Le regole di sicurezza Firebase per Cloud Storage vengono utilizzate per determinare chi ha accesso in lettura e scrittura ai file archiviati in Cloud Storage, nonché come sono strutturati i file e quali metadati contengono. Le regole di sicurezza di Cloud Storage sono composte da regole che prendono in considerazione la request
e resource
per consentire o negare un'azione desiderata, come il caricamento di un file o il recupero dei metadati del file. Questi documenti di riferimento riguardano i tipi di regole, le proprietà di una request
e di una resource
, i tipi di dati utilizzati dalle regole di sicurezza di Cloud Storage e il modo in cui si verificano gli errori.
Regola
Una rule
è un'espressione che viene valutata per determinare se una request
può eseguire l'azione desiderata.
Tipi
Permettere
le regole allow
sono costituite da un metodo, ad esempio read
o write
, nonché da una condizione facoltativa. Quando viene eseguita una regola, la condizione viene valutata e, se la condizione restituisce true
, viene consentito il metodo desiderato; in caso contrario, il metodo viene negato. Una regola allow
senza condizione consente sempre il metodo desiderato.
// Always allow method allow <method>; // Allow method if condition is true allow <method>: if <condition>;
Attualmente, allow
è l'unico tipo di regola supportato.
Metodi di richiesta
Leggere
Il metodo read
copre tutte le richieste in cui vengono letti i dati o i metadati dei file, inclusi i download di file e le letture dei metadati dei file.
// Always allow reads allow read; // Allow reads if condition evaluates to true allow read: if <condition>;
Scrivere
Il metodo write
copre tutte le richieste in cui vengono scritti dati o metadati di file, inclusi caricamenti di file, eliminazioni di file e aggiornamenti di metadati di file.
// Always allow writes allow write; // Allow writes if condition evaluates to true allow write: if <condition>;
Incontro
Le regole vengono eseguite quando una request
dell'utente (ad esempio il caricamento o il download di un file) corrisponde a un percorso di file coperto da una regola. Una match
è costituita da un percorso e da un corpo, che deve contenere almeno una regola allow
. Se non viene trovata alcuna corrispondenza, la richiesta viene rifiutata.
È possibile match
un percorso con nome completo oppure inserire caratteri jolly per abbinare tutti i percorsi che rientrano in un determinato modello.
Segmenti di percorso
single_segment
Puoi utilizzare segmenti di percorso singolo per creare una regola che corrisponda a un file archiviato in Cloud Storage.
// Allow read at "path" if condition evaluates to true match /path { allow read: if <condition>; }
Sono consentiti anche più segmenti di percorso e percorsi nidificati:
// Allow read at "path/to/object" if condition evaluates to true match /path { match /to { match /object { allow read: if <condition>; } } }
{single_segment_wildcard}
Se desideri applicare una regola a più file nello stesso percorso, puoi utilizzare un segmento di percorso con caratteri jolly per abbinare tutti i file in un determinato percorso. Una variabile jolly viene dichiarata in un percorso racchiudendo una variabile tra parentesi graffe: {variable}
. Questa variabile è accessibile all'interno dell'istruzione match come una string
.
// Allow read at any path "/*", if condition evaluates to true match /{single_path} { // Matches "path", "to", or "object" but not "path/to/object" allow read: if <condition>; }
Anche più segmenti di percorso e percorsi nidificati possono contenere caratteri jolly:
// Allow read at any path "/path/*/newPath/*", if condition evaluates to true match /path/{first_wildcard} { match /newPath/{second_wildcard} { // Matches "path/to/newPath/newObject" or "path/from/newPath/oldObject" allow read: if <condition>; } }
{multi_segment_wildcard=**}
Se desideri far corrispondere un numero qualsiasi di segmenti di percorso in corrispondenza o al di sotto di un percorso, puoi utilizzare un carattere jolly multisegmento, che corrisponderà a tutte le richieste verso e sotto la posizione. Ciò può essere utile per fornire a un utente il proprio spazio di archiviazione in formato libero o per creare regole che corrispondano a molti segmenti di percorso diversi (come la creazione di un set di file leggibili pubblicamente o la richiesta di autenticazione per tutte le scritture).
Un percorso con caratteri jolly a più segmenti viene dichiarato in modo simile a un carattere jolly a segmento singolo, con l'aggiunta di =**
alla fine della variabile: {variable=**}
. Una variabile jolly multisegmento è disponibile all'interno dell'istruzione match come oggetto path
.
// Allow read at any path "/**", if condition evaluates to true match /{multi_path=**} { // Matches anything at or below this, from "path", "path/to", "path/to/object", ... allow read: if <condition>; }
Richiesta
La variabile request
viene fornita all'interno di una condizione per rappresentare la richiesta effettuata su quel percorso. La variabile request
ha una serie di proprietà che possono essere utilizzate per decidere se consentire la richiesta in arrivo.
Proprietà
auth
Quando un utente autenticato esegue una richiesta su Cloud Storage, la variabile auth
viene popolata con l' uid
dell'utente ( request.auth.uid
) e con le attestazioni del JWT di autenticazione Firebase ( request.auth.token
).
request.auth.token
contiene alcune o tutte le seguenti chiavi:
Campo | Descrizione |
---|---|
email | L'indirizzo email associato all'account, se presente. |
email_verified | true se l'utente ha verificato di avere accesso all'indirizzo email . Alcuni provider verificano automaticamente gli indirizzi email di loro proprietà. |
phone_number | Il numero di telefono associato all'account, se presente. |
name | Il nome visualizzato dell'utente, se impostato. |
sub | L'UID Firebase dell'utente. Questo è unico all'interno di un progetto. |
firebase.identities | Dizionario di tutte le identità associate all'account di questo utente. I tasti del dizionario possono essere uno dei seguenti: email , phone , google.com , facebook.com , github.com , twitter.com . I valori del dizionario sono matrici di identificatori univoci per ciascun provider di identità associato all'account. Ad esempio, auth.token.firebase.identities["google.com"][0] contiene il primo ID utente Google associato all'account. |
firebase.sign_in_provider | Il provider di accesso utilizzato per ottenere questo token. Può essere una delle seguenti stringhe: custom , password , phone , anonymous , google.com , facebook.com , github.com , twitter.com . |
firebase.tenant | Il tenantId associato all'account, se presente. ad esempio tenant2-m6tyz |
Se si utilizza l'autenticazione personalizzata, request.auth.token
contiene anche eventuali attestazioni personalizzate specificate dallo sviluppatore.
Quando un utente non autenticato esegue una richiesta, request.auth
è null
.
// Allow requests from authenticated users allow read, write: if request.auth != null;
path
La variabile path
contiene il percorso rispetto al quale viene eseguita una request
.
// Allow a request if the first path segment equals "images" allow read, write: if request.path[0] == 'images';
resource
La variabile resource
contiene i metadati di un file in fase di caricamento o i metadati aggiornati per un file esistente. Ciò è correlato alla variabile resource
, che contiene i metadati del file corrente nel percorso richiesto, anziché i nuovi metadati.
// Allow a request if the new value is smaller than 5MB allow read, write: if request.resource.size < 5 * 1024 * 1024;
request.resource
contiene le seguenti proprietà della resource
:
Proprietà |
---|
name |
bucket |
metadata |
size |
contentType |
time
La variabile time
contiene un timestamp che rappresenta l'ora corrente del server in cui viene valutata una richiesta. È possibile utilizzarlo per fornire un accesso ai file basato sul tempo, ad esempio: consentire il caricamento dei file solo fino a una determinata data o consentire la lettura dei file solo fino a un'ora dopo il caricamento.
// Allow a read if the file was created less than one hour ago allow read: if request.time < resource.timeCreated + duration.value(1, 'h');
Sono fornite molte funzioni per scrivere regole utilizzando timestamp e durate .
Risorsa
La variabile della resource
contiene metadati per i file in Cloud Storage, come nome file, dimensione, ora di creazione e metadati personalizzati.
Proprietà
name
Una stringa contenente il nome completo del file, incluso il percorso del file.
// Allow reads if the resource name is "path/to/object" allow read: if resource.name == 'path/to/object'
bucket
Una stringa contenente il bucket Google Cloud Storage in cui è archiviato questo file.
// Allow reads of all resources in your bucket allow read: if resource.bucket == '<your-cloud-storage-bucket>'
generation
Un int contenente la generazione dell'oggetto Google Cloud Storage del file. Utilizzato per il controllo delle versioni degli oggetti.
// Allow reads if the resource matches a known object version allow read: if resource.generation == <known-generation>
metageneration
Un int contenente la metagenerazione dell'oggetto Google Cloud Storage del file. Utilizzato per il controllo delle versioni degli oggetti.
// Allow reads if the resource matches a known object metadata version allow read: if resource.metageneration == <known-generation>
size
Un int contenente la dimensione del file in byte.
// Allow reads if the resource is less than 10 MB allow read: if resource.size < 10 * 1024 * 1024;
timeCreated
Un timestamp che rappresenta il momento in cui è stato creato il file.
// Allow reads if the resource was created less than an hour ago allow read: if resource.timeCreated < request.time + duration.value(60, "m")
updated
Un timestamp che rappresenta l'ultimo aggiornamento del file.
// Allow reads if the resource was updated less than an hour ago allow read: if resource.updated < request.time + duration.value(60, "m")
md5Hash
Una stringa contenente l' hash MD5 del file.
// Allow writes if the hash of the uploaded file is the same as the existing file allow write: if request.resource.md5Hash == resource.md5Hash;
crc32c
Una stringa contenente l' hash crc32c del file.
// Allow writes if the hash of the uploaded file is the same as the existing file allow write: if request.resource.crc32c == resource.crc32c;
etag
Una stringa contenente l' etag del file.
// Allow writes if the etag matches a known object etag allow write: if resource.etag == <known-generation>
contentDisposition
Una stringa contenente la disposizione del contenuto del file.
// Allow reads if the content disposition matches a certain value allow read: if resource.contentDisposition == 'inlined';
contentEncoding
Una stringa contenente la codifica del contenuto del file.
// Allow reads if the content is encoded with gzip allow read: if resource.contentEncoding == 'gzip';
contentLanguage
Una stringa contenente la lingua del contenuto del file.
// Allow reads if the content language is Japanese allow read: if resource.contentLanguage == 'ja';
contentType
Una stringa contenente il tipo di contenuto del file.
// Allow reads if the content type is PNG. allow read: if resource.contentType == 'image/png';
metadata
Un Map<String, String>
contenente ulteriori campi di metadati forniti dallo sviluppatore.
// Allow reads if a certain metadata field matches a desired value allow read: if resource.metadata.customProperty == 'customValue';
firestore.get e firestore.exist
Le funzioni firestore.get()
e firestore.exists()
consentono di accedere ai documenti in Cloud Firestore per valutare criteri di autorizzazione complessi.
Le funzioni firestore.get()
e firestore.exists()
prevedono entrambe percorsi di documenti completamente specificati. Quando si utilizzano variabili per costruire percorsi per firestore.get()
e firestore.exists()
, è necessario eseguire l'escape esplicito delle variabili utilizzando la sintassi $(variable)
.
firestore.get
Ottieni il contenuto di un documento Cloud Firestore.
service firebase.storage { match /b/{bucket}/o { match /users/{club}/files/{fileId} { allow read: if club in firestore.get(/databases/(default)/documents/users/$(request.auth.uid)).data.memberships } } }
firestore.exists
Controlla se esiste un documento Cloud Firestore.
service firebase.storage { match /b/{bucket}/o { match /users/{userId}/photos/{fileId} { allow read: if firestore.exists(/databases/(default)/documents/users/$(userId)/friends/$(request.auth.uid)) } } }
Servizio
Il service
è la prima dichiarazione in un file di regole di sicurezza di Cloud Storage e specifica a quale servizio verranno applicate queste regole.
Nome
name
Verrà applicato il nome delle regole del servizio. L'unico valore corrente è firebase.storage
.
// Specify the service name service firebase.storage { match /b/{bucket}/o { ... } }
Tipi di dati
Il linguaggio Rules consente di verificare il tipo utilizzando l'operatore is
.
// For example
a is null
a is string
null
Il tipo di dati null
rappresenta un valore non esistente.
allow read: if request.auth != null;
bool
Il tipo bool
rappresenta un valore booleano true
o false
.
allow read: if true; // always succeeds allow write: if false; // always fails
Confronto
I valori booleani possono essere confrontati utilizzando gli operatori ==
!=
.
Operazioni booleane
Operazione | Espressione |
---|---|
AND | x && y |
OR | x || y |
NOT | !x |
Le operazioni cortocircuitano e possono restituire true
, false
o Error .
allow read: if true || false; // always succeeds, short circuits at true allow write: if false && true; // always fails, short circuits at false
int
e float
I tipi int
e float
rappresentano i numeri. Gli interi sono: 0
, 1
, -2
, ecc. , mentre i float sono: 1.0
, -2.0
, 3.33
, ecc.
Gli int sono valori a 64 bit con segno e i float sono valori conformi a IEEE 754 a 64 bit. I valori di tipo int
verranno forzati a float
quando utilizzati in confronti e operazioni aritmetiche con un valore float
.
Confronto
Gli interi e i float possono essere confrontati e ordinati utilizzando gli operatori ==
, !=
, >
, <
, >=
e <=
.
Aritmetica
Gli interi e i float possono essere aggiunti, sottratti, moltiplicati, divisi, modulizzati e negati:
Operazione | Espressione |
---|---|
Aggiunta | x + y |
Sottrazione | x - y |
Moltiplicazione | x * y |
Divisione | x / y |
Modulo | x % y |
Negazione | -x |
Funzioni matematiche
Firebase Security Rules for Cloud Storage fornisce anche una serie di funzioni di supporto matematico per semplificare le espressioni:
Funzione | Descrizione |
---|---|
math.ceil(x) | Soffitto del valore numerico |
math.floor(x) | Piano del valore numerico |
math.round(x) | Arrotondare il valore di input all'interno più vicino |
math.abs(x) | Valore assoluto dell'input |
math.isInfinite(x) | Verifica se il valore è ±∞ , restituisce un bool |
math.isNaN(x) | Verifica se il valore non è un numero NaN , restituisce un bool |
string
Confronto
Le stringhe possono essere confrontate e ordinate lessograficamente utilizzando gli operatori ==
, !=
, >
, <
, >=
e <=
.
Concatenazione
Le stringhe possono essere concatenate utilizzando l'operatore +
.
// Concatenate a file name and extension 'file' + '.txt'
Indice e intervallo
L'operatore index
, string[]
, restituisce una stringa che contiene il carattere nell'indice fornito nella stringa.
// Allow reads of files that begin with 'a' match /{fileName} { allow read: if fileName[0] == 'a'; }
L'operatore range
, string[i:j]
, restituisce una stringa che contiene i caratteri tra gli indici specificati, da i
(incluso) fino a j
(esclusivo). Se i
o j
non sono specificati, il valore predefinito è rispettivamente 0 e la dimensione della stringa, ma è necessario specificare almeno i
o j
affinché l'intervallo sia valido.
// Allow reads of files that begin with 'abcdef' match /{fileName} { allow read: if fileName[0:6] == 'abcdef'; }
Gli operatori index
e range
genereranno un errore se gli indici forniti superano i limiti della stringa.
size
Restituisce il numero di caratteri nella stringa.
// Allow files with names less than 10 characters match /{fileName} { allow write: if fileName.size() < 10; }
matches
Esegue una corrispondenza con l'espressione regolare, restituisce true
se la stringa corrisponde all'espressione regolare data. Utilizza la sintassi Google RE2 .
// Allow writes to files which end in ".txt" match /{fileName} { allow write: if fileName.matches('.*\\.txt') }
split
Divide una stringa in base a un'espressione regolare fornita e restituisce un list
di stringhe. Utilizza la sintassi Google RE2 .
// Allow files named "file.*" to be uploaded match /{fileName} { allow write: if fileName.split('.*\\..*')[0] == 'file' }
path
I percorsi sono nomi simili a directory con corrispondenza di modelli opzionale. La presenza di una barra /
denota l'inizio di un segmento di percorso.
path
Converte un argomento string
in un path
.
// Allow reads on a specific file path match /{allFiles=**} { allow read: if allFiles == path('/path/to/file'); }
timestamp
I timestamp sono in UTC, con valori possibili che iniziano a 0001-01-01T00.00.00Z e terminano a 9999-12-31T23.59.59Z.
Confronto
I timestamp possono essere confrontati e ordinati utilizzando gli operatori ==
, !=
, >
, <
, >=
e <=
.
Aritmetica
I timestamp supportano l'addizione e la sottrazione tra timestamp e durate come segue:
Espressione | Risultato |
---|---|
timestamp + duration | timestamp |
duration + timestamp | timestamp |
timestamp - duration | timestamp |
timestamp - timestamp | duration |
duration + duration | duration |
duration - duration | duration |
date
Un valore timestamp
contenente solo year
, month
e day
.
// Allow reads on the same day that the resource was created. allow read: if request.time.date() == resource.timeCreated.date()
year
Il valore dell'anno come int, da 1 a 9999.
// Allow reads on all requests made before 2017 allow read: if request.time.year() < 2017
month
Il valore del mese come int, da 1 a 12.
// Allow reads on all requests made during the month of January allow read: if request.time.month() == 1;
day
Il giorno corrente del mese come int, da 1 a 31.
// Allow reads on all requests made during the first day of each month allow read: if request.time.day() == 1;
time
Un valore duration
contenente l'ora corrente.
// Allow reads on all requests made before 12PM allow read: if request.time.time() < duration.time(12, 0, 0, 0);
hours
Il valore delle ore è un int, da 0 a 23.
// Allow reads on all requests made before 12PM allow read: if request.time.hours() < 12;
minutes
Il valore dei minuti è un int, da 0 a 59.
// Allow reads during even minutes of every hour allow read: if request.time.minutes() % 2 == 0;
seconds
Il valore dei secondi è un int, da 0 a 59.
// Allow reads during the second half of each minute allow read: if request.time.seconds() > 29;
nanos
I secondi frazionari in nano come int.
// Allow reads during the first 0.1 seconds of each second allow read: if request.time.nanos() < 100000000;
dayOfWeek
Il giorno della settimana, dall'1 (lunedì) alle 7 (domenica).
// Allow reads on weekdays (Monday to Friday) allow read: if request.time.dayOfWeek() < 6;
dayOfYear
Il giorno dell'anno corrente, da 1 a 366.
// Allow reads every fourth day allow read: if request.time.dayOfYear() % 4 == 0;
toMillis
Restituisce il numero corrente di millisecondi dall'epoca di Unix.
// Allow reads if the request is made before a specified time allow read: if request.time.toMillis() < <milliseconds>;
duration
I valori di durata sono rappresentati come secondi più frazioni di secondo in nanosecondi.
Confronto
Le durate possono essere confrontate e ordinate utilizzando gli operatori ==
, !=
, >
, <
, >=
e <=
.
Aritmetica
Le durate supportano l'addizione e la sottrazione tra timestamp e durate come segue:
Espressione | Risultato |
---|---|
timestamp + duration | timestamp |
duration + timestamp | timestamp |
timestamp - duration | timestamp |
timestamp - timestamp | duration |
duration + duration | duration |
duration - duration | duration |
seconds
Il numero di secondi nella durata corrente. Deve essere compreso tra -315.576.000.000 e +315.576.000.000 inclusi.
nanos
Il numero di frazioni di secondo (in nanosecondi) della durata corrente. Deve essere compreso tra -999.999.999 e +999.999.999 inclusi. Per secondi diversi da zero e nanonsecondi diversi da zero, i segni di entrambi devono essere in accordo.
duration.value
Le durate possono essere create utilizzando la funzione duration.value(int magnitude, string units)
, che crea una durata temporale dalla grandezza e dall'unità specificate.
// All of these durations represent one hour: duration.value(1, "h") duration.value(60, "m") duration.value(3600, "s")
unit
possibili sono:
Durata | unit |
---|---|
Settimane | w |
Giorni | d |
Ore | h |
Minuti | m |
Secondi | s |
Millisecondi | ms |
Nanosecondi | ns |
duration.time
Le durate possono essere create utilizzando la funzione duration.time(int hours, int minutes, int seconds, int nanoseconds)
, che crea una durata temporale di ore, minuti, secondi e nanosecondi specificati.
// Create a four hour, three minute, two second, one nanosecond duration duration.time(4, 3, 2, 1)
list
Una lista contiene un array ordinato di valori, che può essere di tipo: null
, bool
, int
, float
, string
, path
, list
, map
, timestamp
o duration
.
Dati x
e y
di tipo list
e i
e j
di tipo int
Creazione
Per creare un elenco, aggiungi valori tra parentesi:
// Create a list of strings ['apples', 'grapes', 'bananas', 'cheese', 'goats']
Confronto
Gli elenchi possono essere confrontati utilizzando gli operatori ==
!=
. L'uguaglianza di due elenchi richiede che tutti i valori siano uguali.
Indice e intervallo
L'operatore index
, list[]
, restituisce l'elemento in corrispondenza dell'indice fornito nell'elenco.
// Allow reads of all files that begin with 'a' match /{fileName} { allow read: if fileName[0] == 'a'; }
L'operatore range
, list[i:j]
, restituisce tutti gli elementi in un elenco tra gli indici specificati, da i
(incluso) fino a j
(esclusivo). Se i
o j
non sono specificati, il valore predefinito è rispettivamente 0 e la dimensione dell'elenco, ma è necessario specificare almeno i
o j
affinché l'intervallo sia valido.
// Allow reads of all files that begin with 'abcdef' match /{fileName} { allow read: if fileName[0:6] == 'abcdef'; }
in
Restituisce true
se il valore desiderato è presente nella lista o false
se non presente.
// Allow read if a filename has the string 'txt' in it match /{fileName} { allow read: if 'txt' in fileName.split('\\.'); }
join
Combina un elenco di stringhe in un'unica stringa, separata dalla stringa specificata.
// Allow reads if the joined array is 'file.txt' allow read: if ['file', 'txt'].join('.') == 'file.txt';
size
Il numero di elementi nell'elenco.
// Allow read if there are three items in our list allow read: if ['foo', 'bar', 'baz'].size() == 3;
hasAll
Restituisce true
se tutti i valori sono presenti nell'elenco.
// Allow read if one list has all items in the other list allow read: if ['file', 'txt'].hasAll(['file', 'txt']);
map
Una mappa contiene coppie chiave/valore, dove le chiavi sono stringhe e i valori possono essere uno qualsiasi tra: null
, bool
, int
, float
, string
, path
, list
, map
, timestamp
o duration
.
Creazione
Per creare una mappa, aggiungi coppie chiave/valore tra parentesi graffe:
// Create a map of strings to strings { 'mercury': 'mars', 'rain': 'cloud', 'cats': 'dogs', }
Confronto
Le mappe possono essere confrontate utilizzando gli operatori ==
!=
. L'uguaglianza di due mappe richiede che tutte le chiavi siano presenti in entrambe le mappe e che tutti i valori siano uguali.
Indice
È possibile accedere ai valori in una mappa utilizzando la notazione tra parentesi o punto:
// Access custom metadata properties allow read: if resource.metadata.property == 'property' allow write: if resource.metadata['otherProperty'] == 'otherProperty'
Se una chiave non è presente, verrà restituito un error
.
in
Restituisce true
se la chiave desiderata è presente nella mappa o false
se non presente.
// Allow reads if a property is present in the custom metadata allow read: if property in resource.metadata;
size
Il numero di chiavi nella mappa.
// Allow reads if there's exactly one custom metadata key allow read: if resource.metadata.size() == 1;
keys
Un elenco di tutte le chiavi nella mappa.
// Allow reads if the first metadata key is 'myKey' allow read: if resource.metadata.keys()[0] == 'myKey';
values
Un elenco di tutti i valori nella mappa, in ordine chiave.
// Allow reads if the first metadata value is 'myValue' allow read: if resource.metadata.values()[0] == 'myValue';
Errori
Valutazione degli errori
Le regole di sicurezza Firebase per Cloud Storage continuano la valutazione quando vengono rilevati errori. Questo è utile perché i condizionali &&
e ||
le espressioni possono assorbire un errore se il condizionale altrimenti andrebbe in cortocircuito rispettivamente in false
o true
. Ad esempio:
Espressione | Risultato |
---|---|
error && true | error |
error && false | false |
error || true | true |
error || false | error |
I luoghi comuni in cui vengono generati errori sono: divisione per zero, accesso a valori in un elenco o mappa che non esistono e passaggio di valori di tipo errato a una funzione.
// Error if resource.size is zero allow read: if 1000000 / resource.size; // Error, key doesn't exist allow read: if resource.metadata.nonExistentKey == 'value'; // Error, no unit 'y' exists allow read: if request.time < resource.timeCreated + duration.value(1, 'y');