您可以參考本指南,瞭解 Firebase Security Rules 設定中的常見安全漏洞,並檢查及強化您自己的規則安全性,並在部署變更前進行測試。
如果您收到資料未妥善安全防護的警示,請檢查這些常見的錯誤,並更新任何有安全漏洞的規則。
存取 Firebase Security Rules
如要查看現有的 Rules,請使用 Firebase CLI 或 Firebase 主控台。請務必使用相同方法編輯規則,以免意外覆寫更新。如果您不確定在本機定義的規則是否反映最新更新,Firebase 控制台一律會顯示最近部署的 Firebase Security Rules 版本。
如要透過 Firebase 控制台存取規則,請選取專案,然後前往 Realtime Database、Cloud Firestore 或 Storage。進入正確的資料庫或儲存空間桶後,按一下「規則」。
如要透過 Firebase CLI 存取規則,請前往 firebase.json 檔案中註明的規則檔案。
瞭解 Firebase Security Rules
Firebase Security Rules 保護資料免受惡意使用者的侵擾。在 Firebase 控制台中建立資料庫執行個體或 Cloud Storage 值區時,您可以選擇拒絕所有使用者的存取權 (鎖定模式),或將存取權授予所有使用者 (測試模式)。雖然您可能會在開發期間採用較開放的設定,但請務必先花時間妥善設定規則,並確保資料安全無虞,再部署應用程式。
在開發應用程式並測試規則的不同設定時,請使用其中一個本機 Firebase 模擬器,在本機開發環境中執行應用程式。
常見的安全性偏低規則情境
您可能會預設設定 Rules,或是在最初開發應用程式時設定。在部署應用程式前,請先檢查並更新這些設定。請務必避免下列常見陷阱,確實保護使用者資料。
公開存取
設定 Firebase 專案時,您可能已將規則設為允許在開發期間公開存取。您可能會認為只有您在使用應用程式,但如果您已部署應用程式,那麼網路上就會提供該應用程式。如果您沒有驗證使用者身分,也沒有設定安全性規則,那麼任何猜測到專案 ID 的使用者都能竊取、修改或刪除資料。
不建議:為所有使用者提供讀取和寫入存取權。
Cloud Firestore
// Allow read/write access to all users under any conditions
// Warning: **NEVER** use this ruleset in production; it allows
// anyone to overwrite your entire database.
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}
Realtime Database
{
// Allow read/write access to all users under any conditions
// Warning: **NEVER** use this ruleset in production; it allows
// anyone to overwrite your entire database.
"rules": {
".read": true,
".write": true
}
}
Cloud Storage
// Anyone can read or write to the bucket, even non-users of your app.
// Because it is shared with App Engine, this will also make
// files uploaded via App Engine public.
// Warning: This rule makes every file in your Cloud Storage bucket accessible to any user.
// Apply caution before using it in production, since it means anyone
// can overwrite all your files.
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write;
}
}
}
|
解決方案:限制讀取及寫入存取權的規則。 建立適合資料階層的規則。解決這項安全性問題的常見方法之一,就是使用 Firebase Authentication 實施使用者層級安全性。進一步瞭解如何使用規則驗證使用者。
Cloud Firestore
僅限內容擁有者
service cloud.firestore {
match /databases/{database}/documents {
// Allow only authenticated content owners access
match /some_collection/{document} {
// Allow reads and deletion if the current user owns the existing document
allow read, delete: if request.auth.uid == resource.data.author_uid;
// Allow creation if the current user owns the new document
allow create: if request.auth.uid == request.resource.data.author_uid;
// Allow updates by the owner, and prevent change of ownership
allow update: if request.auth.uid == request.resource.data.author_uid
&& request.auth.uid == resource.data.author_uid;
}
}
}
混合式公開與私人存取
service cloud.firestore {
match /databases/{database}/documents {
// Allow public read access, but only content owners can write
match /some_collection/{document} {
// Allow public reads
allow read: if true
// Allow creation if the current user owns the new document
allow create: if request.auth.uid == request.resource.data.author_uid;
// Allow updates by the owner, and prevent change of ownership
allow update: if request.auth.uid == request.resource.data.author_uid
&& request.auth.uid == resource.data.author_uid;
// Allow deletion if the current user owns the existing document
allow delete: if request.auth.uid == resource.data.author_uid;
}
}
}
Realtime Database
僅限內容擁有者
{
"rules": {
"some_path": {
"$uid": {
// Allow only authenticated content owners access to their data
".read": "auth !== null && auth.uid === $uid",
".write": "auth !== null && auth.uid === $uid"
}
}
}
}
混合式公開與私人存取
{
// Allow anyone to read data, but only authenticated content owners can
// make changes to their data
"rules": {
"some_path/$uid": {
".read": true,
// or ".read": "auth.uid !== null" for only authenticated users
".write": "auth.uid === $uid"
}
}
}
Cloud Storage
僅限內容擁有者
// Grants a user access to a node matching their user ID
service firebase.storage {
match /b/{bucket}/o {
// Files look like: "user/<UID>/path/to/file.txt"
match /user/{userId}/{allPaths=**} {
allow read, write: if request.auth.uid == userId;
}
}
}
混合公開和私人存取權
service firebase.storage {
match /b/{bucket}/o {
// Files look like: "user/<UID>/path/to/file.txt"
match /user/{userId}/{allPaths=**} {
allow read;
allow write: if request.auth.uid == userId;
}
}
}
|
所有已驗證使用者的存取權
有時候,Rules 會檢查使用者已經登入,但不會根據該驗證進一步限制存取權。如果其中一個規則包含 auth != null
,請確認您要讓所有已登入的使用者都能存取資料。
不建議使用:任何登入的使用者都能讀取及寫入整個資料庫。
Cloud Firestore
service cloud.firestore {
match /databases/{database}/documents {
match /some_collection/{document} {
allow read, write: if request.auth.uid != null;
}
}
}
Realtime Database
{
"rules": {
".read": "auth.uid !== null",
".write": "auth.uid !== null"
}
}
Cloud Storage
// Only authenticated users can read or write to the bucket
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth != null;
}
}
}
|
解決方案:使用安全性條件限制存取權。 在檢查驗證時,您可能也想使用其中一個驗證屬性,進一步限制特定資料集的特定使用者存取權。進一步瞭解各種驗證屬性。
Cloud Firestore
角色型存取權
service cloud.firestore {
match /databases/{database}/documents {
// Assign roles to all users and refine access based on user roles
match /some_collection/{document} {
allow read: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == "Reader"
allow write: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == "Writer"
// Note: Checking for roles in your database using `get` (as in the code
// above) or `exists` carry standard charges for read operations.
}
}
}
以屬性為準的存取權
// Give each user in your database a particular attribute
// and set it to true/false
// Then, use that attribute to grant access to subsets of data
// For example, an "admin" attribute set
// to "true" grants write access to data
service cloud.firestore {
match /databases/{database}/documents {
match /collection/{document} {
allow write: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true;
allow read: true;
}
}
}
混合式公開與私人存取
service cloud.firestore {
match /databases/{database}/documents {
// Allow public read access, but only content owners can write
match /some_collection/{document} {
allow read: if true
allow write: if request.auth.uid == request.resource.data.author_uid
}
}
}
Realtime Database
僅限內容擁有者
{
"rules": {
"some_path": {
"$uid": {
// Allow only authenticated content owners access to their data
".read": "auth.uid === $uid",
".write": "auth.uid === $uid"
}
}
}
}
路徑分隔存取
{
"rules": {
"some_path/$uid": {
".write": "auth.uid === $uid",
// Create a "public" subpath in your dataset
"public": {
".read": true
// or ".read": "auth.uid !== null"
},
// Create a "private" subpath in your dataset
"private": {
".read": "auth.uid === $uid"
}
}
}
}
混合公開和私人存取權
{
// Allow anyone to read data, but only authenticated content owners can
// make changes to their data
"rules": {
"some_path/$uid": {
".read": true,
// or ".read": "auth.uid !== null" for only authenticated users
".write": "auth.uid === $uid"
}
}
}
Cloud Storage
群組存取權
// 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;
}
僅限內容擁有者
// Grants a user access to a node matching their user ID
service firebase.storage {
match /b/{bucket}/o {
// Files look like: "user/<UID>/path/to/file.txt"
match /user/{userId}/{allPaths=**} {
allow read, write: if request.auth.uid == userId;
}
}
}
混合公開和私人存取權
service firebase.storage {
match /b/{bucket}/o {
// Files look like: "user/<UID>/path/to/file.txt"
match /user/{userId}/{allPaths=**} {
allow read;
allow write: if request.auth.uid == userId;
}
}
}
|
(Realtime Database) 不正確繼承的規則
Realtime Database Security Rules 串聯,且規則是以最淺層、父項路徑覆寫更深的子節點規則。在子節點中編寫規則時,請記住,子節點只能授予額外權限。您無法在資料庫中更精確地指定資料的存取權,也無法撤銷資料的存取權。
不建議:在子路徑中精修規則{
"rules": {
"foo": {
// allows read to /foo/*
".read": "data.child('baz').val() === true",
"bar": {
/* ignored, since read was allowed already */
".read": false
}
}
}
}
|
封閉存取
在開發應用程式時,另一個常見做法是將資料鎖定。通常這表示您已關閉所有使用者的讀取和寫入權限,如下所示:
Cloud Firestore
// Deny read/write access to all users under any conditions
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
}
}
Realtime Database
{
"rules": {
".read": false,
".write": false
}
}
Cloud Storage
// Access to files through Cloud Storage is completely disallowed.
// Files may still be accessible through App Engine or Google Cloud Storage APIs.
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if false;
}
}
}
Firebase Admin SDK 和 Cloud Functions 仍可存取資料庫。如要將 Cloud Firestore 或 Realtime Database 做為僅限伺服器的後端,並搭配使用 Firebase Admin SDK,請使用這些規則。雖然這項做法安全無虞,但您仍應測試應用程式的用戶端是否能正確擷取資料。
如要進一步瞭解 Cloud Firestore Security Rules 和其運作方式,請參閱「開始使用 Cloud Firestore Security Rules」一文。
測試 Cloud Firestore Security Rules
如要檢查應用程式行為並驗證 Cloud Firestore Security Rules 設定,請使用 Firebase Emulator。在部署任何變更之前,請使用 Cloud Firestore 模擬器在本機環境中執行並自動化單元測試。
如要在 Firebase 主控台中快速驗證 Firebase Security Rules,請使用 Firebase 規則模擬器。