איך פועלים כללי האבטחה

אבטחה היא אחד החלקים המורכבים ביותר בפאזל של פיתוח אפליקציות. ברוב האפליקציות, המפתחים צריכים ליצור ולהפעיל שרת שמטפל באימות (מי המשתמש) ובהרשאה (מה המשתמש יכול לעשות).

Firebase Security Rules מסירים את השכבה האמצעית (השרת) ומאפשרים לציין הרשאות מבוססות-נתיב ללקוחות שמתחברים ישירות לנתונים. במדריך הזה מוסבר איך הכללים חלים על בקשות נכנסות.

בוחרים מוצר כדי לקבל מידע נוסף על הכללים שלו.

Cloud Firestore

המבנה הבסיסי

Firebase Security Rules ב-Cloud Firestore וב-Cloud Storage משתמש במבנה ובתחביר הבאים:

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

חשוב להבין את מושגי המפתח הבאים כשאתם יוצרים את הכללים:

  • Request: השיטות שהופעלו בהצהרה allow. אלה השיטות שאתם מאפשרים להריץ. השיטות הרגילות הן: get,‏ list,‏ create,‏ update ו-delete. שיטות הנוחות read ו-write מאפשרות גישה רחבה לקריאה ולכתיבה במסד הנתונים או בנתיב האחסון שצוינו.
  • נתיב: מסד הנתונים או מיקום האחסון, שמיוצגים כנתיב URI.
  • כלל: משפט allow, שכולל תנאי שמאפשר בקשה אם הוא מקבל ערך True.

כללי אבטחה בגרסה 2

החל ממאי 2019, גרסה 2 של כללי האבטחה של Firebase זמינה עכשיו. בגרסה 2 של הכללים יש שינוי בהתנהגות של סמלי Wildcard רפרסיביים {name=**}. אם אתם מתכננים להשתמש בשאילתות של קבוצות אוספים, עליכם להשתמש בגרסה 2. כדי להביע הסכמה לגרסה 2, צריך להגדיר את rules_version = '2'; כשורה הראשונה בכללי האבטחה:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {

נתיבים תואמים

כל הצהרות ההתאמה צריכות להפנות למסמכים, ולא לאוספים. משפט התאמה יכול להפנות למסמך ספציפי, כמו ב-match /cities/SF, או להשתמש בתווים כלליים לחיפוש כדי להפנות לכל מסמך בנתיב שצוין, כמו ב-match /cities/{city}.

בדוגמה שלמעלה, משפט ההתאמה משתמש בתחביר התו הכללי {city}. המשמעות היא שהכלל חל על כל מסמך באוסף cities, כמו /cities/SF או /cities/NYC. כשהביטויים allow במשפט ההתאמה ייבדקו, המשתנה city יתורגם לשם המסמך של העיר, למשל SF או NYC.

אוספים משניים תואמים

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

נניח שכל מסמך באוסף cities מכיל אוסף משנה של landmarks. כללי האבטחה חלים רק על הנתיב שתואמת, כך שבקרות הגישה שהוגדרו באוסף cities לא חלות על אוסף המשנה landmarks. במקום זאת, כותבים כללים מפורשים כדי לשלוט בגישה לאוספים המשנה:

service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      allow read, write: if <condition>;

      // Explicitly define rules for the 'landmarks' subcollection
      match /landmarks/{landmark} {
        allow read, write: if <condition>;
      }
    }
  }
}

כשמשתמשים בהטמעה של משפטי match, הנתיב של משפט ה-match הפנימי תמיד יחסי לנתיב של משפט ה-match החיצוני. לכן, כללי המדיניות הבאים זהים:

service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      match /landmarks/{landmark} {
        allow read, write: if <condition>;
      }
    }
  }
}
service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city}/landmarks/{landmark} {
      allow read, write: if <condition>;
    }
  }
}

תווים כלליים לחיפוש רקורסיביים

אם רוצים שהכללים יחולו על היררכיה עמוקה באופן שרירותי, צריך להשתמש בתחביר של תו כללי לחיפוש רקורסיבי, {name=**}:

service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the cities collection as well as any document
    // in a subcollection.
    match /cities/{document=**} {
      allow read, write: if <condition>;
    }
  }
}

כשמשתמשים בתחביר של תו כללי לחיפוש רקורסיבי, משתנה התו הכללי לחיפוש יכיל את מקטע הנתיב התואם כולו, גם אם המסמך נמצא באוסף משנה שמנוקד לעומק. לדוגמה, הכללים שמפורטים למעלה יתאימו למסמך שנמצא בכתובת /cities/SF/landmarks/coit_tower, והערך של המשתנה document יהיה SF/landmarks/coit_tower.

עם זאת, חשוב לזכור שההתנהגות של תווים כלליים רפלקסיביים תלויה בגרסה של הכללים.

גרסה 1

כברירת מחדל, כללי האבטחה משתמשים בגרסה 1. בגרסה 1, תווים כלליים רפלקסיביים תואמים לפריט נתיב אחד או יותר. הם לא תואמים לנתיב ריק, ולכן match /cities/{city}/{document=**} תואם למסמכים באוספי משנה אבל לא באוסף cities, ואילו match /cities/{document=**} תואם גם למסמכים באוסף cities וגם באוספי המשנה.

תווים כלליים רפלקסיביים חייבים להופיע בסוף משפט התאמה.

גרסה 2

בגרסה 2 של כללי האבטחה, תווים כלליים לחיפוש רפלקסיביים תואמים לאפס או יותר פריטים בנתיב. match/cities/{city}/{document=**} תואמת למסמכים בכל אוספי המשנה וגם למסמכים באוסף cities.

כדי להביע הסכמה לגרסה 2, צריך להוסיף את הערך rules_version = '2'; בחלק העליון של כללי האבטחה:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the cities collection as well as any document
    // in a subcollection.
    match /cities/{city}/{document=**} {
      allow read, write: if <condition>;
    }
  }
}

אפשר להשתמש בתו כללי לחיפוש רספונסיבי אחד לכל היותר בכל משפט התאמה, אבל בגרסה 2 אפשר למקם את התו הזה בכל מקום במשפט ההתאמה. לדוגמה:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the songs collection group
    match /{path=**}/songs/{song} {
      allow read, write: if <condition>;
    }
  }
}

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

הצהרות התאמה חופפות

יכול להיות שמסמך יתאים ליותר מטענת match אחת. במקרה שבו כמה ביטויים של allow תואמים לבקשה, הגישה מותרת אם אחד מהתנאים הוא true:

service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the 'cities' collection.
    match /cities/{city} {
      allow read, write: if false;
    }

    // Matches any document in the 'cities' collection or subcollections.
    match /cities/{document=**} {
      allow read, write: if true;
    }
  }
}

בדוגמה שלמעלה, כל הקריאות והכתובות לאוסף cities יהיו מותרות כי הכלל השני הוא תמיד true, גם אם הכלל הראשון הוא תמיד false.

מגבלות על כללי אבטחה

כשעובדים עם כללי אבטחה, חשוב לשים לב למגבלות הבאות:

מגבלה פרטים
המספר המקסימלי של קריאות ל-exists(), ל-get() ול-getAfter() בכל בקשה
  • 10 לבקשות של מסמך יחיד ולבקשות של שאילתות.
  • 20 לקריאות של מסמכים מרובים, לעסקאות ולכתיבה באצווה. המגבלה הקודמת של 10 חלה גם על כל פעולה.

    לדוגמה, נניח שיצרתם בקשת כתיבה באצווה עם 3 פעולות כתיבה, ושכללי האבטחה שלכם משתמשים ב-2 קריאות גישה למסמך כדי לאמת כל פעולת כתיבה. במקרה כזה, כל פעולת כתיבה משתמשת ב-2 מתוך 10 קריאות הגישה שלה, ובבקשת הכתיבה בכמות גדולה משתמשים ב-6 מתוך 20 קריאות הגישה שלה.

אם חורגים מאחד מהגבולות האלה, מתקבלת הודעת שגיאה מסוג 'הרשאה נדחתה'.

יכול להיות שחלק מהקריאות לגישה למסמכים יישמרו במטמון, קריאות כאלה לא נספרות במסגרת המגבלות.

עומק הקינון המקסימלי של משפטי match 10
אורך הנתיב המקסימלי, בקטעי נתיב, שמותר בקבוצה של משפטי match בתצוגת עץ 100
המספר המקסימלי של משתני תיעוד נתיב שמותר להשתמש בהם בתוך קבוצה של משפטי match בתצוגת עץ 20
עומק קריאה מקסימלי של פונקציה 20
מספר הארגומנטים המקסימלי של פונקציה 7
המספר המקסימלי של קישורי משתני let לכל פונקציה 10
המספר המקסימלי של קריאות פונקציה חזרותיות או מחזוריות 0 &lpar;not permitted&rpar;
המספר המקסימלי של ביטויים שאפשר להעריך בכל בקשה 1,000
הגודל המקסימלי של קבוצת כללים קבוצות הכללים חייבות לעמוד בשני מגבלות גודל:
  • מגבלה של 256KB על גודל מקור הטקסט של כללי המדיניות שפורסם מהמסוף Firebase או מה-CLI באמצעות firebase deploy.
  • מגבלה של 250KB על גודל קבוצת הכללים המתומצתת שנוצרת כש-Firebase מעבד את המקור ומפעיל אותו בקצה העורפי.

Cloud Storage

המבנה הבסיסי

Firebase Security Rules ב-Cloud Firestore וב-Cloud Storage משתמש במבנה ובתחביר הבאים:

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

חשוב להבין את מושגי המפתח הבאים כשאתם יוצרים את הכללים:

  • Request: השיטות שהופעלו בהצהרה allow. אלה השיטות שאתם מאפשרים להריץ. השיטות הרגילות הן: get,‏ list,‏ create,‏ update ו-delete. שיטות הנוחות read ו-write מאפשרות גישה רחבה לקריאה ולכתיבה במסד הנתונים או בנתיב האחסון שצוינו.
  • נתיב: מסד הנתונים או מיקום האחסון, שמיוצגים כנתיב URI.
  • כלל: משפט allow, שכולל תנאי שמאפשר בקשה אם הוא מקבל ערך True.

נתיבים תואמים

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

התאמות מדויקות

// Exact match for "images/profilePhoto.png"
match /images/profilePhoto.png {
  allow write: if <condition>;
}

// Exact match for "images/croppedProfilePhoto.png"
match /images/croppedProfilePhoto.png {
  allow write: if <other_condition>;
}

התאמות בתצוגת עץ

// Partial match for files that start with "images"
match /images {
  // Exact match for "images/profilePhoto.png"
  match /profilePhoto.png {
    allow write: if <condition>;
  }

  // Exact match for "images/croppedProfilePhoto.png"
  match /croppedProfilePhoto.png {
    allow write: if <other_condition>;
  }
}

התאמות של תווים כלליים לחיפוש

אפשר גם להשתמש בכללים כדי match תבנית באמצעות תווים כלליים לחיפוש. תו כללי לחיפוש הוא משתנה בעל שם שמייצג מחרוזת אחת, כמו profilePhoto.png, או כמה קטעי נתיב, כמו images/profilePhoto.png.

כדי ליצור תו כללי לחיפוש, מוסיפים סוגריים מסולסלים סביב שם התו הכללי, כמו {string}. כדי להצהיר על תו כללי לחיפוש עם כמה פלחים, מוסיפים את הערך =** לשם של התו הכללי לחיפוש, כמו {path=**}:

// Partial match for files that start with "images"
match /images {
  // Exact match for "images/*"
  // e.g. images/profilePhoto.png is matched
  match /{imageId} {
    // This rule only matches a single path segment (*)
    // imageId is a string that contains the specific segment matched
    allow read: if <condition>;
  }

  // Exact match for "images/**"
  // e.g. images/users/user:12345/profilePhoto.png is matched
  // images/profilePhoto.png is also matched!
  match /{allImages=**} {
    // This rule matches one or more path segments (**)
    // allImages is a path that contains all segments matched
    allow read: if <other_condition>;
  }
}

אם כמה כללים תואמים לקובץ, התוצאה היא OR של התוצאה של כל הערכות הכללים. כלומר, אם כלל כלשהו שהקובץ תואם לו מקבל את הערך true, התוצאה היא true.

לפי הכללים שלמעלה, אפשר לקרוא את הקובץ ‎images/profilePhoto.png אם הערך של condition או other_condition הוא true, ואילו הקובץ ‎images/users/user:12345/profilePhoto.png כפוף רק לתוצאה של other_condition.

אפשר להפנות למשתנה תו כללי לחיפוש מתוך ההרשאה של שם הקובץ או הנתיב של הספק match:

// Another way to restrict the name of a file
match /images/{imageId} {
  allow read: if imageId == "profilePhoto.png";
}

Cloud Storage Security Rules לא מתבצעת שרשור, והכללים נבדקים רק כשנתיב הבקשה תואם לנתיב עם כללים שצוינו.

שליחת בקשה להערכה

המערכת מבצעת הערכה של העלאות, הורדות, שינויים במטא-נתונים ומחיקות באמצעות הערך של request שנשלח אל Cloud Storage. המשתנה request מכיל את נתיב הקובץ שבו מתבצעת הבקשה, את השעה שבה התקבלה הבקשה ואת הערך החדש של resource אם הבקשה היא לכתיבה. הנתונים כוללים גם כותרות HTTP ומצב אימות.

האובייקט request מכיל גם את המזהה הייחודי של המשתמש ואת עומס העבודה (payload) של Firebase Authentication באובייקט request.auth. נסביר על כך בהרחבה בקטע אימות במסמכים.

בהמשך מופיעה רשימה מלאה של המאפיינים באובייקט request:

נכס סוג תיאור
auth map<string, string> כשמשתמש מחובר לחשבון, הוא מספק את uid, המזהה הייחודי של המשתמש, וגם את token, מפה של Firebase Authentication הצהרות JWT. אחרת, הערך יהיה null.
params map<string, string> מפה שמכילה את הפרמטרים של השאילתה בבקשה.
path נתיב path שמייצג את הנתיב שבו מתבצעת הבקשה.
resource map<string, string> ערך המשאב החדש, שמופיע רק בבקשות write.
time חותמת זמן חותמת זמן שמייצגת את השעה בשרת שבה הבקשה נבדקה.

הערכת משאבים

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

Firebase Security Rules עבור Cloud Storage מספק מטא-נתונים של קובץ באובייקט resource, שמכיל צמדי מפתח/ערך של המטא-נתונים שמוצגים באובייקט Cloud Storage. אפשר לבדוק את המאפיינים האלה בבקשות read או write כדי להבטיח את תקינות הנתונים.

בבקשות write (כמו העלאות, עדכוני מטא-נתונים ומחיקה), בנוסף לאובייקט resource שמכיל את המטא-נתונים של הקובץ שקיים כרגע בנתיב הבקשה, יש לכם גם אפשרות להשתמש באובייקט request.resource שמכיל קבוצת משנה של המטא-נתונים של הקובץ שרוצים לכתוב אם הכתיבה מותרת. אפשר להשתמש בשני הערכים האלה כדי לוודא את תקינות הנתונים או לאכוף אילוצים באפליקציה, כמו סוג הקובץ או הגודל שלו.

בהמשך מופיעה רשימה מלאה של המאפיינים באובייקט resource:

נכס סוג תיאור
name מחרוזת השם המלא של האובייקט
bucket מחרוזת השם של הקטגוריה שבה האובייקט נמצא.
generation int מספר הגרסה של האובייקט Google Cloud Storage.
metageneration int מספר המטא-הדור של אובייקט Google Cloud Storage.
size int גודל האובייקט בבייטים.
timeCreated חותמת זמן חותמת זמן שמייצגת את הזמן שבו נוצר אובייקט.
updated חותמת זמן חותמת זמן שמייצגת את הזמן שבו אובייקט עודכן בפעם האחרונה.
md5Hash מחרוזת גיבוב (hash) MD5 של האובייקט.
crc32c מחרוזת גיבוב CRC32C של האובייקט.
etag מחרוזת ה-etag שמשויך לאובייקט הזה.
contentDisposition מחרוזת אופן הטיפול בתוכן שמשויך לאובייקט הזה.
contentEncoding מחרוזת קידוד התוכן שמשויך לאובייקט הזה.
contentLanguage מחרוזת שפת התוכן שמשויכת לאובייקט הזה.
contentType מחרוזת סוג התוכן שמשויך לאובייקט הזה.
metadata map<string, string> צמדי מפתח/ערך של מטא-נתונים מותאמים אישית נוספים שצוינו על ידי המפתח.

השדה request.resource מכיל את כל הערכים האלה, מלבד generation, ‏ metageneration, ‏ etag, ‏ timeCreated ו-updated.

מגבלות על כללי אבטחה

כשעובדים עם כללי אבטחה, חשוב לשים לב למגבלות הבאות:

מגבלה פרטים
המספר המקסימלי של קריאות ל-firestore.exists() ול-firestore.get() לכל בקשה

2 לבקשות של מסמך יחיד ולבקשות של שאילתות.

אם חורגים מהמגבלה הזו, תופיע שגיאה מסוג permission denied.

יכול להיות שקריאות גישה לאותו מסמך יישמרו במטמון, וקריאות במטמון לא נספרות במסגרת המגבלות.

דוגמה מלאה

אם משלבים את כל הרכיבים האלה, אפשר ליצור דוגמה מלאה לכללים לפתרון אחסון תמונות:

service firebase.storage {
 match /b/{bucket}/o {
   match /images {
     // Cascade read to any image type at any path
     match /{allImages=**} {
       allow read;
     }

     // Allow write files to the path "images/*", subject to the constraints:
     // 1) File is less than 5MB
     // 2) Content type is an image
     // 3) Uploaded content type matches existing content type
     // 4) File name (stored in imageId wildcard variable) is less than 32 characters
     match /{imageId} {
       allow write: if request.resource.size < 5 * 1024 * 1024
                    && request.resource.contentType.matches('image/.*')
                    && request.resource.contentType == resource.contentType
                    && imageId.size() < 32
     }
   }
 }
}

Realtime Database

המבנה הבסיסי

ב-Realtime Database, Firebase Security Rules מורכב מהבעיות שדומות ל-JavaScript שמכילות במסמך JSON.

נעשה בהם שימוש בתחביר הבא:

{
  "rules": {
    "<<path>>": {
    // Allow the request if the condition for each method is true.
      ".read": <<condition>>,
      ".write": <<condition>>,
      ".validate": <<condition>>
    }
  }
}

יש שלושה רכיבים בסיסיים בכלל:

  • נתיב: המיקום של מסד הנתונים. המבנה הזה משקף את מבנה ה-JSON של מסד הנתונים.
  • Request:אלה השיטות שבהן הכלל משתמש כדי להעניק גישה. הכללים read ו-write מעניקים גישה רחבה לקריאה ולכתיבה, בעוד שהכללים validate משמשים לאימות משני כדי להעניק גישה על סמך נתונים נכנסים או קיימים.
  • Condition: התנאי שמאפשר בקשה אם הערך המחושב שלו הוא True.

איך הכללים חלים על נתיבים

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

כדאי להביא בחשבון את הכללים הבאים:

{
  "rules": {
     "foo": {
        // allows read to /foo/*
        ".read": "data.child('baz').val() === true",
        "bar": {
          // ignored, since read was allowed already
          ".read": false
        }
     }
  }
}

מבנה האבטחה הזה מאפשר לקרוא מ-/bar/ בכל פעם ש-/foo/ מכיל צאצא baz עם הערך true. לכלל ".read": false בקטע /foo/bar/ אין השפעה כאן, כי אי אפשר לבטל את הגישה דרך נתיב צאצא.

יכול להיות שהתכונה הזו לא תראה אינטואיטיבית במבט ראשון, אבל היא חלק חזק בשפת הכללים ומאפשרת להטמיע הרשאות גישה מורכבות מאוד במאמץ מינימלי. האפשרות הזו שימושית במיוחד לאבטחה מבוססת-משתמשים.

עם זאת, כללי .validate לא מופעלים ברצף. כדי לאפשר כתיבה, כל כללי האימות חייבים להתקיים בכל הרמות בהיררכיה.

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

{
  "rules": {
    "records": {
      "rec1": {
        ".read": true
      },
      "rec2": {
        ".read": false
      }
    }
  }
}

אם לא מבינים שהכללים נבדקים באופן אטומי, יכול להיות שייראה כאילו אחזור הנתיב /records/ יחזיר את הערך rec1 אבל לא את הערך rec2. עם זאת, התוצאה בפועל היא שגיאה:

JavaScript
var db = firebase.database();
db.ref("records").once("value", function(snap) {
  // success method is not called
}, function(err) {
  // error callback triggered with PERMISSION_DENIED
});
Objective-C
הערה: מוצר Firebase הזה לא זמין ביעד של קטע מקדים לאפליקציה.
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[_ref child:@"records"] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  // success block is not called
} withCancelBlock:^(NSError * _Nonnull error) {
  // cancel block triggered with PERMISSION_DENIED
}];
Swift
הערה: מוצר Firebase הזה לא זמין ביעד של קטע מקדים לאפליקציה.
var ref = FIRDatabase.database().reference()
ref.child("records").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // success block is not called
}, withCancelBlock: { error in
    // cancel block triggered with PERMISSION_DENIED
})
Java
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("records");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    // success method is not called
  }

  @Override
  public void onCancelled(FirebaseError firebaseError) {
    // error callback triggered with PERMISSION_DENIED
  });
});
REST
curl https://docs-examples.firebaseio.com/rest/records/
# response returns a PERMISSION_DENIED error

מכיוון שפעולת הקריאה ב-/records/ היא אטומית, ואין כלל קריאה שמעניק גישה לכל הנתונים ב-/records/, תופיע הודעת השגיאה PERMISSION_DENIED. אם נבדוק את הכלל הזה בסימולטור האבטחה במסוף Firebase, נוכל לראות שפעולת הקריאה נדחתה:

Attempt to read /records with auth=Success(null)
    /
    /records

No .read rule allowed the operation.
Read was denied.

הפעולה נדחתה כי אף כלל קריאה לא איפשר גישה לנתיב /records/. עם זאת, חשוב לציין שהכלל של rec1 מעולם לא הוערך כי הוא לא היה בנתיב שביקשנו. כדי לאחזר את rec1, נצטרך לגשת אליו ישירות:

JavaScript
var db = firebase.database();
db.ref("records/rec1").once("value", function(snap) {
  // SUCCESS!
}, function(err) {
  // error callback is not called
});
Objective-C
הערה: מוצר Firebase הזה לא זמין ביעד של קטע מקדים לאפליקציה.
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[ref child:@"records/rec1"] observeSingleEventOfType:FEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
    // SUCCESS!
}];
Swift
הערה: מוצר Firebase הזה לא זמין ביעד של קטע מקדים לאפליקציה.
var ref = FIRDatabase.database().reference()
ref.child("records/rec1").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // SUCCESS!
})
Java
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("records/rec1");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    // SUCCESS!
  }

  @Override
  public void onCancelled(FirebaseError firebaseError) {
    // error callback is not called
  }
});
REST
curl https://docs-examples.firebaseio.com/rest/records/rec1
# SUCCESS!

משתנה מיקום

Realtime Database Rules תומכים במשתנה $location כדי להתאים לפלחים של נתיב. כדי להתאים את הכלל לכל צומת צאצא לאורך הנתיב, משתמשים בתחילית $ לפני מקטע הנתיב.

  {
    "rules": {
      "rooms": {
        // This rule applies to any child of /rooms/, the key for each room id
        // is stored inside $room_id variable for reference
        "$room_id": {
          "topic": {
            // The room's topic can be changed if the room id has "public" in it
            ".write": "$room_id.contains('public')"
          }
        }
      }
    }
  }

אפשר גם להשתמש ב-$variable במקביל לשמות נתיב קבועים.

  {
    "rules": {
      "widget": {
        // a widget can have a title or color attribute
        "title": { ".validate": true },
        "color": { ".validate": true },

        // but no other child paths are allowed
        // in this case, $other means any key excluding "title" and "color"
        "$other": { ".validate": false }
      }
    }
  }