Regole di sicurezza per le operazioni della pipeline

Sebbene le operazioni della pipeline offrano un ricco insieme di funzionalità, il motore delle regole è limitato al riconoscimento dei filtri di confronto (ad es. >) e logici (ad es. or) per garantire la soddisfacibilità e la sicurezza dei vincoli.

Espressioni di filtro supportate

Affinché le operazioni della pipeline siano limitate ai limiti impostati dalle regole, devono utilizzare operatori logici e di confronto con le costanti. I seguenti tipi di filtri sono riconosciuti dal motore delle regole:

  • Confronti: eq, neq, gt, gte, lt, lte, in, arrayContains.
  • Logici: and, or.

Ecco alcuni esempi:

  • where(eq("foo", 2))
  • where(lt("foo", 2))
  • documents("/user/1", "/user/2").where(...)

Proprietà della richiesta

Puoi continuare a utilizzare l'oggetto request per convalidare l'autenticazione e il contesto della query, anche se alcune proprietà disponibili nelle query standard non sono supportate nelle operazioni della pipeline.

Proprietà supportate

Il nuovo motore continua a supportare le seguenti proprietà:

  • request.auth: accedi ai dati relativi all'UID e al token dell'utente.
  • request.method: identifica l'operazione (ad esempio, get, list).
  • request.path: il percorso della risorsa a cui si accede.
  • request.time: il timestamp lato server della richiesta.

Proprietà non supportate

Le proprietà request.query come limit, offset e orderBy non sono supportate per i controlli delle regole delle operazioni di pipeline a causa della complessità della determinazione di questi valori nelle query multifase.

Gestione e autorizzazioni delle fasi della pipeline

Esistono diverse fasi della pipeline che corrispondono a operazioni granulari specifiche nelle regole di sicurezza:

  • Autorizzazioni allow list: attivate dalle fasi collection(), collectionGroup() e database().
  • Autorizzazioni allow get: attivate dalla fase documents(), che viene trattata in modo simile a un'operazione get batch.
  • Autorizzazioni allow create: attivate dalle fasi insert() e upsert() durante la creazione di nuovi documenti.
  • Autorizzazioni allow update: attivate dalle fasi update() e dalle fasi upsert() durante l'aggiornamento dei documenti esistenti.
  • Autorizzazioni allow delete: attivate da delete() fasi.
  • Autorizzazioni allow write: si applicano a tutte le operazioni DML (insert(), update(), upsert() e delete()).
  • Fase Literals: la fase literals() non legge dal database, ma può comportare costi. Per impedire utilizzi illeciti, deve essere associata a un'altra fase (come collection()) che può essere verificata dalle regole.

Fasi di modifica dei campi

Le regole operano solo sui dati archiviati e non sui valori derivati. Se una pipeline include fasi che modificano i campi (ad esempio, add_fields(...), replace_with(...), select(...), remove_fields(...)), il motore delle regole interrompe l'applicazione dei vincoli di filtro dopo che viene rilevata la fase. Per assicurarti che le regole funzionino come previsto, posiziona le fasi di filtro (ovvero where) prima di qualsiasi fase che possa modificare i documenti archiviati originali.

Ad esempio, considera la seguente regola di sicurezza:

match /databases/{database}/documents {
  match /cities/{city} {
    // Allow the user to read data if the document has the 'visibility'
    // field set to 'public'
    allow read: if resource.data.visibility == 'public';
  }
}

Negata: questa regola rifiuta la seguente pipeline perché la fase addFields si verifica prima del filtro dei documenti in cui visibility è public:

const results = await db.pipeline()
  .collection("/cities")
  // Filters after a modification stage are ignored by Rules.
  .addFields(constant(1000).as("population"))
  .where(eq(field("visibility"), constant("public")))
  .execute();

Consentita: questa regola consente la seguente pipeline perché la fase where(eq(field("visibility"), constant("public"))) si verifica prima di qualsiasi fase di modifica:

const results = await db.pipeline()
  .collection("/cities")
  .where(eq(field("visibility"), constant("public")))
  .addFields(constant(1000).as("population"))
  .execute();

Fasi del linguaggio di manipolazione dei dati e regole di sicurezza

Quando esegui le fasi del linguaggio di manipolazione dei dati (DML) (insert(), update(), upsert() e delete()), le regole di sicurezza valutano le autorizzazioni in modo diverso rispetto alle query di lettura:

  • Valutazione delle regole per documento: a differenza delle pipeline di lettura, che richiedono espressioni di filtro in anticipo per limitare la query in fase di pianificazione, le operazioni DML valutano le regole di sicurezza in base a ogni singola mutazione del documento.
  • Variabili delle regole:
    • request.resource: contiene i dati del documento proposti per le operazioni insert(), update() e upsert().
    • resource: contiene i dati del documento corrente archiviati nel database prima della modifica (disponibile per update(), delete() e upsert() dei documenti esistenti).

Limiti di sistema e comportamento di esecuzione con DML

Quando esegui operazioni DML con le regole di sicurezza, tieni presente i seguenti limiti di sistema e comportamenti di esecuzione:

Il limite di 20 ricerche su get() e exists()

Le regole di sicurezza di Firebase consentono un massimo di 20 ricerche di documenti (get() o exists()) in un'intera richiesta.

Quando una pipeline DML viene eseguita al di fuori di una transazione esplicita, Cloud Firestore elabora le scritture dei documenti in batch. Poiché ogni batch viene eseguito nella propria transazione e i documenti potrebbero essere modificati contemporaneamente tra i batch, le regole di sicurezza e le ricerche dei documenti vengono rivalutate per ogni batch di scrittura.

Anche se le regole di sicurezza vengono valutate rispetto a un singolo documento statico (ad esempio, per verificare se un utente è un amministratore):

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /posts/{postId} {
      allow write: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.isAdmin == true;
    }
  }
}

Ogni batch di scrittura di 10 documenti esegue una ricerca. Di conseguenza, dopo aver scritto tutti i documenti possibili, viene raggiunto il limite di 20 ricerche per la richiesta e la pipeline non va a buon fine con un errore PERMISSION_DENIED. Inoltre, ogni ricerca eseguita per batch di scrittura comporta una fatturazione di lettura separata.

Operazione riuscita parzialmente e PERMISSION_DENIED

Quando vengono eseguite al di fuori di una transazione, le operazioni DML eseguono il commit delle scritture in batch sequenziali. Se un batch non va a buon fine, perché un documento non soddisfa una condizione della regola o perché viene superato il limite di 20 ricerche, la pipeline si interrompe e restituisce un errore PERMISSION_DENIED.

Tuttavia, non viene eseguito il rollback dei batch di cui è già stato eseguito il commit. Il database rimane in uno stato parzialmente aggiornato. Poiché il client riceve un errore senza un elenco di documenti modificati, devi eseguire una query sui dati per verificare quali scritture sono state eseguite correttamente.

Diagnosi degli errori delle regole con Cloud Audit Logs

Per motivi di sicurezza, gli errori PERMISSION_DENIED rivolti ai client non rivelano quale condizione della regola di sicurezza non è stata soddisfatta o se è stato raggiunto il limite di 20 ricerche.

Per diagnosticare gli errori di valutazione delle regole, gli amministratori del progetto possono esaminare gli audit log di Cloud nella console Google Cloud (in Firestore > Monitoring o in Esplora log) per visualizzare le voci EvaluationError dettagliate.