Condizioni d'uso nelle regole di sicurezza Firebase Cloud Storage

Questa guida si basa sulla sintassi di base della guida linguistica Firebase Security Rules per mostrare come aggiungere condizioni alle Firebase Security Rules for Cloud Storage.

L'elemento fondamentale delle regole di sicurezza di Cloud Storage è la condizione . Una condizione è un'espressione booleana che determina se una particolare operazione deve essere consentita o negata. Per le regole di base, l'utilizzo di valori letterali true e false come condizioni funziona perfettamente. Ma il linguaggio Firebase Security Rules for Cloud Storage ti offre modi per scrivere condizioni più complesse che possono:

  • Controlla l'autenticazione dell'utente
  • Convalidare i dati in arrivo

Autenticazione

Firebase Security Rules for Cloud Storage si integra con Firebase Authentication per fornire una potente autenticazione basata sull'utente a Cloud Storage. Ciò consente un controllo granulare degli accessi basato sulle attestazioni di un token di autenticazione Firebase.

Quando un utente autenticato esegue una richiesta su Cloud Storage, la variabile request.auth viene popolata con l' uid dell'utente ( request.auth.uid ) e con le attestazioni del JWT di autenticazione Firebase ( request.auth.token ).

Inoltre, quando si utilizza l'autenticazione personalizzata, vengono visualizzate ulteriori attestazioni nel campo request.auth.token .

Quando un utente non autenticato esegue una richiesta, la variabile request.auth è null .

Utilizzando questi dati, esistono diversi modi comuni per utilizzare l'autenticazione per proteggere i file:

  • Pubblico: ignora request.auth
  • Privato autenticato: controlla che request.auth non sia null
  • Utente privato: controlla che request.auth.uid sia uguale a un uid del percorso
  • Privato di gruppo: controlla le attestazioni del token personalizzato per corrispondere a un'attestazione scelta o leggi i metadati del file per vedere se esiste un campo di metadati

Pubblico

Qualsiasi regola che non considera il contesto request.auth può essere considerata una regola public , poiché non considera il contesto di autenticazione dell'utente. Queste regole possono essere utili per far emergere dati pubblici come risorse di gioco, file audio o altri contenuti statici.

// Anyone to read a public image if the file is less than 100kB
// Anyone can upload a public file ending in '.txt'
match /public/{imageId} {
  allow read: if resource.size < 100 * 1024;
  allow write: if imageId.matches(".*\\.txt");
}

Privato autenticato

In alcuni casi, potresti volere che i dati siano visualizzabili da tutti gli utenti autenticati della tua applicazione, ma non dagli utenti non autenticati. Poiché la variabile request.auth è null per tutti gli utenti non autenticati, tutto ciò che devi fare è verificare che la variabile request.auth esista per richiedere l'autenticazione:

// Require authentication on all internal image reads
match /internal/{imageId} {
  allow read: if request.auth != null;
}

Utente privato

Di gran lunga il caso d'uso più comune per request.auth sarà quello di fornire ai singoli utenti autorizzazioni granulari sui propri file: dal caricamento delle immagini del profilo alla lettura di documenti privati.

Poiché i file in Cloud Storage hanno un "percorso" completo, tutto ciò che serve per rendere un file controllato da un utente è un'informazione univoca che identifica l'utente nel prefisso del nome file (come l' uid dell'utente) che può essere controllata quando la regola viene valutata:

// Only a user can upload their profile picture, but anyone can view it
match /users/{userId}/profilePicture.png {
  allow read;
  allow write: if request.auth.uid == userId;
}

Gruppo privato

Un altro caso d'uso altrettanto comune sarà quello di consentire autorizzazioni di gruppo su un oggetto, ad esempio consentire a più membri del team di collaborare su un documento condiviso. Esistono diversi approcci per farlo:

  • Conia un token personalizzato di autenticazione Firebase che contenga informazioni aggiuntive su un membro del gruppo (come un ID gruppo)
  • Includere informazioni sul gruppo (come un ID di gruppo o un elenco di uid autorizzati) nei metadati del file

Una volta archiviati nel token o nei metadati del file, questi dati possono essere referenziati all'interno di una regola:

// Allow reads if the group ID in your token matches the file metadata's `owner` property
// Allow writes if the group ID is in the user's custom token
match /files/{groupId}/{fileName} {
  allow read: if resource.metadata.owner == request.auth.token.groupId;
  allow write: if request.auth.token.groupId == groupId;
}

Richiedi valutazione

Caricamenti, download, modifiche ai metadati ed eliminazioni vengono valutati utilizzando la request inviata a Cloud Storage. Oltre all'ID univoco dell'utente e al payload dell'autenticazione Firebase nell'oggetto request.auth come descritto sopra, la variabile request contiene il percorso del file in cui viene eseguita la richiesta, l'ora in cui viene ricevuta la richiesta e il nuovo valore resource se la richiesta è una scrittura.

L'oggetto request contiene anche l'ID univoco dell'utente e il payload dell'autenticazione Firebase nell'oggetto request.auth , che verrà spiegato ulteriormente nella sezione Sicurezza basata sull'utente della documentazione.

Un elenco completo delle proprietà nell'oggetto request è disponibile di seguito:

Proprietà Tipo Descrizione
auth mappa<stringa, stringa> Quando un utente ha effettuato l'accesso, fornisce uid , l'ID univoco dell'utente e token , una mappa delle attestazioni JWT di autenticazione Firebase. Altrimenti sarà null .
params mappa<stringa, stringa> Mappa contenente i parametri di query della richiesta.
path sentiero Un path che rappresenta il percorso in cui viene eseguita la richiesta.
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

Quando valuti le regole, potresti anche voler valutare i metadati del file che viene caricato, scaricato, modificato o eliminato. Ciò ti consente di creare regole complesse e potenti che fanno cose come consentire solo il caricamento di file con determinati tipi di contenuto o l'eliminazione solo di file più grandi di una certa dimensione.

Le regole di sicurezza Firebase per Cloud Storage forniscono metadati di file nell'oggetto resource , che contiene coppie chiave/valore dei metadati visualizzati in un oggetto Cloud Storage. Queste proprietà possono essere ispezionate durante le richieste di read o write per garantire l'integrità dei dati.

Nelle richieste write (come caricamenti, aggiornamenti di metadati ed eliminazioni), oltre all'oggetto resource , che contiene i metadati del file attualmente esistente nel percorso della richiesta, hai anche la possibilità di utilizzare l'oggetto request.resource , che contiene un sottoinsieme dei metadati del file da scrivere se la scrittura è consentita. È possibile utilizzare questi due valori per garantire l'integrità dei dati o applicare vincoli dell'applicazione come il tipo o la dimensione del file.

Di seguito è disponibile un elenco completo delle proprietà nell'oggetto resource :

Proprietà Tipo Descrizione
name corda Il nome completo dell'oggetto
bucket corda Il nome del bucket in cui risiede questo oggetto.
generation int La generazione dell'oggetto Google Cloud Storage di questo oggetto.
metageneration int La metagenerazione dell'oggetto Google Cloud Storage di questo oggetto.
size int La dimensione 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 corda Un hash MD5 dell'oggetto.
crc32c corda Un hash crc32c dell'oggetto.
etag corda L'etag associato a questo oggetto.
contentDisposition corda La disposizione del contenuto associata a questo oggetto.
contentEncoding corda La codifica del contenuto associato a questo oggetto.
contentLanguage corda La lingua del contenuto associata a questo oggetto.
contentType corda Il tipo di contenuto associato a questo oggetto.
metadata mappa<stringa, stringa> Coppie chiave/valore di metadati personalizzati aggiuntivi specificati dallo sviluppatore.

request.resource contiene tutti questi elementi ad eccezione di generation , metageneration , etag , timeCreated e updated .

Migliora con Cloud Firestore

Puoi accedere ai documenti in Cloud Firestore per valutare altri criteri di autorizzazione.

Utilizzando le funzioni firestore.get() e firestore.exists() , le tue regole di sicurezza possono valutare le richieste in entrata rispetto ai documenti in Cloud Firestore. 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) .

Nell'esempio seguente vediamo una regola che limita l'accesso in lettura ai file agli utenti che sono membri di determinati club.

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.id)).memberships
    }
  }
}
Nell'esempio successivo, solo gli amici di un utente possono vedere le proprie foto.
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.id))
    }
  }
}

Dopo aver creato e salvato le prime regole di sicurezza di Cloud Storage che utilizzano queste funzioni di Cloud Firestore, ti verrà richiesto nella console Firebase o nella CLI di Firebase di abilitare le autorizzazioni per connettere i due prodotti.

Puoi disabilitare la funzionalità rimuovendo un ruolo IAM, come descritto in Gestire e distribuire le regole di sicurezza Firebase .

Convalidare i dati

Le regole di sicurezza Firebase per Cloud Storage possono essere utilizzate anche per la convalida dei dati, inclusa la convalida del nome e del percorso del file, nonché delle proprietà dei metadati del file come contentType e size .

service firebase.storage {
  match /b/{bucket}/o {
    match /images/{imageId} {
      // Only allow uploads of any image file that's less than 5MB
      allow write: if request.resource.size < 5 * 1024 * 1024
                   && request.resource.contentType.matches('image/.*');
    }
  }
}

Funzioni personalizzate

Man mano che le regole di sicurezza Firebase diventano più complesse, potresti voler racchiudere serie di condizioni in funzioni che puoi riutilizzare nel tuo set di regole. Le regole di sicurezza supportano funzioni personalizzate. La sintassi per le funzioni personalizzate è un po' come JavaScript, ma le funzioni delle regole di sicurezza Firebase sono scritte in un linguaggio specifico del dominio che presenta alcune importanti limitazioni:

  • Le funzioni possono contenere solo una singola istruzione return . Non possono contenere alcuna logica aggiuntiva. Ad esempio, non possono eseguire cicli o chiamare servizi esterni.
  • Le funzioni possono accedere automaticamente a funzioni e variabili dall'ambito in cui sono definite. Ad esempio, una funzione definita nell'ambito del service firebase.storage ha accesso alla variabile resource e, solo per Cloud Firestore, funzioni integrate come get() ed exists() .
  • Le funzioni possono chiamare altre funzioni ma non possono ricorrere. La profondità totale dello stack di chiamate è limitata a 10.
  • Nella versione rules2 , le funzioni possono definire variabili utilizzando la parola chiave let . Le funzioni possono avere un numero qualsiasi di let associazioni, ma devono terminare con un'istruzione return.

Una funzione è definita con la parola chiave function e accetta zero o più argomenti. Ad esempio, potresti voler combinare i due tipi di condizioni utilizzati negli esempi precedenti in un'unica funzione:

service firebase.storage {
  match /b/{bucket}/o {
    // True if the user is signed in or the requested data is 'public'
    function signedInOrPublic() {
      return request.auth.uid != null || resource.data.visibility == 'public';
    }
    match /images/{imageId} {
      allow read, write: if signedInOrPublic();
    }
    match /mp3s/{mp3Ids} {
      allow read: if signedInOrPublic();
    }
  }
}

L'utilizzo delle funzioni nelle regole di sicurezza Firebase le rende più gestibili man mano che la complessità delle regole aumenta.

Prossimi passi

Dopo questa discussione sulle condizioni, hai una comprensione più sofisticata delle Regole e sei pronto per:

Scopri come gestire i casi d'uso principali e apprendi il flusso di lavoro per lo sviluppo, il test e la distribuzione delle regole: