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

ב-Firebase יש כמה כלים לניהול 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 או ה-CLI של Firebase. אחרת, יכול להיות שתמחקו את כל העדכונים שבוצעו במסוף Firebase.

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

ב-Local Emulator Suite יש אמוללטורים לכל המוצרים שתומכים בכללי אבטחה. המנוע של כללי האבטחה בכל אמולטור מבצע הערכה תחבירית וגם סמנטית של הכללים, כך שהוא חורג מהבדיקה התחברית שמציע Security Rules management 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, ובדיקה סמנטית זמינה באמצעות Rules Playground.

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

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

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

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

פריסה של העדכונים

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

שימוש ב-Admin 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 עצמו. ממשק ה-API לניהול מספק את הגמישות הרבה ביותר.

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

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

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

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

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

השלבים הרגילים ליצירה ולפריסה של מערכת כללים באמצעות ממשק ה-API לניהול הם:

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

יצירת מקור

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

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

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

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

עכשיו יוצרים טביעת אצבע בקידוד base64 עבור הקובץ הזה. לאחר מכן תוכלו להשתמש במקור שבקובץ הזה כדי לאכלס את עומס העבודה הנדרש ליצירת כלל באמצעות קריאת ה-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 לניהול לצורך פריסה, חשוב להימנע ממצבים של תחרות (race condition) שבהם האפליקציה מסתמכת באופן מיידי על כללים שהפריסה שלהם עדיין לא הושלמה.

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

ל-Realtime Database יש ממשק REST משלו לניהול Rules. למידע נוסף, אפשר לקרוא את המאמר ניהול Firebase Realtime Database Rules דרך REST.

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

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

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

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

לאחר מכן אפשר לשלוח את השדה 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. לפני השבתת התכונה, צריך לערוך את הכללים ולהסיר את כל ההצהרות שמשתמשות בפונקציות Rules כדי לגשת ל-Cloud Firestore. אחרת, אחרי שהתכונה תושבת, הבדיקות של Rules יגרמו לכישלון של בקשות האחסון.

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

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