L’hardening della sicurezza BaaS è un insieme di controlli a strati – CLP, ACL e disciplina delle chiavi – che chiude le aperture con cui un backend nasce. I backend nascono permissivi di proposito: classi aperte e schemi scrivibili dal client fanno volare i prototipi. L’hardening è il passaggio deliberato che ribalta quei valori predefiniti prima del lancio – ed è una checklist breve e nota, non un progetto di ricerca.
Punti chiave
| Domanda | Risposta |
|---|---|
| Che cos’è | Il passaggio pre-lancio che blinda permessi di classe, ACL, chiavi e schema |
| Gli strati | Le CLP filtrano la classe → le ACL filtrano la riga → i campi protetti filtrano la colonna |
| L’unico assoluto | La master key aggira tutto – non lascia mai il server |
| Il percorso privilegiato | Le funzioni Cloud Code sono la porta d’ingresso verificata per le scritture sensibili |
| Ciò che le chiavi non sono | App ID e chiavi client sono identificatori, non segreti – va pianificato di conseguenza |
Il valore predefinito irrobustito, in codice
La metà “per oggetto” della storia – una ACL limitata al proprietario, posata sotto una classe blindata:
// 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: quale controllo fa cosa
| Controllo | Ambito | Dove si imposta | Come fallisce |
|---|---|---|---|
| Permesso di classe | Intera classe, per operazione | Schema (dashboard) | Lasciato ai valori predefiniti permissivi |
| ACL | Un oggetto | Su ogni riga, al salvataggio | Dimenticata sui nuovi oggetti |
| Campi protetti | Una colonna | Schema | Colonne sensibili leggibili dagli altri utenti |
| Master key | Aggira tutto quanto sopra | Solo ambiente server | Spedita in un binario client |
I primi tre si compongono in una scala di permessi che ogni richiesta deve salire. Il quarto è la scala antincendio di quella scala – indispensabile lato server, catastrofico ovunque altrove. E gli identificatori che le app spediscono davvero – l’app ID e le chiavi API client – appartengono a una categoria mentale del tutto diversa: sono estraibili da qualunque binario, quindi identificano l’app anziché proteggerla. Vanno presunti pubblici, lasciando che sia il livello dati a far rispettare le regole.
Dove muore una richiesta ostile
Il diagramma è anche lo script di audit: a ogni barriera, chiedersi che cosa succede quando chi attacca, munito delle chiavi pubbliche dell’app, arriva come utente anonimo, come utente autenticato e come utente di un altro tenant. Ogni “consentito” che sorprende è l’anomalia da correggere.
Come fare hardening di un backend BaaS
| Passo | Azione | Che cosa chiude |
|---|---|---|
| 1 | Impostare le CLP di ogni classe: requiresAuthentication come minimo, scritture limitate per ruolo | Il classico dump anonimo dell’intera tabella |
| 2 | Disattivare addField su tutte le classi e la creazione di classi dal client | Deriva dello schema e iniezione di classi spazzatura |
| 3 | ACL predefinita sugli oggetti di proprietà dell’utente: lettura/scrittura per il proprietario, niente per il pubblico | Letture e scritture tra utenti diversi |
| 4 | Proteggere le colonne sensibili (email, token, punteggi) con regole a livello di campo | Utenti che leggono gli attributi privati degli altri |
| 5 | Confinare la master key negli ambienti server; ruotarla a calendario e a ogni fuga | L’esposizione a un aggiramento totale |
| 6 | Instradare le scritture sensibili attraverso funzioni Cloud Code, con classi blindate dietro | Violazioni delle regole di business e manomissioni |
| 7 | Applicare rate limit agli endpoint di autenticazione e alle query costose | Credential stuffing e scraping massivo |
| 8 | Ritestare da un client reale con le sole chiavi pubbliche; registrare e rivedere l’uso della master key | La deriva di configurazione che passa inosservata |
I passi 1–4 sono applicazione delle regole a livello dati – dichiarativa, controllata su ogni percorso. I passi 5–8 sono disciplina operativa. Entrambe le metà sono necessarie; nessuna è sufficiente.
Disciplina della master key e percorso privilegiato
La master key esiste perché qualcuno di legittimo – migrazioni, strumenti di amministrazione, job pianificati – deve poter ignorare le barriere. Disciplina significa trattarla come la credenziale root che è: iniettata negli ambienti server come configurazione, mai committata, mai registrata nei log, mai incorporata in qualcosa che un utente scarichi, e usata per singola operazione anziché tenuta come valore predefinito per l’intera sessione. La rotazione è la metà sottovalutata – le chiavi trapelano in silenzio nei log di CI e sui vecchi portatili, quindi ruotarle a calendario (e all’istante a ogni sospetto) mette un tetto al raggio d’impatto di una fuga mai rilevata.
Cloud Code è il pattern che rende vivibili regole rigide a livello dati. Si blinda completamente una classe – nessuna scrittura dal client – e si espone una funzione serverless come unica porta d’ingresso. La funzione valida l’input, applica le regole di business che lo schema non sa esprimere (“solo prima che l’ordine venga spedito”), scrive con privilegi elevati e lascia una traccia di audit. La barriera della classe garantisce che il punto di passaggio obbligato non possa essere aggirato; il punto di passaggio tiene la logica rivedibile in un solo posto.
Casi d’uso tipici
- L’hardening pre-lancio. La checklist completa qui sopra, eseguita una volta prima dell’arrivo degli utenti reali – l’ora dedicata alla sicurezza con il miglior ritorno che un piccolo team possa spendere.
- Isolamento dei dati multi-tenant. ACL limitate al proprietario più CLP riservate agli utenti autenticati, così che il tenant A non possa mai interrogare il tenant B – applicato sotto il codice applicativo.
- Pagamenti e inventario. Classi chiuse a qualunque scrittura dal client, con funzioni Cloud Code come percorso verificato per tutto ciò che tocca denaro o scorte.
- Risposta agli incidenti. Una chiave trapelata o una sorpresa nei log innesca una rotazione, un audit degli accessi e una nuova esecuzione del test dei permessi dall’esterno.
- Evidenze di conformità. Una matrice dei permessi versionata e i log d’uso della master key trasformano “prendiamo la sicurezza sul serio” in un artefatto che un auditor può leggere.
Conviene fare hardening a livello dati o nel codice applicativo? Matrice decisionale
| Applicare a livello dati (CLP + ACL) quando… | Applicare nel codice applicativo (Cloud Code) quando… |
|---|---|
| La regola riguarda identità e proprietà | La regola richiede logica di business o stato su più oggetti |
| Deve reggere su ogni percorso, compresi i client futuri | Il requisito è un unico punto di passaggio verificato |
| Una casella nella dashboard è l’intera specifica | Validazione, arricchimento o effetti collaterali viaggiano insieme |
| Serve una sicurezza che sopravviva alle riscritture dell’app | La regola cambia più in fretta di quanto dovrebbe cambiare lo schema |
| Dimenticarla avrebbe conseguenze catastrofiche | Dimenticarla produce un bug di business, non una violazione |
In pratica la risposta è a strati, non l’una o l’altra: regole a livello dati come base che regge sempre, funzioni a livello applicativo per tutto ciò che è condizionale – la stessa richiesta attraversa entrambi.
Limiti e trade-off
- L’hardening è configurazione, e la configurazione va alla deriva. Le classi nuove arrivano con valori predefiniti permissivi; senza l’abitudine di rifare l’audit, l’hardening dell’anno scorso si erode in silenzio.
- Le regole dichiarative non sanno esprimere logica. “Solo i proprietari” è una casella; “rimborsabile solo entro 30 giorni” è codice – appoggiarsi troppo al livello dati spinge i team a contorcere gli schemi invece di scrivere una funzione.
- La rigidità ha un costo in esperienza di sviluppo. Classi blindate e schemi congelati rallentano la prototipazione, ed è per questo che la disciplina è a fasi: aperto in sviluppo, blindato al lancio.
- Rate limit e audit richiedono messa a punto. Limiti troppo stretti soffocano i picchi legittimi; log che nessuno legge sono decorazione. Entrambi hanno bisogno di un responsabile, non solo di un commit di configurazione.
- Gli strati proteggono i dati, non tutto. Vulnerabilità delle dipendenze, password degli utenti trapelate e ingegneria sociale vivono fuori da questo modello – l’hardening del livello dati è necessario, non sufficiente, come il catalogo OWASP API Security Top 10 rende chiaro.
L’hardening della sicurezza BaaS su Back4app
Back4app è una piattaforma open-source di Backend as a Service (BaaS) che combina database gestito, API REST e GraphQL generate automaticamente, autenticazione, archiviazione di file e funzioni serverless con Cloud Code. La checklist di questo articolo si mappa sulla sua dashboard quasi uno a uno: permessi di classe e campi protetti sono caselle per classe, le ACL vengono applicate lato server a ogni richiesta attraverso SDK, REST e GraphQL, e la master key resta nella configurazione server, dove Cloud Code – il percorso privilegiato – può usarla per singola operazione. Le linee guida di sicurezza percorrono lo stesso passaggio passo dopo passo, così fare hardening di un backend è un pomeriggio di caselle e un test onesto dall’esterno.
Domande frequenti
Che cos'è l'hardening della sicurezza BaaS?
Il passaggio pre-lancio che trasforma un backend di sviluppo permissivo in un backend di produzione blindato: permessi di classe ristretti per operazione, ACL per oggetto sui dati degli utenti, master key confinata nel codice server, schema congelato, rate limit impostati e configurazione verificata da un client reale. Ogni controllo copre uno strato diverso, e gli strati vengono controllati in sequenza a ogni richiesta.
L'Application ID è un segreto?
No – va considerato pubblico. Le chiavi client e gli app ID vengono spediti dentro ogni binario mobile e ogni pagina di JavaScript, dove chiunque può estrarli. Identificano l'app; non autenticano il chiamante. La protezione vera viene da ciò che il backend applica dopo l'identificazione: permessi di classe, ACL e autenticazione – gli strati che reggono anche quando ogni chiave lato client è nota.
Perché la master key non deve mai essere spedita in un'app client?
Perché aggira ogni barriera: permessi di classe, ACL, campi protetti e controlli di autenticazione sono tutti nulli per le richieste con master key. Una chiave incorporata in un binario client può essere estratta da chiunque lo scarichi, rendendo l'intero database leggibile e scrivibile da chiunque. La master key appartiene solo al codice lato server – usata per singola operazione, mai conservata dove un client possa raggiungerla.
Qual è la differenza tra CLP e ACL?
L'ambito. Un permesso di classe è una regola unica sullo schema che risponde a "chi può eseguire questa operazione su questa classe, in assoluto"; una ACL è un dato su ogni oggetto che risponde a "chi può toccare questa riga". Le richieste superano prima la barriera della classe, poi quella dell'oggetto, ed entrambe possono negare. L'hardening le usa entrambe: tratti larghi sullo schema, grana fine sulle righe.
Come si ruota una master key trapelata?
Generare subito una chiave nuova nella dashboard della piattaforma, aggiornare ogni consumatore lato server – Cloud Code, job, script di amministrazione, CI – e revocare la chiave vecchia. Poi verificare che cosa la chiave trapelata possa aver toccato finché era valida. La rotazione dovrebbe essere anche una routine, non solo una risposta agli incidenti: le chiavi invecchiano dentro log, backup e vecchi portatili, quindi va pianificata come il rinnovo di un certificato.
Quando le scritture dovrebbero passare da Cloud Code invece che dall'SDK?
Ogni volta che la regola richiede logica, non solo identità: invarianti su più oggetti, prezzi, inventario, qualunque cosa riguardi denaro o quote. Il pattern irrobustito blinda la classe perché i client non possano scriverla direttamente, poi espone una funzione Cloud Code come unica porta d'ingresso – validazione, arricchimento e log di audit viaggiano insieme, e la barriera della classe garantisce che nessuno aggiri il punto di passaggio obbligato.
I rate limit fanno parte della sicurezza di un BaaS?
Sì – i permessi decidono chi può chiamare un endpoint; i rate limit decidono con quale frequenza. Senza di essi, credenziali valide diventano uno strumento di scraping o di forza bruta: gli endpoint di accesso subiscono credential stuffing e le query aperte vengono raccolte alla massima velocità della connessione. Conviene impostare limiti più severi sulle rotte di autenticazione e sulle query costose, e abbinarli ad avvisi, così che un picco di traffico anomalo sia una chiamata di reperibilità, non una fattura a sorpresa.
Come si verifica una configurazione di sicurezza BaaS?
Testando dall'esterno, come farebbe chi attacca: con le sole chiavi client pubbliche, provare a leggere e scrivere ogni classe come utente anonimo, come utente autenticato e come utente di un altro tenant. Tutto ciò che riesce e non dovrebbe è un'anomalia. Ripetere dopo ogni modifica dello schema, tenere la matrice dei permessi in documentazione versionata e rivedere i log in cerca di usi della master key che non dovrebbero esistere.