---
title: "Regole di sicurezza Firebase: 11 regole attaccate"
description: "Regole di sicurezza Firebase testate nell’emulatore: cosa lasciava fare ogni regola a un ospite o a un altro utente e la regola che ha chiuso la falla."
url: "https://madsalt.tech/it/blog/firebase-security-rules-examples/"
author: "Denys Zaichenko"
author_url: "https://madsalt.tech/it/about/"
language: "it"
published: 2026-11-03
---

# Regole di sicurezza Firebase: 11 regole attaccate

In breve

Ho inviato le stesse richieste a 11 set di regole Firestore, come ospite, come utente anonimo e come tre utenti autenticati. `request.auth != null` ha lasciato a un estraneo la possibilità di leggere, modificare ed eliminare gli ordini di tutti. Un controllo del proprietario solo su `resource` ha permesso a un utente di cedere un ordine a un altro. Un solo `match` ampio `{document=**}` ha aperto una collezione che aveva una regola del proprietario corretta. E un ruolo salvato in un documento che l'utente può scrivere lo ha reso admin con una sola richiesta. Ogni caso ha la sua correzione qui sotto, e la regola corretta ha retto alle stesse richieste.

Un'app Firebase non ha un suo server tra il browser e il database. La configurazione del progetto viaggia nella pagina, e le [regole di sicurezza](https://firebase.google.com/docs/rules/insecure-rules) sono ciò che sta tra chiunque la possieda e i Suoi dati. Volevo quindi esempi di regole con l'attacco accanto, non un elenco di regole che sembrano giuste.

**Come ho testato.** Firebase Local Emulator Suite da Firebase CLI 15.34.2, il 3 novembre 2026. Ho caricato ogni set di regole, azzerato i dati e chiamato l'API REST di Firestore con veri token dell'emulatore Auth: nessun token, un utente anonimo, gli utenti A e B, e un estraneo che si era appena registrato. I dati erano inventati: gli ordini `a1` e `a2` di A, `b1` di B.

## Quali regole Firebase lasciano trapelare i dati?

| Regola                                              | Richiesta                                    | Risultato        |
| --------------------------------------------------- | -------------------------------------------- | ---------------- |
| `if true` (modalità test)                           | L'ospite elenca gli ordini                   | `200`, tutti e 3 |
| `if true` (modalità test)                           | L'ospite elimina l'ordine di B               | `200`            |
| `request.auth != null`                              | L'utente anonimo elenca gli ordini           | `200`, tutti e 3 |
| `request.auth != null`                              | L'estraneo elimina l'ordine di A             | `200`            |
| Controllo del proprietario solo su `resource`       | A crea un ordine di proprietà di B           | `200`            |
| Controllo del proprietario solo su `resource`       | A cambia `ownerId` del proprio ordine        | `200`            |
| Regola del proprietario più lettura `{document=**}` | A legge l'ordine di B                        | `200`            |
| L'utente può scrivere il proprio doc `users`        | A imposta `role: admin`, legge l'ordine di B | `200`            |

## Cosa apre davvero la modalità test?

```
match /{document=**} {
  allow read, write: if true;
}
```

Tutto, a tutti. Un ospite senza token ha elencato tutti e 3 gli ordini, ne ha eliminato uno e ne ha creato uno nuovo. Niente di tutto questo richiede un account o un segreto trapelato, solo l'id del progetto.

La versione con scadenza che la modalità test usa spesso fallisce in modo diverso. Con `if request.time < timestamp.date(2026, 1, 1)` e quella data nel passato, l'ospite ha ricevuto `403` e così l'utente A che leggeva il proprio ordine. La falla è chiusa, e con lei l'app.

## `request.auth != null` basta?

No. Dice solo che dietro la richiesta c'è un account qualsiasi.

```
match /orders/{id} {
  allow read, write: if request.auth != null;
}
```

L'ospite ha ricevuto `403`, ed è per questo che questa regola sembra sicura in un test rapido. Poi un estraneo che si era solo registrato ha elencato tutti e 3 gli ordini, cambiato il totale dell'ordine di B ed eliminato quello di A, ogni volta con `200`. Anche un utente anonimo ha elencato tutti e 3. Se la registrazione è aperta, questa regola significa «chiunque si prenda la briga di registrarsi». La documentazione di Firebase la elenca anch'essa tra i [pattern insicuri comuni](https://firebase.google.com/docs/rules/insecure-rules).

## Perché un controllo del proprietario ha bisogno sia di `resource` sia di `request.resource`?

`resource` è il documento com'è salvato. `request.resource` è il documento come sarebbe dopo la scrittura. Una regola che guarda solo il primo verifica di chi è la riga adesso, e non dice nulla su ciò che diventa.

```
match /orders/{id} {
  allow read, update, delete: if resource.data.ownerId == request.auth.uid;
  allow create: if request.auth != null;
}
```

Le letture sembravano giuste: A ha ricevuto `200` sul proprio ordine e `403` su quello di B. Le scritture no. A ha creato un nuovo ordine con `ownerId` impostato su B, e ha ricevuto `200`. A ha poi cambiato `ownerId` del proprio ordine in B, anche qui `200`, e da quel momento B poteva leggerlo. In un'app dove gli ordini sono fatture o saldi, è un utente che scrive nell'account di qualcun altro.

Questa versione ha rifiutato tutto:

```
match /orders/{id} {
  allow read, delete: if request.auth != null
    && resource.data.ownerId == request.auth.uid;
  allow create: if request.auth != null
    && request.resource.data.ownerId == request.auth.uid;
  allow update: if request.auth != null
    && resource.data.ownerId == request.auth.uid
    && request.resource.data.ownerId == resource.data.ownerId;
}
```

| Richiesta di A                             | Risultato |
| ------------------------------------------ | --------- |
| Leggere il proprio ordine                  | `200`     |
| Leggere, modificare, eliminare quello di B | `403`     |
| Creare un ordine di proprietà di B         | `403`     |
| Cambiare `ownerId` in B                    | `403`     |

A poteva comunque cambiare il `total` del proprio ordine, con `200`. Se il client non deve impostare quel campo, indichi quali campi può modificare:

```
allow update: if request.auth != null
  && resource.data.ownerId == request.auth.uid
  && request.resource.data.diff(resource.data).affectedKeys().hasOnly(['note']);
```

Con questa regola, cambiare `total` ha restituito `403` e cambiare `note` ha restituito `200`.

## Perché la mia query è fallita con una regola corretta?

Perché [le regole non sono filtri](https://firebase.google.com/docs/firestore/security/rules-query). Con la regola del proprietario qui sopra, A che chiedeva l'intera collezione ha ricevuto `403`, anche se possiede 2 ordini su 3. Firestore giudica la query da ciò che potrebbe restituire, non da ciò che c'è.

| Richiesta di A            | Risultato    |
| ------------------------- | ------------ |
| Elencare tutti gli ordini | `403`        |
| Query `ownerId == A`      | `200`, 2 doc |
| Query `ownerId == B`      | `403`        |

Quindi quando un elenco si rompe dopo aver stretto le regole, corregga la query. Allargare la regola per far funzionare l'elenco è il modo in cui si scrivono le regole troppo ampie viste sopra.

## Un match ampio può annullare una regola corretta?

Sì, ed è la prima cosa che cercherei in un progetto con un lungo file di regole. Firestore [consente una richiesta se una qualsiasi regola corrispondente la consente](https://firebase.google.com/docs/firestore/security/rules-structure).

```
match /orders/{id} {
  allow read: if request.auth != null
    && resource.data.ownerId == request.auth.uid;
}
match /{document=**} {
  allow read: if request.auth != null;
}
```

Il primo blocco sembra una buona regola del proprietario. Con il secondo presente, A ha letto l'ordine di B con `200`, un estraneo ha elencato tutti e 3 gli ordini, e lo stesso estraneo ha letto il documento di A in `users`. Nulla nel primo blocco La avvisa. Elimini il match ampio; non c'è modo di far sì che una regola successiva ritiri l'accesso.

## Come si rende admin un utente?

Questo schema compare ogni volta che i ruoli stanno in un documento:

```
function isAdmin() {
  return get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == 'admin';
}
match /users/{uid} {
  allow read, write: if request.auth.uid == uid;
}
match /orders/{id} {
  allow read: if resource.data.ownerId == request.auth.uid || isAdmin();
}
```

«Gli utenti possono modificare il proprio profilo» e «gli admin possono leggere tutti gli ordini» sono entrambe ragionevoli. Insieme sono un'escalation di privilegi.

![Admin in una richiesta. Utente A, il cui documento users è scrivibile. Prima: Utente A → legge l’ordine di B → 403; Scrive il proprio ruolo: Utente A → role: admin → 200; Dopo: Utente A → legge l’ordine di B → 200.](https://madsalt.tech/charts/it/firebase-security-rules-examples.svg)

*Figura 1. Il mio test nell’emulatore Firebase (CLI 15.34.2), 3 novembre 2026.*

La correzione è impedire al client di scrivere quel campo. Con `request.resource.data.role == resource.data.role` aggiunto alla regola di scrittura, la stessa richiesta ha restituito `403` e A è rimasto fuori dall'ordine di B. I custom claim impostati da un server sono l'altra strada, perché un client non può modificarli.

## Due cose che si sono rivelate a posto

Le regole su un genitore non trapelano nelle sottocollezioni. Con `allow read` su `/orders/{id}` per qualsiasi utente autenticato, A ha letto l'ordine, e `/orders/b1/notes/n1` sotto di esso ha restituito `403`. È il [comportamento documentato](https://firebase.google.com/docs/firestore/security/rules-structure): le regole si applicano solo al percorso corrispondente.

Un ospite non passa con un confronto contro un token assente. `resource.data.ownerId == request.auth.uid` ha restituito `403` per l'ospite anche senza un `request.auth != null` separato. Il controllo lo scrivo comunque, perché così la regola dice ciò che intende.

## Come si controllano le proprie regole?

Esegua le Sue richieste nell'emulatore come ospite, come estraneo e come secondo utente. È ciò che ha fatto emergere ogni caso qui sopra; leggere le regole no.

Per un primo passaggio, il [Controllo regole Firebase](https://madsalt.tech/it/tools/firebase-rules-checker/) gratuito legge regole incollate senza toccare il Suo progetto. Sui set di regole di questo articolo ha segnalato la modalità test, l'accesso solo per utenti autenticati, il match ampio e il ruolo scritto dall'utente. Legge solo testo, quindi non può dirLe che aspetto abbiano i Suoi dati né se una regola è stata distribuita.

La Sua `apiKey` nella pagina non è di per sé il problema. La configurazione web di Firebase è pubblica per scelta, e lo [scanner di segreti](https://madsalt.tech/it/tools/secret-scanner/) gratuito la segnala come tale, perché sono le regole a proteggere i dati dietro. I file seguono ancora altre regole, con una falla che le regole non possono fermare, che ho testato in regole Firebase Storage.

**Limiti.** Solo Firestore, nell'emulatore locale, via REST, su dati inventati. Il Realtime Database usa un altro linguaggio di regole e non è stato testato. App Check, che limita quali app possono chiamare il Suo backend, non ne fa parte; non sostituisce le regole. La produzione può differire dall'emulatore in dettagli che non ho verificato.

Non è sicuro di cosa lascino passare le Sue regole?

Le leggo volentieri insieme a Lei. Nessuna vendita.

[Mi contatti](https://madsalt.tech/it/#contact)
