Le durcissement de la sécurité BaaS est un ensemble de contrôles en couches — CLP, ACL, discipline des clés — qui ferme les brèches d’un backend par défaut. Les backends naissent permissifs, et c’est voulu : des classes ouvertes et un schéma modifiable depuis le client font décoller les prototypes. Le durcissement est la passe délibérée qui inverse ces valeurs par défaut avant le lancement — et il s’agit d’une checklist courte et connue, pas d’un projet de recherche.
Points clés
| Question | Réponse |
|---|---|
| Ce que c’est | La passe d’avant lancement qui verrouille permissions de classe, ACL, clés et schéma |
| Les couches | Les CLP filtrent la classe → les ACL filtrent la ligne → les champs protégés filtrent la colonne |
| L’unique absolu | La master key contourne tout — elle ne quitte jamais le serveur |
| Le chemin privilégié | Les fonctions Cloud Code sont la porte d’entrée auditée pour les écritures sensibles |
| Ce que les clés ne sont pas | Les app IDs et les clés client sont des identifiants d’app, pas des secrets — organisez-vous en conséquence |
Le durcissement par défaut, en code
La moitié « par objet » de l’histoire — une ACL limitée au propriétaire, posée sous une classe verrouillée :
// JavaScript / Node.js — Back4app JS SDK
// Per-object ACL: the owner reads and writes, a moderator role reads,
// the public gets nothing — layered under the class-level permissions
const note = new Parse.Object('Note');
note.set('body', 'quarterly numbers');
const acl = new Parse.ACL(Parse.User.current()); // owner: read + write
acl.setPublicReadAccess(false);
acl.setPublicWriteAccess(false);
acl.setRoleReadAccess('moderator', true); // role: read only
note.setACL(acl);
await note.save();
// The class gate above it is schema config, set in the dashboard:
// find/get: requiresAuthentication · create: authenticated · addField: nobody // Flutter / Dart — Back4app Flutter SDK
// Per-object ACL: owner read/write, moderator role read, public nothing
final note = ParseObject('Note')..set('body', 'quarterly numbers');
final acl = ParseACL(owner: await ParseUser.currentUser()); // owner: r+w
acl.setPublicReadAccess(allowed: false);
acl.setPublicWriteAccess(allowed: false);
acl.setReadAccess(userId: 'role:moderator', allowed: true); // role: read
note.setACL(acl);
await note.save();
// The class gate above it is schema config, set in the dashboard:
// find/get requiresAuthentication, create authenticated, addField off // iOS / Swift — Back4app Swift SDK
// Per-object ACL: owner read/write, moderator role read, public nothing
var note = Note()
note.body = "quarterly numbers"
var acl = ParseACL()
acl.publicRead = false
acl.publicWrite = false
if let user = User.current {
acl.setReadAccess(user: user, value: true) // owner: read
acl.setWriteAccess(user: user, value: true) // owner: write
}
acl.setReadAccess(roleName: "moderator", value: true) // role: read only
note.ACL = acl
note.save { result in
if case .failure(let error) = result { print(error) }
} // Android / Kotlin — Back4app Android SDK
// Per-object ACL: owner read/write, moderator role read, public nothing
val note = ParseObject("Note").apply { put("body", "quarterly numbers") }
val acl = ParseACL(ParseUser.getCurrentUser()) // owner: read + write
acl.publicReadAccess = false
acl.publicWriteAccess = false
acl.setRoleReadAccess("moderator", true) // role: read only
note.acl = acl
note.saveInBackground { e ->
if (e != null) Log.w("ACL", "save failed: ${e.code}")
}
// The class gate above it is schema config, set in the dashboard:
// find/get requiresAuthentication, create authenticated, addField off CLP vs. ACL vs. master key : quel contrôle fait quoi
| Contrôle | Portée | Où il se configure | Comment il échoue |
|---|---|---|---|
| Permission au niveau de la classe | Classe entière, par opération | Schéma (dashboard) | Laissée sur des valeurs par défaut permissives |
| ACL | Un objet | Sur chaque ligne, à l’enregistrement | Oubliée sur les nouveaux objets |
| Champs protégés | Une colonne | Schéma | Colonnes sensibles lisibles par les autres utilisateurs |
| Master key | Contourne tout ce qui précède | Environnement serveur uniquement | Livrée dans un binaire client |
Les trois premiers s’assemblent en une échelle de permissions que chaque requête doit gravir. Le quatrième est l’issue de secours de cette échelle — indispensable côté serveur, catastrophique partout ailleurs. Quant aux identifiants que les apps livrent bel et bien — l’app ID et les clés d’API client —, ils relèvent d’une tout autre catégorie mentale : extractibles de n’importe quel binaire, ils identifient l’app plutôt qu’ils ne la protègent. Partez du principe qu’ils sont publics, et laissez la couche de données faire respecter les règles.
Où meurt une requête hostile
Le diagramme est aussi le script d’audit : à chaque barrière, demandez-vous ce qui se passe quand un attaquant muni de vos clés publiques arrive en tant qu’utilisateur anonyme, en tant qu’utilisateur connecté, puis en tant qu’utilisateur d’un autre tenant. Chaque « autorisé » qui vous surprend est une anomalie à corriger.
Comment durcir un backend BaaS
| Étape | Action | Ce qu’elle ferme |
|---|---|---|
| 1 | Configurer les CLP de chaque classe : requiresAuthentication au minimum, écritures limitées par rôle | Le dump anonyme classique de la table entière |
| 2 | Désactiver addField sur toutes les classes ainsi que la création de classes par le client | La dérive du schéma et l’injection de classes parasites |
| 3 | ACL par défaut sur les objets appartenant à un utilisateur : lecture/écriture pour le propriétaire, rien pour le public | Les lectures et écritures entre utilisateurs |
| 4 | Protéger les colonnes sensibles (e-mail, tokens, scores) par des règles au niveau des champs | Des utilisateurs qui lisent les attributs privés des autres |
| 5 | Cantonner la master key aux environnements serveur ; la faire tourner selon un calendrier et à la moindre fuite | L’exposition à un contournement total |
| 6 | Faire passer les écritures sensibles par des fonctions Cloud Code, avec des classes verrouillées derrière | Les violations de règles métier et la falsification |
| 7 | Appliquer un rate limiting aux endpoints d’authentification et aux requêtes coûteuses | Le credential stuffing et le scraping massif |
| 8 | Retester depuis un vrai client avec les seules clés publiques ; journaliser et revoir l’usage de la master key | La dérive de configuration qui passe inaperçue |
Les étapes 1 à 4 relèvent de l’application des règles au niveau de la couche de données — déclarative, vérifiée sur chaque chemin. Les étapes 5 à 8 relèvent de la discipline opérationnelle. Les deux moitiés sont nécessaires ; aucune n’est suffisante.
Discipline de la master key et chemin privilégié
La master key existe parce que des acteurs légitimes — migrations, outils d’administration, jobs planifiés — doivent pouvoir ignorer les barrières. La discipline consiste à la traiter comme l’identifiant root qu’elle est : injectée dans les environnements serveur en tant que configuration, jamais commitée, jamais journalisée, jamais embarquée dans quoi que ce soit qu’un utilisateur télécharge, et utilisée opération par opération plutôt que conservée comme valeur par défaut pour toute une session. La rotation en est la moitié sous-estimée — les clés fuient discrètement dans les logs de CI et sur de vieux portables, si bien que les faire tourner selon un calendrier (et instantanément au moindre soupçon) limite le rayon d’impact d’une fuite que vous ne détecterez jamais.
Cloud Code est le pattern qui rend vivables des règles strictes au niveau de la couche de données. Verrouillez complètement une classe — aucune écriture client — et exposez une fonction serverless comme unique porte d’entrée. La fonction valide les entrées, applique les règles métier que le schéma ne sait pas exprimer (« seulement avant l’expédition de la commande »), écrit avec des privilèges élevés et laisse une trace d’audit. La barrière de la classe garantit que ce point de passage obligé ne peut pas être contourné ; le point de passage garde la logique relisible en un seul endroit.
Cas d’usage courants
- Le verrouillage d’avant lancement. La checklist complète ci-dessus, exécutée une fois avant l’arrivée des vrais utilisateurs — l’heure de sécurité la plus rentable qu’une petite équipe puisse passer.
- Isolation des données multi-tenant. Des ACL limitées au propriétaire et des CLP réservées aux utilisateurs authentifiés, pour que le tenant A ne puisse jamais interroger les données du tenant B — appliqué sous le code applicatif.
- Paiements et inventaire. Des classes fermées à toute écriture client, avec des fonctions Cloud Code comme chemin audité pour tout ce qui touche à l’argent ou au stock.
- Réponse à incident. Une clé qui fuit ou une surprise dans les logs déclenche une rotation, un audit des accès et une nouvelle exécution du test de permissions depuis l’extérieur.
- Preuves de conformité. Une matrice de permissions versionnée et des logs d’usage de la master key transforment « nous prenons la sécurité au sérieux » en un document qu’un auditeur peut lire.
Faut-il durcir au niveau de la couche de données ou dans le code applicatif ? Matrice de décision
| Appliquez au niveau de la couche de données (CLP + ACL) quand… | Appliquez dans le code applicatif (Cloud Code) quand… |
|---|---|
| La règle porte sur l’identité et la propriété | La règle exige de la logique métier ou un état portant sur plusieurs objets |
| Elle doit tenir sur chaque chemin, y compris pour les futurs clients | Un point de passage unique et audité est l’exigence |
| Une case à cocher dans le dashboard constitue toute la spécification | Validation, enrichissement ou effets de bord suivent le même chemin |
| Vous voulez une sécurité qui survive aux réécritures de l’app | La règle change plus vite que le schéma ne le devrait |
| Un oubli aurait des conséquences catastrophiques | Un oubli produirait un bug métier, pas une brèche |
En pratique, la réponse est en couches, pas l’un ou l’autre : les règles de la couche de données comme plancher qui tient toujours, les fonctions de la couche applicative pour tout ce qui est conditionnel — et la même requête traverse les deux.
Limites et trade-offs
- Le durcissement est de la configuration, et la configuration dérive. Les nouvelles classes arrivent avec des valeurs par défaut permissives ; sans l’habitude de réauditer, le verrouillage de l’an dernier s’érode sans bruit.
- Les règles déclaratives ne savent pas exprimer de logique. « Propriétaires uniquement » est une case à cocher ; « remboursable seulement dans les 30 jours » est du code — trop s’appuyer sur la couche de données pousse les équipes à tordre leur schéma au lieu d’écrire une fonction.
- La rigueur a un coût en expérience développeur. Des classes verrouillées et un schéma gelé ralentissent le prototypage, d’où une discipline par étapes : ouvert en développement, verrouillé au lancement.
- Rate limits et audits demandent des réglages. Des limites trop serrées brident les pics légitimes ; des logs que personne ne lit ne sont que de la décoration. Les deux ont besoin d’un responsable, pas seulement d’un commit de mise en place.
- Les couches protègent les données, pas tout le reste. Les vulnérabilités des dépendances, les mots de passe utilisateurs divulgués et l’ingénierie sociale sortent de ce modèle — durcir la couche de données est nécessaire, pas suffisant, comme le montre clairement le catalogue OWASP API Security Top 10.
Durcissement de la sécurité BaaS sur Back4app
Back4app est une plateforme open-source de Backend as a Service (BaaS) qui combine une base de données gérée, des API REST et GraphQL générées automatiquement, l’authentification, le stockage de fichiers et des fonctions serverless avec Cloud Code. La checklist de cet article se transpose presque point par point dans son dashboard : les permissions au niveau de la classe et les champs protégés sont des cases à cocher par classe, les ACL sont appliquées côté serveur à chaque requête — via les SDK, REST et GraphQL —, et la master key reste dans la configuration serveur, où Cloud Code — le chemin privilégié — peut l’utiliser opération par opération. Les consignes de sécurité parcourent la même passe étape par étape : durcir un backend se résume à un après-midi de réglages et à un test honnête depuis l’extérieur.
Questions fréquentes
Qu'est-ce que le durcissement de la sécurité BaaS ?
La passe d'avant lancement qui transforme un backend de développement permissif en backend de production verrouillé : permissions au niveau de la classe restreintes par opération, ACL par objet sur les données des utilisateurs, master key cantonnée au code serveur, schéma gelé, rate limits en place et configuration auditée depuis un vrai client. Chaque contrôle couvre une couche différente, et les couches sont vérifiées l'une après l'autre à chaque requête.
L'application ID est-il un secret ?
Non — considérez-le comme public. Les clés client et les app IDs sont livrés dans chaque binaire mobile et chaque page de JavaScript, où n'importe qui peut les extraire. Ils identifient l'app ; ils n'authentifient pas l'appelant. La vraie protection vient de ce que le backend applique après l'identification : permissions au niveau de la classe, ACL et authentification — les couches qui tiennent même quand toutes les clés côté client sont connues.
Pourquoi la master key ne doit-elle jamais être livrée dans une app cliente ?
Parce qu'elle contourne toutes les barrières : permissions au niveau de la classe, ACL, champs protégés et contrôles d'authentification sont sans effet sur les requêtes faites avec la master key. Une clé embarquée dans un binaire client peut être extraite par quiconque l'a téléchargé, et votre base de données entière devient publique en lecture comme en écriture. La master key a sa place dans le code côté serveur uniquement — utilisée opération par opération, jamais stockée là où un client peut l'atteindre.
Quelle est la différence entre les CLP et les ACL ?
La portée. Une permission au niveau de la classe est une règle unique sur le schéma qui répond à « qui peut exécuter cette opération sur cette classe, tout court » ; une ACL est une donnée portée par chaque objet qui répond à « qui peut toucher cette ligne ». Les requêtes franchissent d'abord la barrière de la classe, puis celle de l'objet, et chacune peut refuser. Le durcissement utilise les deux : les grandes lignes sur le schéma, le grain fin sur les lignes.
Comment faire tourner une master key qui a fuité ?
Générez immédiatement une nouvelle clé dans le dashboard de la plateforme, mettez à jour chaque consommateur côté serveur — Cloud Code, jobs, scripts d'administration, CI — puis révoquez l'ancienne clé. Auditez ensuite ce que la clé compromise a pu toucher tant qu'elle était valide. La rotation doit aussi être une routine, pas seulement une réponse à incident : les clés finissent par traîner dans des logs, des sauvegardes et de vieux portables, alors planifiez-la comme le renouvellement d'un certificat.
Quand les écritures doivent-elles passer par Cloud Code plutôt que par le SDK ?
Dès que la règle exige de la logique, pas seulement une identité : invariants portant sur plusieurs objets, tarification, inventaire, tout ce qui touche à l'argent ou aux quotas. Le pattern durci verrouille la classe pour que les clients ne puissent pas y écrire directement, puis expose une fonction Cloud Code comme unique porte d'entrée — validation, enrichissement et journal d'audit suivent le même chemin, et la barrière de la classe garantit que personne ne contourne ce point de passage obligé.
Les rate limits ont-ils leur place dans la sécurité d'un BaaS ?
Oui — les permissions décident qui peut appeler un endpoint ; les rate limits décident à quelle fréquence. Sans eux, des identifiants valides deviennent un outil de scraping ou de force brute : les endpoints de connexion subissent du credential stuffing et les requêtes ouvertes sont aspirées à plein débit. Fixez des limites plus strictes sur les routes d'authentification et les requêtes coûteuses, et couplez-les à des alertes pour qu'un pic de trafic anormal déclenche une alerte d'astreinte, pas une facture surprise.
Comment auditer la configuration de sécurité d'un BaaS ?
Testez depuis l'extérieur, comme le ferait un attaquant : avec uniquement les clés client publiques, tentez de lire et d'écrire chaque classe en tant qu'utilisateur anonyme, utilisateur authentifié et utilisateur d'un autre tenant. Tout ce qui réussit alors que ça ne devrait pas est une anomalie. Recommencez après chaque modification du schéma, conservez la matrice des permissions dans une documentation versionnée et passez les logs en revue à la recherche d'usages de la master key qui ne devraient pas exister.