Pereiti prie turinio

Firebase security rules pavyzdžiai: 11 išbandytų taisyklių

Žiūrėti kaip MarkdownAtidaryti per ClaudeAtidaryti per ChatGPTAtidaryti per Perplexity

Klausimas taip pat nukopijuojamas. Jei pokalbis atsidaro tuščias, įklijuokite jį.

Trumpai

Tas pačias užklausas išsiunčiau prieš 11 Firestore taisyklių rinkinių kaip svečias, anoniminis vartotojas ir trys prisijungę vartotojai. request.auth != null leido pašaliniam žmogui skaityti, keisti ir trinti visų užsakymus. Savininko patikra tik pagal resource leido vartotojui perduoti užsakymą kitam. Vienas platus {document=**} match atvėrė kolekciją, kuri turėjo teisingą savininko taisyklę. O rolė, laikoma vartotojo įrašomame dokumente, vienu užklausimu padarė jį administratoriumi. Kiekvienam atvejui žemiau yra pataisymas, ir pataisyta taisyklė atlaikė tas pačias užklausas.

Tarp naršyklės ir duomenų bazės Firebase programoje nėra jūsų serverio. Projekto konfigūracija pateikiama kartu su puslapiu, o security rules yra vienintelis barjeras tarp bet kurio jos turėtojo ir jūsų duomenų. Todėl norėjau pavyzdžių, kuriuose šalia taisyklės parodyta ataka, o ne sąrašo taisyklių, kurios tik atrodo teisingos.

Kaip testavau. Firebase Local Emulator Suite iš Firebase CLI 15.34.2, 2026 m. lapkričio 3 d. Kiekvieną taisyklių rinkinį įkėliau, atstačiau duomenis ir kviečiau Firestore REST API su tikrais Auth emuliatoriaus tokenais: be tokeno, anoniminis vartotojas, vartotojai A ir B bei pašalinis, kuris tik užsiregistravo. Duomenys išgalvoti: užsakymai a1 ir a2 priklauso A, b1 priklauso B.

Kurios Firebase taisyklės praleidžia?

Taisyklė Užklausa Rezultatas
if true (testavimo režimas) Svečias išvardija užsakymus 200, visi 3
if true (testavimo režimas) Svečias ištrina B užsakymą 200
request.auth != null Anoniminis vartotojas išvardija užsakymus 200, visi 3
request.auth != null Pašalinis ištrina A užsakymą 200
Savininko patikra tik pagal resource A sukuria užsakymą, priklausantį B 200
Savininko patikra tik pagal resource A pakeičia savo užsakymo ownerId 200
Savininko taisyklė ir {document=**} read A skaito B užsakymą 200
Vartotojas gali rašyti savo users dokumentą A nustato role: admin, skaito B užsakymą 200

Ką iš tikrųjų atveria testavimo režimas?

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

Viską ir visiems. Svečias be tokeno išvardijo visus 3 užsakymus, vieną ištrynė ir sukūrė naują. Tam nereikia nei paskyros, nei nutekėjusios paslapties, tik projekto id.

Datuota testavimo režimo versija suklysta kitaip. Su if request.time < timestamp.date(2026, 1, 1) ir šia data praeityje svečias gavo 403, o vartotojas A, skaitantis savo užsakymą, taip pat. Nutekėjimas baigėsi, bet kartu ir programa.

Ar pakanka request.auth != null?

Ne. Ji tik sako, kad už užklausos yra kokia nors paskyra.

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

Svečias gavo 403, todėl per greitą testą ši taisyklė atrodo saugi. Tada pašalinis, kuris tik užsiregistravo, išvardijo visus 3 užsakymus, pakeitė B užsakymo sumą ir ištrynė A užsakymą, visais atvejais su 200. Anoniminis vartotojas taip pat išvardijo visus 3. Jei registracija atvira, ši taisyklė reiškia „visi, kas nepatingi užsiregistruoti“. Firebase dokumentacija ją irgi laiko įprastu nesaugiu šablonu.

Kodėl savininko patikrai reikia ir resource, ir request.resource?

resource yra dokumentas, koks jis saugomas. request.resource yra dokumentas, koks jis taptų po rašymo. Taisyklė, žiūrinti tik į pirmąjį, tikrina, kam eilutė priklauso dabar, bet nieko nesako apie tai, kuo ją paverčia.

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

Skaitymas atrodė teisingai: A gavo 200 savo užsakymui ir 403 B užsakymui. Rašymas ne. A sukūrė naują užsakymą su ownerId, nustatytu į B, ir gavo 200. Tada A pakeitė savo užsakymo ownerId į B, taip pat 200, ir nuo to laiko B galėjo jį skaityti. Programoje, kur užsakymai reiškia sąskaitas ar likučius, tai yra vartotojas, rašantis į svetimą paskyrą.

Ši versija atmetė viską:

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;
}
A užklausa Rezultatas
Skaityti savo užsakymą 200
Skaityti, keisti, trinti B užsakymą 403
Sukurti užsakymą, priklausantį B 403
Pakeisti ownerId į B 403

Vis tiek A galėjo pakeisti total savo užsakyme, su 200. Jei klientas šio lauko nustatinėti negali, nurodykite, kuriuos laukus jam leidžiama keisti:

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

Su ja total keitimas grąžino 403, o note keitimas grąžino 200.

Kodėl mano užklausa nepavyko su teisinga taisykle?

Nes taisyklės nėra filtrai. Pagal aukščiau pateiktą savininko taisyklę A, paprašęs visos kolekcijos, gavo 403, nors A priklauso 2 iš 3 užsakymų. Firestore vertina užklausą pagal tai, ką ji galėtų grąžinti, o ne pagal tai, kas yra.

A užklausa Rezultatas
Išvardyti visus užsakymus 403
Užklausa ownerId == A 200, 2 dok.
Užklausa ownerId == B 403

Taigi, kai sąrašas suluošėja sugriežtinus taisykles, taisykite užklausą. Taisyklės atlaisvinimas, kad sąrašas veiktų, yra būtent tas būdas, kuriuo parašomos aukščiau aprašytos plačios taisyklės.

Ar platus match gali panaikinti teisingą taisyklę?

Taip, ir to aš pirmiausia ieškočiau projekte su ilgu taisyklių failu. Firestore leidžia užklausą, jei ją leidžia bet kuri atitinkanti taisyklė.

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

Pirmasis blokas atrodo kaip gera savininko taisyklė. Esant antrajam blokui A perskaitė B užsakymą su 200, pašalinis išvardijo visus 3 užsakymus, o tas pats pašalinis perskaitė A dokumentą users. Pirmajame bloke nėra nieko, kas perspėtų. Ištrinkite platųjį match; vėlesne taisykle prieigos atimti neįmanoma.

Kaip vartotojas pats save padaro administratoriumi?

Šis šablonas atsiranda, kai tik rolės laikomos dokumente:

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();
}

„Vartotojai gali redaguoti savo profilį“ ir „administratoriai gali skaityti visus užsakymus“ po atskirai yra pagrįsta. Kartu tai yra teisių eskalavimas.

Administratorius per vieną užklausą. Vartotojas A, kurio paties users dokumentas įrašomas. Prieš: Vartotojas A → skaito B užsakymą → 403; Rolės įrašymas: Vartotojas A → role: admin → 200; Po: Vartotojas A → skaito B užsakymą → 200.
1 pav. Mano testas Firebase emuliatoriuje (CLI 15.34.2), 2026 m. lapkričio 3 d.

Pataisymas: neleisti klientui rašyti to lauko. Pridėjus request.resource.data.role == resource.data.role prie rašymo taisyklės, ta pati užklausa grąžino 403, o A liko už B užsakymo ribų. Kitas būdas yra custom claims, nustatomi iš serverio, nes klientas jų pakeisti negali.

Du dalykai, kurie pasirodė gerai

Tėvinio dokumento taisyklės neprasisunkia į subkolekcijas. Su allow read ant /orders/{id} bet kuriam prisijungusiam vartotojui A perskaitė užsakymą, o /orders/b1/notes/n1 po juo grąžino 403. Tai dokumentuotas elgesys: taisyklės taikomos tik atitikusiam keliui.

Svečias neprasmunka per palyginimą su trūkstamu tokenu. resource.data.ownerId == request.auth.uid svečiui grąžino 403 net be atskiro request.auth != null. Vis tiek šią patikrą užrašau, nes tada taisyklė sako tai, ką turi omenyje.

Kaip patikrinti savo taisykles?

Vykdykite savo užklausas emuliatoriuje kaip svečias, kaip pašalinis ir kaip antras vartotojas. Būtent taip išaiškėjo kiekvienas aukščiau aprašytas atvejis; skaitant taisykles jų nepastebėjau.

Pirmam praėjimui nemokamas Firebase taisyklių patikra skaito įklijuotas taisykles ir neliečia jūsų projekto. Čia pateiktuose rinkiniuose jis pažymėjo testavimo režimą, prieigą tik prisijungusiems, platųjį match ir pačių įrašomą rolę. Jis skaito tik tekstą, todėl negali pasakyti, kaip atrodo jūsų duomenys ar ar taisyklė buvo įdiegta.

Jūsų apiKey puslapyje pats savaime nėra problema. Firebase web konfigūracija pagal paskirtį yra vieša, o nemokamas Paslapčių skeneris ją taip ir pažymi, nes duomenis už jos saugo taisyklės. Failams galioja kitos taisyklės, su nutekėjimu, kurio taisyklės sustabdyti negali, ir tai išbandžiau straipsnyje Firebase Storage rules.

Apribojimai. Tik Firestore, vietiniame emuliatoriuje, per REST, su išgalvotais duomenimis. Realtime Database naudoja kitą taisyklių kalbą ir netestuota. App Check, ribojantis, kurios programos gali kreiptis į jūsų backend, čia neįtrauktas; jis taisyklių nepakeičia. Gamyboje detalės gali skirtis nuo emuliatoriaus, ir to netikrinau.

Nesate tikri, ką jūsų taisyklės praleidžia?

Mielai perskaitysiu jas kartu su jumis. Be pardavimų kalbų.

Susisiekti

© 2026 Denys Zaichenko. Originalus straipsnis: https://madsalt.tech/lt/blog/firebase-security-rules-examples/