安全性規則的運作方式

安全性可能是應用程式開發中最複雜的部分, 在大部分應用程式中,開發人員必須建構並執行 會處理驗證 (使用者的身分) 和授權 (使用者可執行的操作)。

Firebase Security Rules 移除中間 (伺服器) 層,並允許您為直接連結資料的用戶端指定路徑式權限。請參閱本指南,進一步瞭解如何將規則套用至傳入要求。

選取產品即可進一步瞭解相關規則。

Cloud Firestore

基本結構

Cloud FirestoreCloud Storage 中的 Firebase Security Rules 採用以下結構和 語法:

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

建立規則時,請務必瞭解以下重要概念:

  • 要求:allow 陳述式中叫用的方法或方法。這些 您允許執行的方法標準方法包括:getlistcreateupdatedeletereadwrite 便利方法 對指定的資料庫或儲存空間路徑啟用廣泛的讀寫存取權。
  • 路徑:資料庫或儲存空間位置,以 URI 路徑。
  • 規則:allow 陳述式,其中包含允許 傳回的結果。

安全性規則第 2 版

自 2019 年 5 月起,Firebase 安全性規則的 2 版現已推出。規則第 2 版會變更遞迴萬用字元 {name=**} 的行為。如果您打算使用第 2 版 使用集合群組查詢。您必須選擇加入 版本 2,確保安全性的第一行 rules_version = '2'; 規則:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {

比對路徑

所有比對陳述式都應指向文件,而非珍藏集。配對 陳述式可以指向特定文件 (例如 match /cities/SF),或使用萬用字元 指向指定路徑中的任何文件,如 match /cities/{city} 中所示。

在上述範例中,比對陳述式使用 {city} 萬用字元語法。 也就是說,這項規則適用於 cities 集合中的任何文件,例如 /cities/SF/cities/NYC。當比對陳述式中的 allow 運算式出現 city 變數會解析為城市文件名稱。 例如 SFNYC

相符的子集合

Cloud Firestore 中的資料會按照文件集合整理,而 文件可能會透過子集合擴充階層。請務必 瞭解安全性規則與階層資料的互動方式。

假設 cities 集合中的每份文件都包含 landmarks 個子集合。安全性規則只會套用到相符的路徑,因此 cities 集合中定義的存取權控管設定不適用於 landmarks 個子集合。請改為編寫明確規則來控管存取權 子集合:

service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      allow read, write: if <condition>;

      // Explicitly define rules for the 'landmarks' subcollection
      match /landmarks/{landmark} {
        allow read, write: if <condition>;
      }
    }
  }
}

建立 match 陳述式的巢狀結構時,內部 match 陳述式的路徑一律為 相對於外部 match 陳述式的路徑。因此,下列規則集的作用相同:

service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      match /landmarks/{landmark} {
        allow read, write: if <condition>;
      }
    }
  }
}
service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city}/landmarks/{landmark} {
      allow read, write: if <condition>;
    }
  }
}

遞迴萬用字元

如要將規則套用至任意深層階層,請使用 遞迴萬用字元語法 {name=**}

service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the cities collection as well as any document
    // in a subcollection.
    match /cities/{document=**} {
      allow read, write: if <condition>;
    }
  }
}

使用遞迴萬用字元語法時,萬用字元變數會包含整個相符的路徑片段,即使文件位於深層巢狀子集內也一樣。例如,上述規則 位於 /cities/SF/landmarks/coit_tower 的文件,以及 document 變數為 SF/landmarks/coit_tower

不過請注意,遞迴萬用字元的行為取決於規則版本。

版本 1

根據預設,安全性規則會使用第 1 版。在第 1 版中,遞迴萬用字元 比對一或多個路徑項目它們與空白路徑不相符 match /cities/{city}/{document=**} 與子集合中的文件相符,但 不在 cities 集合中,但與 match /cities/{document=**} 相符 cities 集合和子集合中的文件。

遞迴萬用字元必須放在比對陳述式的結尾。

版本 2

在第 2 版的安全性規則中,遞迴萬用字元符合零或多個路徑 項目。match/cities/{city}/{document=**} 與任一份文件相符 子集合和 cities 集合中的文件。

您必須在頂端新增 rules_version = '2';,才能採用第 2 版 安全性規則:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the cities collection as well as any document
    // in a subcollection.
    match /cities/{city}/{document=**} {
      allow read, write: if <condition>;
    }
  }
}

每個比對陳述式最多只能有一個遞迴萬用字元,但在版本中則 2,您可以將這個萬用字元放在比對陳述式中的任何位置。例如:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the songs collection group
    match /{path=**}/songs/{song} {
      allow read, write: if <condition>;
    }
  }
}

如果您使用集合群組查詢,則必須使用第 2 版,請參閱保護集合群組查詢

重疊的比對聲明

文件可能會比對多個 match 陳述式。在 如果有多個 allow 運算式符合同一個要求,則允許存取 如果「任一」條件為 true

service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the 'cities' collection.
    match /cities/{city} {
      allow read, write: if false;
    }

    // Matches any document in the 'cities' collection or subcollections.
    match /cities/{document=**} {
      allow read, write: if true;
    }
  }
}

在上述範例中,對於 cities 集合的所有讀取和寫入作業都將 但第二項規則一律為 true,但第 1 項 則一律為 false

安全性規則限制

處理安全性規則時,請注意以下限制:

限制 說明
每項要求的 exists()get()getAfter() 呼叫數量上限
  • 單一文件要求和查詢要求的上限為 10 項。
  • 多文件讀取作業、交易和批次寫入作業的上限為 20 項。上述限制 (10 項呼叫) 同樣適用於各項作業。

    舉例來說,假設您建立的批次寫入要求含有 3 項寫入作業,而您的安全性規則會使用 2 項文件存取呼叫來驗證各項寫入作業。此時,各項寫入作業會使用 2 項存取呼叫 (上限為 10 項),批次寫入要求則會使用 6 項存取呼叫 (上限為 20 項)。

超過任一項限制都會引發權限遭拒的錯誤。

系統可能會快取部分的文件存取呼叫,已快取的呼叫不會計入限制中。

巢狀 match 陳述式深度上限 10
一組巢狀 match 陳述式中允許的路徑長度上限 (以路徑區段為單位) 100
一組巢狀 match 陳述式中允許的路徑擷取變數數量上限 20
函式呼叫深度上限 20
函式引數數量上限 7
每個函式的 let 變數繫結上限 10
遞迴或循環函式呼叫的數量上限 0 (不允許)
每個要求中經評估的運算式數量上限 1,000 個
規則集的大小上限 規則集必須遵守以下兩項大小限制:
  • 如果使用 firebase deployFirebase 主控台或 CLI 發布規則集文字來源,大小限制為 256 KB。
  • 針對結果產生的已編譯規則集大小,限制為 250 KB Firebase 處理來源並在 後端。

Cloud Storage

基本結構

Cloud FirestoreCloud Storage 中的 Firebase Security Rules 採用以下結構和 語法:

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

建立規則時,請務必瞭解以下重要概念:

  • 要求:allow 陳述式中叫用的方法或方法。這些 您允許執行的方法標準方法包括:getlistcreateupdatedeletereadwrite 便利方法 對指定的資料庫或儲存空間路徑啟用廣泛的讀寫存取權。
  • 路徑:資料庫或儲存空間位置,以 URI 路徑。
  • 規則:allow 陳述式,其中包含允許 傳回的結果。

比對路徑

Cloud Storage Security Rules match存取用來存取檔案的檔案路徑 Cloud Storage。規則可以match確切路徑或萬用字元路徑,以及 也可以建立巢狀結構如果沒有比對規則允許要求方法,或 條件評估為 false,系統就會拒絕要求。

完全相符的結果

// Exact match for "images/profilePhoto.png"
match /images/profilePhoto.png {
  allow write: if <condition>;
}

// Exact match for "images/croppedProfilePhoto.png"
match /images/croppedProfilePhoto.png {
  allow write: if <other_condition>;
}

巢狀比對

// Partial match for files that start with "images"
match /images {
  // Exact match for "images/profilePhoto.png"
  match /profilePhoto.png {
    allow write: if <condition>;
  }

  // Exact match for "images/croppedProfilePhoto.png"
  match /croppedProfilePhoto.png {
    allow write: if <other_condition>;
  }
}

萬用字元比對

規則也可以使用萬用字元來 match 模式。萬用字元是指名變數,可代表單一字串 (例如 profilePhoto.png) 或多個路徑片段 (例如 images/profilePhoto.png)。

萬用字元是指在萬用字元名稱周圍加上大括號,例如 {string}。如要宣告多個片段萬用字元,請在=** 萬用字元名稱,例如 {path=**}

// Partial match for files that start with "images"
match /images {
  // Exact match for "images/*"
  // e.g. images/profilePhoto.png is matched
  match /{imageId} {
    // This rule only matches a single path segment (*)
    // imageId is a string that contains the specific segment matched
    allow read: if <condition>;
  }

  // Exact match for "images/**"
  // e.g. images/users/user:12345/profilePhoto.png is matched
  // images/profilePhoto.png is also matched!
  match /{allImages=**} {
    // This rule matches one or more path segments (**)
    // allImages is a path that contains all segments matched
    allow read: if <other_condition>;
  }
}

如果有多個規則與檔案相符,結果就是所有規則評估結果的 OR。也就是說,如果檔案符合的任何規則評估為 true, 結果是 true

在上述規則中,檔案「images/profilePhoto.png」就能讀取 conditionother_condition 的值為 true,而檔案 「images/users/user:12345/profilePhoto.png」只有在結果為 other_condition

您可以在 match 提供檔案中參照萬用字元變數 名稱或路徑授權:

// Another way to restrict the name of a file
match /images/{imageId} {
  allow read: if imageId == "profilePhoto.png";
}

Cloud Storage Security Rules 不會層疊,且只有在要求路徑與指定規則的路徑相符時,系統才會評估規則。

要求評估

上傳、下載、中繼資料變更和刪除等作業, request已匯款給 Cloud Storagerequest 變數包含執行要求的檔案路徑、收到要求的時間,以及要求為寫入作業時的新 resource 值。HTTP 標頭 以及驗證狀態

request 物件也會包含使用者的專屬 ID,以及 request.auth 物件中的 Firebase Authentication 酬載, 如要進一步瞭解,請參閱驗證 一節。

以下是 request 物件中的完整屬性清單:

屬性 類型 說明
auth map<string, string> 使用者登入時,請提供 uid、使用者的專屬 ID,以及 tokenFirebase Authentication JWT 憑證附加資訊的對應。否則, null
params map<string, string> 包含要求查詢參數的地圖。
path 路徑 path 代表要求執行的路徑。
resource map<string, string> 新資源值,只會顯示在 write 要求中。
time 時間戳記 代表要求評估要求的伺服器時間的時間戳記。

資源評估

評估規則時,建議您評估檔案的中繼資料 上傳、下載、修改或刪除這可讓您 複雜且功能強大的規則,例如僅允許符合特定條件的檔案 要上傳的內容類型,或只上傳大於特定大小的檔案 已刪除。

Cloud StorageFirebase Security Rules 提供 resource 中的檔案中繼資料 物件,其中包含出現在 Cloud Storage 物件。如要查看這些屬性,請前往 read 或 用於確保資料完整性的 write 要求。

write 要求 (例如上傳、中繼資料更新和刪除) 中,除了 resource 物件 (包含目前位於要求路徑中的檔案中繼資料) 之外,您還可以使用 request.resource 物件,該物件包含允許寫入的檔案中繼資料子集。您可以使用這兩個值來確保資料完整性,或強制應用程式限制 (例如檔案類型或大小)。

以下是 resource 物件中的完整屬性清單:

屬性 類型 說明
name 字串 物件的全名
bucket 字串 這個物件所在的值區名稱。
generation int 此物件的 Google Cloud Storage 物件世代
metageneration int Google Cloud Storage 此物件的物件中繼產生
size int 物件大小 (以位元組為單位)。
timeCreated 時間戳記 代表物件建立時間的時間戳記。
updated 時間戳記 代表物件上次更新時間的時間戳記。
md5Hash 字串 物件的 MD5 雜湊。
crc32c 字串 物件的 CRC32c 雜湊。
etag 字串 與這個物件相關聯的 ETag。
contentDisposition 字串 與此物件相關聯的內容配置。
contentEncoding 字串 與此物件相關聯的內容編碼。
contentLanguage 字串 與這個物件相關聯的內容語言。
contentType 字串 與此物件相關聯的內容類型。
metadata map<string, string> 開發人員指定的其他自訂中繼資料鍵/值組合。

request.resource 包含以上所有項目,但 generation 除外。 metagenerationetagtimeCreatedupdated

安全性規則限制

處理安全性規則時,請注意以下限制:

限制 詳細資料
最大 firestore.exists() 和 每次要求 firestore.get() 次呼叫

2 適用於單一文件要求和查詢要求。

超過此限制會產生權限遭拒錯誤。

系統可能會快取對相同文件的存取呼叫,並快取呼叫 不會計入用量限制

完整範例

總結來說,您可以建立完整的圖片規則範例 儲存空間解決方案:

service firebase.storage {
 match /b/{bucket}/o {
   match /images {
     // Cascade read to any image type at any path
     match /{allImages=**} {
       allow read;
     }

     // Allow write files to the path "images/*", subject to the constraints:
     // 1) File is less than 5MB
     // 2) Content type is an image
     // 3) Uploaded content type matches existing content type
     // 4) File name (stored in imageId wildcard variable) is less than 32 characters
     match /{imageId} {
       allow write: if request.resource.size < 5 * 1024 * 1024
                    && request.resource.contentType.matches('image/.*')
                    && request.resource.contentType == resource.contentType
                    && imageId.size() < 32
     }
   }
 }
}

Realtime Database

基本結構

Realtime Database 中,Firebase Security Rules 包含類似 JavaScript 的運算式,包含在 JSON 文件。

使用以下語法:

{
  "rules": {
    "<<path>>": {
    // Allow the request if the condition for each method is true.
      ".read": <<condition>>,
      ".write": <<condition>>,
      ".validate": <<condition>>
    }
  }
}

規則包含三個基本元素:

  • 路徑:資料庫位置。這會複製資料庫的 JSON 結構。
  • 要求:以下是規則用來授予存取權的方法。readwrite 規則會授予廣泛的讀取和寫入存取權,而 validate 規則則可做為次要驗證,根據傳入或現有資料授予存取權。
  • 條件:允許要求在評估為 true 時允許的條件。

規則套用到路徑的方式

Realtime Database 中,Rules 會以不可分割的形式套用,亦即位於 較高層級的父項節點會覆寫規則 更精細的子節點 較深節點的規則無法授予父項路徑的存取權。如果您已為其中一個父項路徑授予存取權,就無法在資料庫結構中更精確地指定或撤銷更深層路徑的存取權。

請參考下列規則:

{
  "rules": {
     "foo": {
        // allows read to /foo/*
        ".read": "data.child('baz').val() === true",
        "bar": {
          // ignored, since read was allowed already
          ".read": false
        }
     }
  }
}

這個安全性結構允許 /bar/ 讀取 /foo/ 包含具有 true 值的子項 baz/foo/bar/ 下方的 ".read": false 規則在此處沒有效果,因為子路徑無法撤銷存取權。

雖然您不一定要提供直覺易用的功能,但這項重要功能是 允許實施非常複雜的存取權限 以最省力的方式執行這對於使用者層級安全性特別實用。

不過,.validate 規則不會串聯。所有驗證規則 都必須滿足階層的所有層級要求,才能允許寫入。

此外,由於規則不會套用到父項路徑,因此讀取或寫入 作業失敗時,如果沒有指定位置或父項規則 授予存取權限的位置即使每個受影響的子項路徑都可以存取 導致無法完整讀取請考慮以下結構:

{
  "rules": {
    "records": {
      "rec1": {
        ".read": true
      },
      "rec2": {
        ".read": false
      }
    }
  }
}

如果不瞭解規則會以不可分割的形式進行評估 擷取 /records/ 路徑時,將傳回 rec1 但不含 rec2。不過,實際結果會是錯誤:

JavaScript
var db = firebase.database();
db.ref("records").once("value", function(snap) {
  // success method is not called
}, function(err) {
  // error callback triggered with PERMISSION_DENIED
});
Objective-C
注意:這項 Firebase 產品不適用於 App Clip 目標。
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[_ref child:@"records"] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  // success block is not called
} withCancelBlock:^(NSError * _Nonnull error) {
  // cancel block triggered with PERMISSION_DENIED
}];
Swift
注意:這項 Firebase 產品不適用於 App Clip 目標。
var ref = FIRDatabase.database().reference()
ref.child("records").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // success block is not called
}, withCancelBlock: { error in
    // cancel block triggered with PERMISSION_DENIED
})
Java
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("records");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    // success method is not called
  }

  @Override
  public void onCancelled(FirebaseError firebaseError) {
    // error callback triggered with PERMISSION_DENIED
  });
});
REST
curl https://docs-examples.firebaseio.com/rest/records/
# response returns a PERMISSION_DENIED error

由於 /records/ 的讀取作業不可部分完成,而且沒有讀取規則授予 /records/ 下所有資料的存取權,因此系統會擲回 PERMISSION_DENIED 錯誤。如果我們在 Firebase 控制台的安全性模擬工具中評估這項規則,就會發現讀取作業遭到拒絕:

Attempt to read /records with auth=Success(null)
    /
    /records

No .read rule allowed the operation.
Read was denied.

沒有任何讀取規則允許存取 /records/ 路徑,因此作業遭拒。請注意,系統並未評估 rec1 的規則,因為該規則不在我們要求的路徑中。如要擷取 rec1,我們必須直接存取:

JavaScript
var db = firebase.database();
db.ref("records/rec1").once("value", function(snap) {
  // SUCCESS!
}, function(err) {
  // error callback is not called
});
Objective-C
注意:這項 Firebase 產品不適用於 App Clip 目標。
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[ref child:@"records/rec1"] observeSingleEventOfType:FEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
    // SUCCESS!
}];
Swift
注意:這項 Firebase 產品不適用於 App Clip 目標。
var ref = FIRDatabase.database().reference()
ref.child("records/rec1").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // SUCCESS!
})
Java
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("records/rec1");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    // SUCCESS!
  }

  @Override
  public void onCancelled(FirebaseError firebaseError) {
    // error callback is not called
  }
});
REST
curl https://docs-examples.firebaseio.com/rest/records/rec1
# SUCCESS!

位置變數

Realtime Database Rules支援 $location 來比對路徑區隔在路徑前方使用 $ 前置字串 來比對規則和路徑上所有的子節點

  {
    "rules": {
      "rooms": {
        // This rule applies to any child of /rooms/, the key for each room id
        // is stored inside $room_id variable for reference
        "$room_id": {
          "topic": {
            // The room's topic can be changed if the room id has "public" in it
            ".write": "$room_id.contains('public')"
          }
        }
      }
    }
  }

您也可以使用 $variable 搭配常數路徑 。

  {
    "rules": {
      "widget": {
        // a widget can have a title or color attribute
        "title": { ".validate": true },
        "color": { ".validate": true },

        // but no other child paths are allowed
        // in this case, $other means any key excluding "title" and "color"
        "$other": { ".validate": false }
      }
    }
  }

除非另有註明,否則本頁面中的內容是採用創用 CC 姓名標示 4.0 授權,程式碼範例則為阿帕契 2.0 授權。詳情請參閱《Google Developers 網站政策》。Java 是 Oracle 和/或其關聯企業的註冊商標。

上次更新時間:2024-09-12 (世界標準時間)。