ניהול ופריסה של כללי האבטחה ב-Firebase

ב-Firebase יש כמה כלים לניהול Security Rules, כל אחד מהם שימושי במקרים מסוימים וכולם משתמשים באותו ממשק API לניהול כללי האבטחה של Firebase בקצה העורפי.

לא משנה באיזה כלי משתמשים כדי להפעיל אותו, ה-Management API:

  • מקבל מקור של כללים: קבוצת כללים, בדרך כלל קובץ קוד שמכיל הצהרות Firebase Security Rules.
  • אחסון המקור שנטמע כקבוצת כללים שלא ניתנת לשינוי.
  • מעקב אחרי הפריסה של כל קבוצת כללים בגרסה. שירותים שמופעלים בהם כללי אבטחה של Firebase מחפשים את הגרסה של הפרויקט כדי להעריך כל בקשה למשאב מאובטח.
  • מאפשר להריץ בדיקות תחביריות וסמנטיות של קבוצת כללים.

שימוש ב-CLI של Firebase

באמצעות ה-CLI של Firebase, אתם יכולים להעלות מקורות מקומיים ולפרוס גרסאות. הפקודה Firebase Local Emulator Suite של ה-CLI מאפשרת לבצע בדיקה מקומית מלאה של מקורות.

באמצעות ה-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.

חשוב לוודא שכל השינויים שאתם מבצעים ב-CLI של Firebase משתקפים במסוף Firebase, או שאתם מבצעים עדכונים באופן עקבי באמצעות מסוף Firebase או Firebase CLI. אחרת, יכול להיות שתחליפו עדכונים שבוצעו במסוף Firebase.

בדיקת העדכונים

Local Emulator Suite מספק אמולטורים לכל המוצרים שבהם מופעלים כללי אבטחה. מנוע כללי האבטחה של כל אמולטור מבצע הערכה תחבירית וסמנטית של הכללים, ובכך חורג מהבדיקה התחבירית שמציע ה-API לניהול כללי האבטחה.

אם אתם עובדים עם ה-CLI, חבילת הכלים היא כלי מצוין לבדיקות Firebase Security Rules. משתמשים ב-Local Emulator Suite כדי לבדוק את העדכונים באופן מקומי ולוודא שה-Security Rules של האפליקציה פועלים כמו שרוצים.

פריסת העדכונים

אחרי שמעדכנים ובודקים את Security Rules, פורסים את המקורות בסביבת הייצור.

ב-Cloud Firestore Security Rules, משייכים קובצי .rules למסדי הנתונים שמוגדרים כברירת מחדל ולמסדי נתונים נוספים עם שמות, על ידי בדיקה ועדכון של הקובץ firebase.json.

משתמשים בפקודות הבאות כדי לפרוס באופן סלקטיבי את 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

אפשר גם לערוך מקורות של Security Rules ולפרוס אותם כגרסאות ממסוף Firebase. בדיקה תחבירית מתבצעת כשעורכים בממשק המשתמש של מסוף Firebase, ובדיקה סמנטית זמינה באמצעות מגרש המשחקים של Security Rules.

עריכה ועדכון של הכללים

  1. פותחים את מסוף Firebase ובוחרים את הפרויקט.
  2. אחר כך בוחרים באפשרות Realtime Database,‏ Cloud Firestore או Storage מתפריט הניווט של המוצר, ולוחצים על Rules כדי לעבור לעורך של Security Rules.
  3. עורכים את הכללים ישירות בכלי העריכה.

בדיקת העדכונים

בנוסף לבדיקת התחביר בממשק המשתמש של כלי העריכה, אתם יכולים לבדוק את ההתנהגות הסמנטית של Security Rules באמצעות מסד הנתונים ומשאבי האחסון של הפרויקט, ישירות במסוף Firebase באמצעות Security Rules Playground. פותחים את המסך Rules Playground בעורך של Security Rules, משנים את ההגדרות ולוחצים על Run. מחפשים את הודעת האישור בחלק העליון של כלי העריכה.

פריסת העדכונים

כשאתם מרוצים מהעדכונים, לחצו על פרסום.

שימוש ב-SDK לאדמינים

אפשר להשתמש בכללים של Admin SDK ל-Node.js. באמצעות הגישה הפרוגרמטית הזו, אתם יכולים:

  • להטמיע כלים, סקריפטים, לוחות בקרה וצינורות עיבוד נתונים של CI/CD בהתאמה אישית כדי לנהל את הכללים.
  • לנהל כללים בקלות רבה יותר בכמה פרויקטים ב-Firebase.

כשמעדכנים כללים באופן פרוגרמטי, חשוב מאוד להימנע משינויים לא מכוונים בבקרת הגישה לאפליקציה. כשכותבים קוד Admin SDK, צריך לשים דגש על אבטחה, במיוחד כשמעדכנים או פורסים כללים.

דבר חשוב נוסף שכדאי לזכור הוא שלוקח כמה דקות עד שגרסאות של Firebase Security Rules מופצות באופן מלא. כשמשתמשים ב-Admin SDK כדי לפרוס כללים, חשוב להימנע ממרוץ תהליכים שבו האפליקציה מסתמכת באופן מיידי על כללים שהפריסה שלהם עדיין לא הושלמה. אם אתם צריכים לעדכן לעיתים קרובות את כללי בקרת הגישה, כדאי להשתמש בפתרונות שמבוססים על Cloud Firestore, שנועד לצמצם את מרוץ התהליכים למרות העדכונים התכופים.

חשוב גם לשים לב למגבלות הבאות:

  • הכללים צריכים להיות קטנים מ-256KiB של טקסט בקידוד UTF-8 אחרי שעברו סריאליזציה.
  • בכל פרויקט אפשר לפרוס עד 2,500 קבוצות של כללים. אם תגיעו למגבלה הזו, תצטרכו למחוק כמה קבוצות כללים ישנות לפני שתוכלו ליצור קבוצות חדשות.

יצירה ופריסה של קבוצות כללים של Cloud Storage או Cloud Firestore

תהליך עבודה אופייני לניהול כללי אבטחה באמצעות Admin SDK יכול לכלול שלושה שלבים נפרדים:

  1. יצירת מקור קובץ כללים (אופציונלי)
  2. יצירת קבוצת כללים
  3. מפרסמים או פורסים את קבוצת הכללים החדשה.

ערכת ה-SDK מספקת שיטה לשילוב השלבים האלה בקריאה אחת ל-API עבור כללי האבטחה של Cloud Storage ו-Cloud Firestore. לדוגמה:

    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 קבוצות כללים

כדי לעדכן את קבוצות הכללים של Realtime Database באמצעות Admin SDK, משתמשים בשיטות getRules() ו-setRules() של admin.database. אפשר לאחזר קבוצות כללים בפורמט 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.`);

שימוש ב-API בארכיטקטורת REST

הכלים שמתוארים למעלה מתאימים מאוד לתהליכי עבודה שונים, כולל ניהול Firebase Security Rules של כמה מסדי נתונים של Cloud Firestore בפרויקט, אבל יכול להיות שתרצו לנהל ולפרוס את Firebase Security Rules באמצעות ה-Management API עצמו. ‫Management API מספק את הגמישות הגדולה ביותר.

חשוב גם לשים לב למגבלות הבאות:

  • הכללים צריכים להיות קטנים מ-256KiB של טקסט בקידוד UTF-8 אחרי שעברו סריאליזציה.
  • בכל פרויקט אפשר לפרוס עד 2,500 קבוצות של כללים. אם תגיעו למגבלה הזו, תצטרכו למחוק כמה קבוצות כללים ישנות לפני שתוכלו ליצור קבוצות חדשות.

יצירה ופריסה של קבוצות כללים של Cloud Firestore או Cloud Storage באמצעות REST

הדוגמאות בקטע הזה משתמשות ב-Firestore Security Rules, אבל הן רלוונטיות גם ל-Cloud Storage Security Rules.

בדוגמאות נעשה שימוש גם ב-cURL כדי לבצע קריאות ל-API. השלבים להגדרה ולהעברה של אסימוני אימות לא נכללים. אתם יכולים להתנסות ב-API הזה באמצעות API Explorer שמשולב במאמרי העזרה.

השלבים הטיפוסיים ליצירה ולפריסה של קבוצת כללים באמצעות Management API הם:

  1. יצירת מקורות של קובצי כללים
  2. יצירת קבוצת כללים
  3. מפרסמים (פורסים) את קבוצת הכללים החדשה.

יצירת מקור

נניח שאתם עובדים על פרויקט Firebase בשם secure_commerce ורוצים לפרוס Cloud Firestore Security Rules נעול למסד נתונים בפרויקט בשם east_store.

אפשר להטמיע את הכללים האלה בקובץ firestore.rules.

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

יצירת קבוצת כללים

עכשיו, צרו טביעת אצבע בקידוד Base64 לקובץ הזה. לאחר מכן, אפשר להשתמש במקור בקובץ הזה כדי לאכלס את המטען הייעודי (payload) שנדרש ליצירת קבוצת כללים באמצעות הקריאה ל-REST של projects.rulesets.create. כאן, משתמשים בפקודה cat כדי להוסיף את התוכן של firestore.rules למטען הייעודי (payload) של ה-REST.

למטרות מעקב, כדי לשייך את זה למסד הנתונים של east_store, צריך להגדיר את attachment_point ל-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 מתעדכנות באופן מלא תוך כמה דקות. כשמשתמשים ב-API לניהול בארכיטקטורת REST כדי לפרוס, חשוב להימנע ממרוץ תהליכים שבו האפליקציה מסתמכת באופן מיידי על כללים שהפריסה שלהם עדיין לא הושלמה.

עדכון של Realtime Database קבוצות כללים באמצעות REST

ל-Realtime Database יש ממשק REST משלו לניהול Security Rules. ניהול Realtime Database Security Rules של Firebase באמצעות REST.

ניהול קבוצות כללים באמצעות REST

כדי לעזור בניהול פריסות גדולות של כללים, בנוסף ל-method של REST ליצירת קבוצות כללים וגרסאות, ה-Management API מספק methods לביצוע הפעולות הבאות:

  • להציג, לקבל ולמחוק קבוצות כללים
  • הצגה, קבלה ומחיקה של גרסאות של כללים

בפריסות גדולות מאוד שמגיעות למגבלה של 2,500 קבוצות כללים לאורך זמן, אפשר ליצור לוגיקה למחיקת הכללים הישנים ביותר במחזור זמן קבוע. לדוגמה, כדי למחוק את כל קבוצות הכללים שנפרסו לפני יותר מ-30 יום, אפשר להפעיל את השיטה projects.rulesets.list, לנתח את רשימת ה-JSON של אובייקטים מסוג Ruleset במפתחות createTime שלהם, ואז להפעיל את project.rulesets.delete בקבוצות הכללים המתאימות לפי ruleset_id.

בדיקת העדכונים באמצעות REST

לבסוף, ה-Management API מאפשר להריץ בדיקות תחביריות וסמנטיות על משאבי Cloud Firestore ו-Cloud Storage בפרויקטים בסביבת הייצור.

הבדיקה עם הרכיב הזה של ה-API כוללת:

  1. הגדרה של אובייקט JSON מסוג TestSuite שמייצג קבוצה של אובייקטים מסוג TestCase
  2. שליחת TestSuite
  3. הניתוח החזיר TestResult אובייקטים

נגדיר אובייקט TestSuite עם TestCase יחיד בקובץ testcase.json. בדוגמה הזו, אנחנו מעבירים את קוד המקור של שפת Security Rules בתוך השורה עם המטען הייעודי (payload) של ה-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"}}}
            }
          ]
      }
    ]
  }
}

לאחר מכן, אפשר לשלוח את TestSuite להערכה באמצעות השיטה projects.test.

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

האובייקט TestReport שמוחזר (שמכיל את סטטוס הבדיקה SUCCESS/FAILURE, רשימות של הודעות ניפוי באגים, רשימות של ביטויי כללים שבוקרו ודוחות ההערכה שלהם) יאשר באמצעות הסטטוס SUCCESS שהגישה מותרת כראוי.

ניהול הרשאות ל-Cloud Storage Security Rules בשירותים שונים

אם אתם יוצרים Cloud Storage Security Rules שמשתמשים בתוכן של מסמכי Cloud Firestore כדי להעריך תנאי אבטחה, תתבקשו במסוף Firebase או ב-CLI של Firebase להפעיל הרשאות לחיבור בין שני המוצרים.

אם תחליטו להשבית את האבטחה הזו בין השירותים:

  1. לפני שמשביתים את התכונה, צריך לערוך את הכללים ולהסיר את כל ההצהרות שמשתמשות בפונקציות של Security Rules כדי לגשת אל Cloud Firestore. אחרת, אחרי שהתכונה תושבת, הערכות של Security Rules יגרמו לבקשות האחסון להיכשל.

  2. משתמשים בדף IAM במסוף Google Cloud כדי למחוק את התפקיד Firebase Rules Firestore Service Agent, לפי המדריך של Cloud לביטול תפקידים.

בפעם הבאה שתשמרו כללים חוצי-שירותים מ-CLI של Firebase או ממסוף Firebase, תתבקשו להפעיל מחדש את התכונה.