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

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

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

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

שימוש ב-CLI של Firebase

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

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

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

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

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

אפשר להשתמש בפקודות הבאות כדי לפרוס באופן סלקטיבי את 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 או אחסון בתפריט הניווט של המוצר, ולוחצים על כללים כדי לעבור לעורך 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, צריך להשתמש ב-methods 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 באמצעות ממשק ה-API לניהול עצמו. ה-Management 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 עבור הקובץ הזה. לאחר מכן אפשר להשתמש במקור שבקובץ הזה כדי לאכלס את המטען הייעודי (Payload) שנדרש ליצירת קבוצת כללים עם הקריאה projects.rulesets.create ל-REST. כאן משתמשים בפקודה 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. למידע נוסף, ראו ניהול Realtime Database Rules ב-Firebase באמצעות REST.

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

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

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

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

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

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

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

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

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

לאחר מכן אפשר לשלוח את השדה 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 כדי למחוק את התפקיד 'סוכן שירות של Firestore על כללי Firebase'. תוכלו להיעזר במדריך של Cloud לביטול תפקידים.

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