管理及部署 Firebase 安全性規則

Firebase 提供多種工具來管理 Rules,每個工具都適用於特定情況,且都使用相同的後端 Firebase 安全性規則管理 API。

無論使用哪個工具叫用管理 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 為所有支援安全性規則的產品提供模擬器。每個模擬器的安全性規則引擎會對規則執行語法和語意評估,因此超越了安全性規則管理 API 提供的語法測試。

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

部署更新

更新及測試 Rules 後,請將來源部署至實際環境。

針對 Cloud Firestore Security Rules,請查看並更新 firebase.json 檔案,將 .rules 檔案與預設和其他已命名的資料庫建立關聯。

請使用下列指令,選擇性地部署 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 控制台

您也可以編輯 Rules 來源,並透過 Firebase 控制台將其部署為「版本」。您在 Firebase 主控台 UI 中編輯時,系統會執行語法測試,並可使用 Rules Playground 進行語意測試。

編輯及更新規則

  1. 開啟 Firebase 控制台,然後選取所需專案。
  2. 接著,從產品導覽選單中選取 Realtime DatabaseCloud Firestore 或「儲存空間」,然後按一下「規則」,前往 Rules 編輯器。
  3. 直接在編輯器中編輯規則。

測試更新

除了在編輯器 UI 中測試語法之外,您也可以使用 Rules Playground,直接在 Firebase 主控台中使用專案的資料庫和儲存空間資源,測試語意 Rules 行為。在 Rules 編輯器中開啟「Rules Playground」畫面,修改設定,然後按一下「Run」。查看編輯器頂端是否有確認訊息。

部署更新

確認更新內容正確無誤後,請按一下「發布」

使用 Admin SDK

您可以使用 Admin SDK 為 Node.js rulesets。有了這項程式輔助存取權,您可以:

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

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

另外也請注意,Firebase Security Rules 版本需要幾分鐘才能全面生效。使用 Admin SDK 部署規則時,請務必避免競爭狀況,也就是應用程式立即依賴尚未完成部署的規則。如果您的用途需要經常更新存取控制規則,請考慮使用 Cloud Firestore 的解決方案,因為這項解決方案可在經常更新的情況下減少競爭狀況。

請注意下列限制:

  • 規則序列化時,必須小於 256 KiB (採用 UTF-8 編碼的文字)。
  • 一個專案最多可部署 2500 個規則集。達到這個上限後,您必須先刪除部分舊規則集,再建立新的規則集。

建立及部署 Cloud StorageCloud Firestore 規則集

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

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

SDK 提供一種方法,可將這些步驟結合為 Cloud StorageCloud 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);

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

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

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

如果部署規模龐大,且隨著時間推移而達到 2500 個規則集的上限,您可以建立邏輯,在固定的時間週期內刪除最舊的規則。舉例來說,如要刪除部署超過 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 管理,但您可能會想使用管理 API 本身來管理及部署 Firebase Security Rules。管理 API 可提供最大的彈性。

請注意下列限制:

  • 規則序列化時,必須小於 256 KiB (採用 UTF-8 編碼的文字)。
  • 一個專案最多可部署 2500 個規則集。達到此上限後,您必須先刪除一些舊規則集,才能建立新規則集。

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

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

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

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

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

建立來源

假設您正在處理 secure_commerce Firebase 專案,並想要將已鎖定的 Cloud Firestore 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 介面,用於管理 Rules。請參閱透過 REST 管理 Firebase Realtime Database Rules 的相關說明。

使用 REST 管理規則集

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

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

如果部署規模龐大,且隨著時間推移而達到 2500 個規則集的上限,您可以建立邏輯,在固定的時間週期內刪除最舊的規則。舉例來說,如要刪除部署超過 30 天的「all」規則集,您可以呼叫 projects.rulesets.list 方法,剖析 Ruleset 物件的 JSON 清單,並根據 createTime 鍵,對相應規則集呼叫 project.rulesets.deleteruleset_id

使用 REST 測試更新

最後,管理 API 可讓您在正式專案中對 Cloud FirestoreCloud Storage 資源執行語法和語意測試。

使用這個 API 元件進行測試,包括:

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

讓我們在 testcase.json 檔案中定義含有單一 TestCaseTestSuite 物件。在這個範例中,我們會將 Rules 語言來源與 REST 酬載一併傳遞,並搭配測試套件,以便根據這些規則執行。我們會指定規則評估預期值,以及要針對規則集進行測試的用戶端要求。您也可以使用「FULL」值指定測試報告的完整程度,表示報告應納入所有 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. 首先,請先停用這項功能,然後編輯規則,移除所有使用 Rules 函式存取 Cloud Firestore 的陳述式。否則,在停用這項功能後,Rules 評估作業會導致您的儲存空間要求失敗。

  2. 請按照Cloud 指南中撤銷角色的說明,使用 Google Cloud 控制台的「身分與存取權管理」頁面刪除「Firebase Rules Firestore Service Agent」角色。

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