La sicurezza può essere uno dei pezzi più complessi del puzzle dello sviluppo delle app. Nella maggior parte delle applicazioni, gli sviluppatori devono creare ed eseguire un server che gestisce l'autenticazione (chi è l'utente) e l'autorizzazione (cosa può fare un utente).
Firebase Security Rules rimuove il livello centrale (server) e ti consente di specificare in base al percorso autorizzazioni per i client che si connettono direttamente ai tuoi dati. Utilizza questa guida per Scopri di più su come vengono applicate le regole alle richieste in entrata.
Seleziona un prodotto per scoprire di più sulle relative regole.
Cloud Firestore
Struttura di base
Firebase Security Rules in Cloud Firestore e Cloud Storage utilizzano la seguente struttura e sintassi:
service <<name>> {
// Match the resource path.
match <<path>> {
// Allow the request if the following conditions are true.
allow <<methods>> : if <<condition>>
}
}
È importante comprendere i seguenti concetti chiave durante la creazione delle regole:
- Richiesta: il metodo o i metodi richiamati nell'istruzione
allow
. Si tratta di che consenti l'esecuzione. I metodi standard sono:get
,list
,create
,update
edelete
. Metodi di praticità diread
ewrite
abilita l'accesso ampio in lettura e scrittura sul database o sul percorso di archiviazione specificato. - Percorso:il database o la posizione di archiviazione, rappresentata come del percorso dell'URI.
- Regola: l'istruzione
allow
, che include una condizione che consente una richiesta se restituisce true.
Regole di sicurezza versione 2
A partire da maggio 2019, la versione 2 delle regole di sicurezza Firebase è ora disponibile
disponibili. La versione 2 delle regole modifica il comportamento degli annunci ricorrenti
caratteri jolly {name=**}
. Devi utilizzare la versione 2 se prevedi di
Utilizzare le query del gruppo di raccolte. Devi attivare
versione 2 impostando rules_version = '2';
come prima riga nella sezione
regole:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
Percorsi corrispondenti
Tutte le dichiarazioni di corrispondenza devono puntare a documenti, non a raccolte. Una corrispondenza
l'istruzione può puntare a un documento specifico, ad esempio match /cities/SF
, o utilizzare caratteri jolly
per puntare a qualsiasi documento nel percorso specificato, come in match /cities/{city}
.
Nell'esempio precedente, l'istruzione di corrispondenza utilizza la sintassi con caratteri jolly {city}
.
Ciò significa che la regola si applica a qualsiasi documento della raccolta cities
, ad esempio /cities/SF
o /cities/NYC
. Quando le espressioni allow
nell'istruzione di corrispondenza vengono
valutato, la variabile city
si risolverà nel nome del documento della città,
come SF
o NYC
.
Raccolte secondarie corrispondenti
I dati in Cloud Firestore sono organizzati in raccolte di documenti e ogni documento può estendere la gerarchia tramite sottocollezioni. È importante Comprendere in che modo le regole di sicurezza interagiscono con i dati gerarchici.
Considera la situazione in cui ogni documento nella raccolta cities
contiene una
landmarks
raccolta secondaria. Le regole di sicurezza si applicano solo al percorso corrispondente, pertanto
i controlli dell'accesso definiti nella raccolta cities
non si applicano al
landmarks
raccolta secondaria. Scrivi invece regole esplicite per controllare l'accesso
alle sottoraccolte:
service cloud.firestore {
match /databases/{database}/documents {
match /cities/{city} {
allow read, write: if <condition>;
// Explicitly define rules for the 'landmarks' subcollection
match /landmarks/{landmark} {
allow read, write: if <condition>;
}
}
}
}
Quando si nidificano le istruzioni match
, il percorso dell'istruzione match
interna è sempre
rispetto al percorso dell'istruzione match
esterna. Pertanto, i seguenti set di regole
sono equivalenti:
service cloud.firestore {
match /databases/{database}/documents {
match /cities/{city} {
match /landmarks/{landmark} {
allow read, write: if <condition>;
}
}
}
}
service cloud.firestore {
match /databases/{database}/documents {
match /cities/{city}/landmarks/{landmark} {
allow read, write: if <condition>;
}
}
}
Caratteri jolly ricorsivi
Se vuoi che le regole vengano applicate a una gerarchia arbitrariamente profonda, utilizza
sintassi con caratteri jolly ricorsivi, {name=**}
:
service cloud.firestore {
match /databases/{database}/documents {
// Matches any document in the cities collection as well as any document
// in a subcollection.
match /cities/{document=**} {
allow read, write: if <condition>;
}
}
}
Quando si utilizza la sintassi con caratteri jolly ricorsivi, la variabile con caratteri jolly conterrà il carattere
l'intero segmento di percorso corrispondente, anche se il documento si trova in una zona profondamente nidificata
una sottoraccolta. Ad esempio, le regole elencate sopra corrispondono
un documento situato in /cities/SF/landmarks/coit_tower
e il valore
la variabile document
è SF/landmarks/coit_tower
.
Tieni presente, tuttavia, che il comportamento dei caratteri jolly ricorsivi dipende dalle regole completamente gestita.
Versione 1
Le regole di sicurezza utilizzano la versione 1 per impostazione predefinita. Nella versione 1, i caratteri jolly ricorsivi
corrisponde a uno o più elementi del percorso. Non corrispondono a un percorso vuoto, quindi
match /cities/{city}/{document=**}
corrisponde ai documenti nelle sottoraccolte, ma
non nella raccolta cities
, mentre match /cities/{document=**}
corrisponde
a entrambi i documenti nella raccolta cities
e nelle sottoraccolte.
I caratteri jolly ricorsivi devono essere inseriti alla fine di un'istruzione di corrispondenza.
Versione 2
Nella versione 2 delle regole di sicurezza, i caratteri jolly ricorsivi corrispondono a zero o più percorsi
elementi. match/cities/{city}/{document=**}
corrisponde a documenti in qualsiasi
nonché i documenti della raccolta cities
.
Devi attivare la versione 2 aggiungendo rules_version = '2';
nella parte superiore di
le tue regole di sicurezza:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Matches any document in the cities collection as well as any document
// in a subcollection.
match /cities/{city}/{document=**} {
allow read, write: if <condition>;
}
}
}
È possibile avere al massimo un carattere jolly ricorsivo per ciascuna istruzione di corrispondenza, ma nella versione 2, puoi inserire questo carattere jolly in qualsiasi punto dell'istruzione di corrispondenza. Ad esempio:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Matches any document in the songs collection group
match /{path=**}/songs/{song} {
allow read, write: if <condition>;
}
}
}
Se utilizzi le query dei gruppi di raccolte, devi utilizzare versione 2, consulta la sezione Protezione delle gruppo di raccolte di raccolte.
Estratti conto di corrispondenza sovrapposti
È possibile che un documento corrisponda a più dichiarazioni match
. Nella
nel caso in cui più espressioni allow
corrispondano a una richiesta, l'accesso è consentito
se una delle condizioni è true
:
service cloud.firestore {
match /databases/{database}/documents {
// Matches any document in the 'cities' collection.
match /cities/{city} {
allow read, write: if false;
}
// Matches any document in the 'cities' collection or subcollections.
match /cities/{document=**} {
allow read, write: if true;
}
}
}
Nell'esempio precedente, tutte le letture e le scritture nella raccolta cities
saranno
consentito perché la seconda regola è sempre true
, anche se la prima
è sempre false
.
Limiti delle regole di sicurezza
Quando lavori con le regole di sicurezza, tieni presente i seguenti limiti:
Limite | Dettagli |
---|---|
Numero massimo di chiamate exists() , get() e getAfter() per richiesta |
Il superamento di uno dei limiti comporta un errore di autorizzazione negata. Alcune chiamate di accesso ai documenti possono essere memorizzate nella cache e le chiamate nella cache non vengono considerate ai fini dei limiti. |
Profondità massima delle istruzioni match nidificate |
10 |
Lunghezza massima del percorso, in segmenti di percorso, consentita all'interno di un set di istruzioni match nidificate |
100 |
Numero massimo di variabili di acquisizione percorso consentite all'interno di un set di istruzioni match nidificate |
20 |
Profondità massima delle chiamate funzione | 20 |
Numero massimo di argomenti di funzione | 7 |
Numero massimo di associazioni di variabili let per funzione |
10 |
Numero massimo di chiamate di funzione ricorsive o cicliche | 0 (non consentite) |
Numero massimo di espressioni valutate per richiesta | 1000 |
Dimensione massima di un set di regole | I set di regole devono rispettare due limiti di dimensione:
|
Cloud Storage
Struttura di base
Firebase Security Rules in Cloud Firestore e Cloud Storage utilizzano la seguente struttura e sintassi:
service <<name>> {
// Match the resource path.
match <<path>> {
// Allow the request if the following conditions are true.
allow <<methods>> : if <<condition>>
}
}
È importante comprendere i seguenti concetti chiave durante la creazione delle regole:
- Richiesta: il metodo o i metodi richiamati nell'istruzione
allow
. Si tratta di che consenti l'esecuzione. I metodi standard sono:get
,list
,create
,update
edelete
. Metodi di praticità diread
ewrite
abilita l'accesso ampio in lettura e scrittura sul database o sul percorso di archiviazione specificato. - Percorso:il database o la posizione di archiviazione, rappresentata come del percorso dell'URI.
- Regola: l'istruzione
allow
, che include una condizione che consente una richiesta se restituisce true.
Percorsi corrispondenti
Cloud Storage Security Rules match
i percorsi file utilizzati per accedere ai file in
Cloud Storage. Le regole possono match
percorsi esatti o percorsi con caratteri jolly e
possono anche essere nidificate. Se nessuna regola di corrispondenza consente un metodo di richiesta, oppure
la condizione restituisce false
e la richiesta viene rifiutata.
Corrispondenze esatte
// Exact match for "images/profilePhoto.png" match /images/profilePhoto.png { allow write: if <condition>; } // Exact match for "images/croppedProfilePhoto.png" match /images/croppedProfilePhoto.png { allow write: if <other_condition>; }
Corrispondenze nidificate
// Partial match for files that start with "images" match /images { // Exact match for "images/profilePhoto.png" match /profilePhoto.png { allow write: if <condition>; } // Exact match for "images/croppedProfilePhoto.png" match /croppedProfilePhoto.png { allow write: if <other_condition>; } }
Corrispondenze con caratteri jolly
Le regole possono essere utilizzate anche per match
un pattern utilizzando caratteri jolly. Un carattere jolly è un
variabile con nome che rappresenta una singola stringa come
profilePhoto.png
o più segmenti del percorso, come
images/profilePhoto.png
.
Un carattere jolly viene creato aggiungendo parentesi graffe intorno al nome, come
{string}
. È possibile dichiarare un carattere jolly per più segmenti aggiungendo =**
al
nome con caratteri jolly, ad esempio {path=**}
:
// Partial match for files that start with "images" match /images { // Exact match for "images/*" // e.g. images/profilePhoto.png is matched match /{imageId} { // This rule only matches a single path segment (*) // imageId is a string that contains the specific segment matched allow read: if <condition>; } // Exact match for "images/**" // e.g. images/users/user:12345/profilePhoto.png is matched // images/profilePhoto.png is also matched! match /{allImages=**} { // This rule matches one or more path segments (**) // allImages is a path that contains all segments matched allow read: if <other_condition>; } }
Se più regole corrispondono a un file, il risultato è il OR
del risultato di tutte
e valutazioni di regole. In altre parole, se una regola corrispondente al file restituisce true
, il
il risultato è true
.
Nelle regole precedenti, il file "images/profilePhoto.png" può essere letto se
condition
o other_condition
restituiscono true, mentre il file
"images/users/user:12345/profilePhoto.png" è soggetto solo al risultato
other_condition
.
È possibile fare riferimento a una variabile jolly all'interno dell'autorizzazione del nome o del percorso del file fornito in match
:
// Another way to restrict the name of a file match /images/{imageId} { allow read: if imageId == "profilePhoto.png"; }
Cloud Storage Security Rules non vengono applicati a cascata e le regole vengono valutate solo quando il percorso della richiesta corrisponde a un percorso con le regole specificate.
Richiedi valutazione
Caricamenti, download, modifiche ed eliminazioni dei metadati vengono valutati utilizzando
Importo di request
inviato a Cloud Storage. La variabile request
contiene il parametro
il percorso del file in cui viene eseguita la richiesta, l'ora in cui
ricevuto e il nuovo valore resource
se la richiesta è una scrittura. Sono inclusi anche le intestazioni HTTP
e lo stato di autenticazione.
L'oggetto request
contiene anche l'ID univoco dell'utente e
Payload Firebase Authentication nell'oggetto request.auth
, che verrà
spiegata più dettagliatamente nella sezione Autenticazione
sezione dei documenti.
Di seguito è disponibile un elenco completo delle proprietà nell'oggetto request
:
Proprietà | Tipo | Descrizione |
---|---|---|
auth |
mappa<stringa, stringa> | Quando un utente accede, fornisce uid , l'ID univoco dell'utente e
token , una mappa di Firebase Authentication dichiarazioni JWT. In caso contrario, sarà
null . |
params |
mappa<stringa, stringa> | Mappa contenente i parametri di query della richiesta. |
path |
percorso | Un path che rappresenta il percorso della richiesta
è stato eseguito. |
resource |
mappa<stringa, stringa> | Il nuovo valore della risorsa, presente solo nelle richieste write .
|
time |
timestamp | Un timestamp che rappresenta l'ora del server in cui viene valutata la richiesta. |
Valutazione delle risorse
Durante la valutazione delle regole, è consigliabile esaminare anche i metadati del file in fase di caricamento, download, modifica o eliminazione. Questo consente di creare regole complesse ed efficaci, ad esempio consentire solo i file con tipi di contenuti da caricare o solo i file di dimensioni superiori a una determinata dimensione eliminati.
Firebase Security Rules per Cloud Storage fornisce i metadati dei file in resource
contenente le coppie chiave/valore dei metadati mostrati in un
Oggetto Cloud Storage. Queste proprietà possono essere ispezionate su read
o
Richieste di write
per garantire l'integrità dei dati.
Per le richieste di write
(come caricamenti, aggiornamenti ed eliminazioni di metadati), in
aggiunta all'oggetto resource
, che contiene i metadati del file
attualmente esistente nel percorso di richiesta, puoi anche utilizzare
request.resource
, che contiene un sottoinsieme dei metadati del file da utilizzare
se la scrittura è consentita. Puoi utilizzare questi due valori per garantire l'integrità dei dati o applicare vincoli di applicazione come il tipo o le dimensioni del file.
Di seguito è disponibile un elenco completo delle proprietà nell'oggetto resource
:
Proprietà | Tipo | Descrizione |
---|---|---|
name |
stringa | Il nome completo dell'oggetto |
bucket |
stringa | Il nome del bucket in cui si trova questo oggetto. |
generation |
int | La Google Cloud Storage di questo oggetto. |
metageneration |
int | La Google Cloud Storage della metagenerazione dell'oggetto. |
size |
int | Le dimensioni dell'oggetto in byte. |
timeCreated |
timestamp | Un timestamp che rappresenta l'ora in cui è stato creato un oggetto. |
updated |
timestamp | Un timestamp che rappresenta l'ora dell'ultimo aggiornamento di un oggetto. |
md5Hash |
stringa | Un hash MD5 dell'oggetto. |
crc32c |
stringa | Un hash crc32c dell'oggetto. |
etag |
stringa | L'etag associato a questo oggetto. |
contentDisposition |
stringa | La disposizione dei contenuti associata a questo oggetto. |
contentEncoding |
stringa | La codifica dei contenuti associata a questo oggetto. |
contentLanguage |
stringa | La lingua dei contenuti associata a questo oggetto. |
contentType |
stringa | Il tipo di contenuti associato a questo oggetto. |
metadata |
mappa<stringa, stringa> | Coppie chiave/valore di metadati personalizzati aggiuntivi specificati dallo sviluppatore. |
request.resource
contiene tutti questi valori tranne generation
,
metageneration
, etag
, timeCreated
e updated
.
Limiti delle regole di sicurezza
Quando lavori con le regole di sicurezza, tieni presente i seguenti limiti:
Limite | Dettagli |
---|---|
Numero massimo di firestore.exists() e
firestore.get() chiamate per richiesta |
2 per le richieste di documenti singoli e di query. Il superamento di questo limite comporta un errore di autorizzazione negata. Le chiamate di accesso agli stessi documenti possono essere memorizzate nella cache e le chiamate memorizzate nella cache non vengono conteggiate ai fini dei limiti. |
Esempio completo
Riassumendo, puoi creare un esempio completo di regole per un'immagine soluzione di archiviazione:
service firebase.storage { match /b/{bucket}/o { match /images { // Cascade read to any image type at any path match /{allImages=**} { allow read; } // Allow write files to the path "images/*", subject to the constraints: // 1) File is less than 5MB // 2) Content type is an image // 3) Uploaded content type matches existing content type // 4) File name (stored in imageId wildcard variable) is less than 32 characters match /{imageId} { allow write: if request.resource.size < 5 * 1024 * 1024 && request.resource.contentType.matches('image/.*') && request.resource.contentType == resource.contentType && imageId.size() < 32 } } } }
Realtime Database
Struttura di base
In Realtime Database, Firebase Security Rules è costituito da espressioni simili a JavaScript contenute in un oggetto documento JSON.
Utilizzano la seguente sintassi:
{
"rules": {
"<<path>>": {
// Allow the request if the condition for each method is true.
".read": <<condition>>,
".write": <<condition>>,
".validate": <<condition>>
}
}
}
La regola include tre elementi di base:
- Percorso:la posizione del database. Questo rispecchia la struttura JSON del database.
- Richiesta: sono i metodi utilizzati dalla regola per concedere l'accesso.
read
ewrite
regole concedono accesso ampio in lettura e scrittura, mentrevalidate
regole agire come verifica secondaria per concedere l'accesso in base alle richieste in arrivo o e i dati di Google Cloud. - Condizione:la condizione che consente una richiesta se restituisce true.
Come si applicano le regole ai percorsi
In Realtime Database, i Rules vengono applicati a livello atomico, il che significa che le regole i nodi principali di livello superiore eseguono l'override delle regole nei nodi figlio più granulari a un nodo più profondo non possono concedere l'accesso a un percorso padre. Tu non puoi perfezionare o revocare l'accesso in un percorso più approfondito nella struttura del database se lo hai già concesso per uno dei percorsi principali.
Tieni presente le seguenti regole:
{ "rules": { "foo": { // allows read to /foo/* ".read": "data.child('baz').val() === true", "bar": { // ignored, since read was allowed already ".read": false } } } }
Questa struttura di sicurezza consente la lettura di /bar/
da quando
/foo/
contiene un elemento secondario baz
con valore true
.
La regola ".read": false
in /foo/bar/
non ha
perché l'accesso non può essere revocato da un percorso figlio.
Potrebbe non sembrare immediatamente intuitivo, ma si tratta di una parte importante del e consente l'implementazione di privilegi di accesso molto complessi con il minimo sforzo. Questo è particolarmente utile per la sicurezza basata sugli utenti.
Tuttavia, le regole .validate
non vengono applicate a cascata. Affinché una scrittura sia consentita, tutte le regole di convalida devono essere soddisfatte a tutti i livelli della gerarchia.
Inoltre, poiché le regole non vengono applicate nuovamente a un percorso principale, le operazioni di lettura o scrittura non vanno a buon fine se non è presente una regola nella posizione richiesta o in una posizione principale che concede l'accesso. Anche se ogni percorso figlio interessato è accessibile, la lettura nella posizione principale non riuscirà del tutto. Considera questa struttura:
{ "rules": { "records": { "rec1": { ".read": true }, "rec2": { ".read": false } } } }
Se non si comprende che le regole vengono valutate a livello atomico,
ad esempio, il recupero del percorso /records/
restituirà rec1
ma non rec2
. Il risultato effettivo, tuttavia, è un errore:
JavaScript
var db = firebase.database(); db.ref("records").once("value", function(snap) { // success method is not called }, function(err) { // error callback triggered with PERMISSION_DENIED });
Objective-C
FIRDatabaseReference *ref = [[FIRDatabase database] reference]; [[_ref child:@"records"] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) { // success block is not called } withCancelBlock:^(NSError * _Nonnull error) { // cancel block triggered with PERMISSION_DENIED }];
Swift
var ref = FIRDatabase.database().reference() ref.child("records").observeSingleEventOfType(.Value, withBlock: { snapshot in // success block is not called }, withCancelBlock: { error in // cancel block triggered with PERMISSION_DENIED })
Java
FirebaseDatabase database = FirebaseDatabase.getInstance(); DatabaseReference ref = database.getReference("records"); ref.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot snapshot) { // success method is not called } @Override public void onCancelled(FirebaseError firebaseError) { // error callback triggered with PERMISSION_DENIED }); });
REST
curl https://docs-examples.firebaseio.com/rest/records/ # response returns a PERMISSION_DENIED error
Poiché l'operazione di lettura in /records/
è atomica e non esiste alcuna regola di lettura che concede l'accesso a tutti i dati in /records/
, verrà generato un errore PERMISSION_DENIED
. Se valutiamo questa regola nel simulatore di sicurezza nella console Firebase, l'operazione di lettura è stata rifiutata:
Attempt to read /records with auth=Success(null) / /records No .read rule allowed the operation. Read was denied.
L'operazione è stata rifiutata perché nessuna regola di lettura consentiva l'accesso al percorso /records/
, ma tieni presente che la regola per /records/
non è mai stata valutata perché non era nel percorso che abbiamo richiesto. Per recuperare rec1
, dobbiamo accedervi direttamente:
JavaScript
var db = firebase.database(); db.ref("records/rec1").once("value", function(snap) { // SUCCESS! }, function(err) { // error callback is not called });
Objective-C
FIRDatabaseReference *ref = [[FIRDatabase database] reference]; [[ref child:@"records/rec1"] observeSingleEventOfType:FEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) { // SUCCESS! }];
Swift
var ref = FIRDatabase.database().reference() ref.child("records/rec1").observeSingleEventOfType(.Value, withBlock: { snapshot in // SUCCESS! })
Java
FirebaseDatabase database = FirebaseDatabase.getInstance(); DatabaseReference ref = database.getReference("records/rec1"); ref.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot snapshot) { // SUCCESS! } @Override public void onCancelled(FirebaseError firebaseError) { // error callback is not called } });
REST
curl https://docs-examples.firebaseio.com/rest/records/rec1 # SUCCESS!
Variabile posizione
Realtime Database Rules support a $location
per far corrispondere i segmenti del percorso. Utilizza il prefisso $
davanti al percorso
per abbinare la regola ai nodi figlio lungo il percorso.
{
"rules": {
"rooms": {
// This rule applies to any child of /rooms/, the key for each room id
// is stored inside $room_id variable for reference
"$room_id": {
"topic": {
// The room's topic can be changed if the room id has "public" in it
".write": "$room_id.contains('public')"
}
}
}
}
}
Puoi anche utilizzare $variable
in parallelo al percorso costante
i nomi degli utenti.
{
"rules": {
"widget": {
// a widget can have a title or color attribute
"title": { ".validate": true },
"color": { ".validate": true },
// but no other child paths are allowed
// in this case, $other means any key excluding "title" and "color"
"$other": { ".validate": false }
}
}
}