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

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

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

בחר מוצר למידע נוסף על כלליו.

Cloud Firestore

מבנה בסיסי

כללי האבטחה של Firebase ב- Cloud Firestore ובאחסון הענן משתמשים במבנה ובתחביר הבאים:

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

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

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

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

החל ממאי 2019, גרסה 2 של כללי האבטחה של Firebase זמינה כעת. גרסה 2 של הכללים משנה את ההתנהגות של ג'וקר רקורסיבית {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 subcollection. כללי אבטחה חלים רק על הנתיב המתאים, כך שולט הגישה מוגדרת על cities האוסף איננו חלים על landmarks subcollection. במקום זאת, כתוב כללים מפורשים לשליטה בגישה לאוספי משנה:

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 מתוך 10 שיחות הגישה שלה ובקשת הכתיבה המצוות משתמשת ב -6 מתוך 20 שיחות הגישה שלה.

חריגה ממגבלה גורמת לשגיאת שלילת הרשאה.

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

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

אחסון בענן

מבנה בסיסי

כללי האבטחה של Firebase ב- Cloud Firestore ובאחסון הענן משתמשים במבנה ובתחביר הבאים:

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

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

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

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

אחסון ענן אבטחה חוקי 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 של התוצאה של כל הערכות הכללים. כלומר, אם בכלל כלל הקובץ מתאים evalutes כדי true , התוצאה היא true .

בשנת הכללים לעיל, את הקובץ "תמונות / profilePhoto.png" ניתן לקרוא אם מתקיימים condition או other_condition להעריך אל נכון, בעוד הקובץ "images / משתמשים / משתמש: 12,345 / profilePhoto.png" כפוף רק התוצאה של other_condition .

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

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

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

בקש הערכה

העלאות, הורדות, שינויי metadata, ותמחק מוערכות באמצעות request נשלחת לאחסון בענן. request המשתנה מכיל את נתיב הקובץ שבו הבקשה מתבצעת, הפעם כאשר קבלת הבקשה, ואת החדש resource הערך אם הבקשה היא כתיבה. כותרות HTTP ומצב אימות כלולים גם כן.

request האובייקט מכיל גם את המזהה הייחודית של המשתמש, ומטען אימות Firebase ב request.auth האובייקט, אשר יוסבר נוסף אימות קטע Docs.

רשימה מלאה של נכסי request האובייקט זמינה להלן:

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

הערכת משאבים

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

אבטחת Firebase כללי אחסון הענן מספקים metadata קובץ resource האובייקט, אשר מכיל זוגות ערך / מפתח של metadata ועלו באובייקט אחסון בענן. ניתן לבדוק תכונות אלו על read או write בקשות כדי להבטיח שלמות הנתונים.

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

רשימה מלאה של נכסי resource האובייקט זמינה להלן:

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

request.resource מכיל את כל אלה, למעט generation , metageneration , etag , timeCreated , ו updated .

דוגמא מלאה

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

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
     }
   }
 }
}

מסד נתונים בזמן אמת

מבנה בסיסי

במאגר זמן אמת, כללי האבטחה של Firebase מורכבים מביטויים דמויי JavaScript הכלולים במסמך JSON.

הם משתמשים בתחביר הבא:

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

ישנם שלושה יסודות בסיסיים בחוק:

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

כיצד חלים חוקים על שבילים

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

שקול את הכללים הבאים:

{
  "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
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
}];
מָהִיר
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
})
ג'אווה
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
  });
});
מנוחה
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
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[ref child:@"records/rec1"] observeSingleEventOfType:FEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
    // SUCCESS!
}];
מָהִיר
var ref = FIRDatabase.database().reference()
ref.child("records/rec1").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // SUCCESS!
})
ג'אווה
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
  }
});
מנוחה
curl https://docs-examples.firebaseio.com/rest/records/rec1
# SUCCESS!

משתנה מיקום

כללי מסד זמן אמת לתמוך $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 }
      }
    }
  }