管理及部署 Firebase 安全性規則

Firebase 提供多項工具,可協助您管理Security Rules,每項工具都適用於特定情況,且都使用相同的後端 Firebase Security Rules Management API。

無論使用哪種工具叫用,Management API 都會:

  • 擷取規則來源:一組規則,通常是包含 Firebase Security Rules 陳述式的程式碼檔案。
  • 將擷取的來源儲存為不可變更的規則集。
  • 追蹤版本中每個規則集的部署作業。啟用 Firebase 安全性規則的服務會查詢專案版本,評估每個安全資源要求。
  • 提供執行規則集語法和語意測試的功能。

使用 Firebase CLI

您可以使用 Firebase CLI 上傳本機來源並部署版本。CLI 的 Firebase Local Emulator Suite 可讓您對來源執行完整的本機測試。

使用 CLI 可讓您透過應用程式程式碼控管規則版本,並在現有部署程序中部署規則。

產生設定檔

使用 Firebase CLI 設定 Firebase 專案時,您會在專案目錄中建立 .rules 設定檔。使用下列指令開始設定 Firebase 專案:

Cloud Firestore

// Set up Firestore in your project directory, creates a .rules file
firebase init firestore

Realtime Database

// Set up Realtime Database in your project directory, creates a .rules file
firebase init database

Cloud Storage

// Set up Storage in your project directory, creates a .rules file
firebase init storage

編輯及更新規則

直接在 .rules 設定檔中編輯規則來源。

請確認您在 Firebase CLI 中所做的任何編輯都會反映在 Firebase 控制台中,或者您一律使用 Firebase 控制台或 Firebase CLI 進行更新。否則,您可能會覆寫在 Firebase 控制台中所做的任何更新。

測試更新

Local Emulator Suite 為所有啟用安全性規則的產品提供模擬器。每個模擬器的安全性規則引擎都會對規則進行語法和語意評估,因此超越安全性規則 Management API 提供的語法測試。

如果您使用 CLI,這個套件是Firebase Security Rules測試的絕佳工具。使用 Local Emulator Suite 在本機測試更新,並確認應用程式的 Security Rules 展現您想要的行為。

部署更新

更新並測試 Security Rules 後,請將來源部署至正式環境。

如果是 Cloud Firestore Security Rules,請查看並更新 firebase.json 檔案,將 .rules 檔案與預設和額外的具名資料庫建立關聯。

使用下列指令,選擇單獨部署 Security Rules,或在一般部署程序中部署。

Cloud Firestore

// Deploy rules for all databases configured in your firebase.json
firebase deploy --only firestore:rules
// Deploy rules for the specified database configured in your firebase.json firebase deploy --only firestore:<databaseId>

Realtime Database

// Deploy your .rules file
firebase deploy --only database

Cloud Storage

// Deploy your .rules file
firebase deploy --only storage

使用 Firebase 控制台

您也可以在 Firebase 控制台中編輯 Security Rules 來源,並部署為版本。在 Firebase 控制台 UI 中編輯時,系統會執行語法測試,而語意測試則可透過 Security Rules Playground 進行。

編輯及更新規則

  1. 開啟 Firebase 控制台,然後選取專案。
  2. 接著,在產品導覽中選取 Realtime Database、Cloud Firestore 或「Storage」,然後按一下「Rules」,前往 Security Rules 編輯器。
  3. 直接在編輯器中編輯規則。

測試更新

除了在編輯器 UI 中測試語法,您也可以使用專案的資料庫和儲存空間資源,直接在 Firebase 控制台中使用 Security Rules Playground 測試語意 Security Rules 行為。在 Security Rules 編輯器中開啟「Rules Playground」畫面,修改設定並點選「Run」。編輯器頂端會顯示確認訊息。

部署更新

確認更新內容符合預期後,按一下「發布」。

使用 Admin SDK

您可以使用 Node.js 的 Admin SDK 規則集。透過程式輔助存取權,您可以:

  • 導入自訂工具、指令碼、資訊主頁和 CI/CD 管道,以便管理規則。
  • 更輕鬆地管理多個 Firebase 專案的規則。

以程式輔助方式更新規則時,請務必避免對應用程式的存取控管進行非預期的變更。編寫 Admin SDK 程式碼時,請務必以安全性為優先考量,尤其是在更新或部署規則時。

另一項重點是,Firebase Security Rules 版本需要幾分鐘的時間才能完全發布。使用 Admin SDK 部署規則時,請務必避免競爭狀況,即應用程式立即依賴尚未完成部署的規則。如果您的用途需要頻繁更新存取控管規則,請考慮使用 Cloud Firestore 解決方案,這項解決方案旨在減少因頻繁更新而產生的競爭狀況。

此外,也請注意下列限制:

  • 規則序列化後,大小不得超過 256 KiB 的 UTF-8 編碼文字。
  • 一項專案最多可部署 2,500 個規則集。達到上限後,您必須刪除部分舊規則集,才能建立新規則集。

建立及部署 Cloud Storage 或 Cloud Firestore 規則集

使用 Admin SDK 管理安全性規則的一般工作流程可能包含三個獨立步驟:

  1. 建立規則檔案來源 (選用)
  2. 建立規則集
  3. 發布或部署新的規則集

SDK 提供一種方法,可將這些步驟合併為 Cloud Storage 和 Cloud Firestore 安全性規則的單一 API 呼叫。例如:

    const source = `service cloud.firestore {
      match /databases/{database}/documents {
        match /carts/{cartID} {
          allow create: if request.auth != null && request.auth.uid == request.resource.data.ownerUID;
          allow read, update, delete: if request.auth != null && request.auth.uid == resource.data.ownerUID;
        }
      }
    }`;
    // Alternatively, load rules from a file
    // const fs = require('fs');
    // const source = fs.readFileSync('path/to/firestore.rules', 'utf8');

    await admin.securityRules().releaseFirestoreRulesetFromSource(source);

這個模式也適用於 releaseFirestoreRulesetFromSource() 的 Cloud Storage 規則。

或者,您也可以將規則檔案建立為記憶體內物件、建立規則集,並個別部署規則集,以便更精確地控管這些事件。例如:

    const rf = admin.securityRules().createRulesFileFromSource('firestore.rules', source);
    const rs = await admin.securityRules().createRuleset(rf);
    await admin.securityRules().releaseFirestoreRuleset(rs);

更新 Realtime Database 規則集

如要使用 Admin SDK 更新 Realtime Database 規則集,請使用 admin.database 的 getRules() 和 setRules() 方法。您可以擷取 JSON 格式的規則集,或擷取包含註解的字串。

如要更新規則集,請按照下列步驟操作:

    const source = `{
      "rules": {
        "scores": {
          ".indexOn": "score",
          "$uid": {
            ".read": "$uid == auth.uid",
            ".write": "$uid == auth.uid"
          }
        }
      }
    }`;
    await admin.database().setRules(source);

管理規則集

為協助管理大型規則集,Admin SDK 可讓您使用 admin.securityRules().listRulesetMetadata 列出所有現有規則。例如:

    const allRulesets = [];
    let pageToken = null;
    while (true) {
      const result = await admin.securityRules().listRulesetMetadata(pageToken: pageToken);
      allRulesets.push(...result.rulesets);
      pageToken = result.nextPageToken;
      if (!pageToken) {
        break;
      }
    }

如果部署規模非常大,且規則集數量最終達到 2, 500 個上限,您可以建立邏輯,在固定時間週期內刪除最舊的規則。舉例來說,如要刪除部署超過 30 天的「所有」規則集,請執行下列指令:

    const thirtyDays = new Date(Date.now() - THIRTY_DAYS_IN_MILLIS);
    const promises = [];
    allRulesets.forEach((rs) => {
      if (new Date(rs.createTime) < thirtyDays) {
        promises.push(admin.securityRules().deleteRuleset(rs.name));
      }
    });
    await Promise.all(promises);
    console.log(`Deleted ${promises.length} rulesets.`);

使用 REST API。

上述工具非常適合各種工作流程,包括管理專案中多個 Cloud Firestore 資料庫的 Firebase Security Rules,但您可能想使用 Management API 本身來管理及部署 Firebase Security Rules。Management API 提供最大的彈性。

規則管理 REST API 參考文件。

此外,也請注意下列限制:

  • 規則序列化後,大小不得超過 256 KiB 的 UTF-8 編碼文字。
  • 一項專案最多可部署 2,500 個規則集。達到上限後,您必須刪除部分舊規則集,才能建立新規則集。

使用 REST 建立及部署 Cloud Firestore 或 Cloud Storage 規則集

本節範例使用 Firestore Security Rules,但也適用於 Cloud Storage Security Rules。

範例也會使用 cURL 呼叫 API。設定及傳遞驗證權杖的步驟已省略。您可以使用與參考文件整合的 API Explorer 測試這個 API。

使用 Management API 建立及部署規則集的一般步驟如下:

  1. 建立規則檔案來源
  2. 建立規則集
  3. 發布 (部署) 新規則集。

建立來源

假設您正在處理 secure_commerce Firebase 專案,並想將鎖定的 Cloud Firestore Security Rules 部署至專案中名為 east_store 的資料庫。

您可以在 firestore.rules 檔案中實作這些規則。

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if false;
    }
  }
}

建立規則集

現在,請為這個檔案產生 Base64 編碼指紋。接著,您可以使用這個檔案中的來源,填入建立規則集所需的酬載,並使用 projects.rulesets.create REST 呼叫。請使用 cat 指令,將 firestore.rules 的內容插入 REST 酬載。

如要追蹤,請將 attachment_point 設為 east_store,以便與 east_store 資料庫建立關聯。

curl -X POST -d '{
  "source": {
    "files": [
      {
        "content": "' $(cat storage.rules) '",
        "name": "firestore.rules",
        "fingerprint": <sha fingerprint>
      },
    "attachment_point": "firestore.googleapis.com/databases/east_store"
    ]
  }
}' 'https://firebaserules.googleapis.com/v1/projects/secure_commerce/rulesets'

API 會傳回驗證回應和規則集名稱,例如 projects/secure_commerce/rulesets/uuid123。

發布 (部署) 規則集

如果規則集有效,最後一個步驟是在具名版本中部署新的規則集。

curl -X POST -d '{
  "name": "projects/secure_commerce/releases/cloud.firestore/east_store"  ,
  "rulesetName": "projects/secure_commerce/rulesets/uuid123"
}' 'https://firebaserules.googleapis.com/v1/projects/secure_commerce/releases'

請注意,Firebase Security Rules 版本需要幾分鐘的時間才能完全傳播。使用管理 REST API 部署時,請務必避免競爭狀況,也就是應用程式立即依賴尚未完成部署的規則。

使用 REST 更新 Realtime Database 規則集

Realtime Database 提供專屬的 REST 介面,用於管理 Security Rules。請參閱「透過 REST 管理 Firebase Realtime Database Security Rules」。

使用 REST 管理規則集

除了建立規則集和版本的 REST 方法外,Management API 還提供下列方法,協助您管理大型規則部署作業:

  • 列出、取得及刪除規則集
  • 列出、取得及刪除規則版本

如果部署規模非常大,且規則集數量最終達到 2, 500 個上限,您可以建立邏輯,在固定時間週期內刪除最舊的規則。舉例來說,如要刪除部署超過 30 天的「所有」規則集,您可以呼叫 projects.rulesets.list 方法,剖析 Ruleset 物件的 JSON 清單中的 createTime 鍵,然後透過 ruleset_id 對對應的規則集呼叫 project.rulesets.delete。

使用 REST 測試更新

最後,Management API 可讓您對正式版專案中的 Cloud Firestore 和 Cloud Storage 資源執行語法和語意測試。

使用這個 API 元件進行測試時,包含下列步驟:

  1. 定義 TestSuite JSON 物件,代表一組 TestCase 物件
  2. 提交TestSuite
  3. 剖析傳回 TestResult 個物件

我們在 testcase.json 檔案中定義一個包含單一 TestCase 的 TestSuite 物件。在這個範例中,我們將 Security Rules 語言來源與 REST 酬載內嵌傳遞,並將測試套件傳遞至這些規則。我們會指定規則評估預期,以及要測試規則集的用戶端要求。您也可以指定測試報告的完整程度,使用「FULL」值表示報告應包含所有 Security Rules 語言運算式的結果,包括與要求不相符的運算式。

 {
  "source":
  {
    "files":
    [
      {
        "name": "firestore.rules",
        "content": "service cloud.firestore {
          match /databases/{database}/documents {
            match /users/{userId}{
              allow read: if (request.auth.uid == userId);
            }
            function doc(subpath) {
              return get(/databases/$(database)/documents/$(subpath)).data;
            }
            function isAccountOwner(accountId) {
              return request.auth.uid == accountId 
                  || doc(/users/$(request.auth.uid)).accountId == accountId;
            }
            match /licenses/{accountId} {
              allow read: if isAccountOwner(accountId);
            }
          }
        }"
      }
    ]
  },
  "testSuite":
  {
    "testCases":
    [
      {
        "expectation": "ALLOW",
        "request": {
           "auth": {"uid": "123"},
           "path": "/databases/(default)/documents/licenses/abcd",
           "method": "get"},
        "functionMocks": [
            {
            "function": "get",
            "args": [{"exact_value": "/databases/(default)/documents/users/123"}],
            "result": {"value": {"data": {"accountId": "abcd"}}}
            }
          ]
      }
    ]
  }
}

接著,我們可以使用 projects.test 方法提交這個 TestSuite 進行評估。

curl -X POST -d '{
    ' $(cat testcase.json) '
}' 'https://firebaserules.googleapis.com/v1/projects/secure_commerce/rulesets/uuid123:test'

傳回的 TestReport (包含測試成功/失敗狀態、偵錯訊息清單、造訪過的規則運算式清單及其評估報告) 會確認狀態為「成功」,表示已正確允許存取。

管理跨服務 Cloud Storage Security Rules 的權限

如果您建立 Cloud Storage Security Rules,並使用Cloud Firestore文件內容評估安全性條件,Firebase控制台或Firebase CLI 會提示您啟用權限,連結這兩項產品。

如果您決定停用這類跨服務安全性:

  1. 首先,在停用這項功能之前,請先編輯規則,移除所有使用 Security Rules 函式存取 Cloud Firestore 的陳述式。否則,停用這項功能後,Security Rules 評估作業會導致 Storage 要求失敗。

  2. 在 Google Cloud 控制台的「IAM」頁面中,按照撤銷角色的 Cloud 指南,刪除「Firebase Rules Firestore 服務代理」角色。

下次透過 Firebase CLI 或 Firebase 控制台儲存跨服務規則時,系統會提示您重新啟用這項功能。