השתמש בתנאים בכללי האבטחה של Firebase Cloud Storage

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

אבן הבניין העיקרית של כללי האבטחה של Cloud Storage הוא התנאי . תנאי הוא ביטוי בוליאני שקובע אם יש לאפשר או לדחות פעולה מסוימת. לגבי כללים בסיסיים, שימוש במילולי true false כתנאים עובד מצוין. אבל כללי האבטחה של Firebase עבור שפת Cloud Storage נותנים לך דרכים לכתוב תנאים מורכבים יותר שיכולים:

  • בדוק את אימות המשתמש
  • אימות נתונים נכנסים

אימות

כללי האבטחה של Firebase עבור Cloud Storage משתלבים עם Firebase Authentication כדי לספק אימות מבוסס משתמשים רב עוצמה ל-Cloud Storage. זה מאפשר בקרת גישה פרטנית המבוססת על תביעות של אסימון Firebase Authentication.

כאשר משתמש מאומת מבצע בקשה נגד Cloud Storage, המשתנה request.auth מאוכלס ב- uid של המשתמש ( request.auth.uid ) וכן בטענות של Firebase Authentication JWT ( request.auth.token ).

בנוסף, בעת שימוש באימות מותאם אישית, תביעות נוספות מופיעות בשדה request.auth.token .

כאשר משתמש לא מאומת מבצע בקשה, המשתנה request.auth הוא null .

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

  • ציבורי: התעלם request.auth
  • פרטי מאומת: בדוק ש- request.auth אינו null
  • משתמש פרטי: בדוק ש- request.auth.uid שווה ל- uid של נתיב
  • קבוצה פרטית: בדוק את התביעות של האסימון המותאם אישית כדי להתאים לטענה שנבחרה, או קרא את המטא נתונים של הקובץ כדי לראות אם קיים שדה מטא נתונים

פּוּמְבֵּי

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

// Anyone to read a public image if the file is less than 100kB
// Anyone can upload a public file ending in '.txt'
match /public/{imageId} {
  allow read: if resource.size < 100 * 1024;
  allow write: if imageId.matches(".*\\.txt");
}

פרטי מאומת

במקרים מסוימים, ייתכן שתרצה שהנתונים יהיו ניתנים לצפייה על ידי כל המשתמשים המאומתים של האפליקציה שלך, אך לא על ידי משתמשים לא מאומתים. מכיוון שהמשתנה request.auth הוא null עבור כל המשתמשים הלא מאומתים, כל שעליכם לעשות הוא לבדוק את קיים המשתנה request.auth כדי לדרוש אימות:

// Require authentication on all internal image reads
match /internal/{imageId} {
  allow read: if request.auth != null;
}

משתמש פרטי

ללא ספק מקרה השימוש הנפוץ ביותר עבור request.auth יהיה לספק למשתמשים בודדים הרשאות מפורטות לקבצים שלהם: מהעלאת תמונות פרופיל ועד קריאת מסמכים פרטיים.

מכיוון שלקבצים ב-Cloud Storage יש "נתיב" מלא לקובץ, כל מה שצריך כדי ליצור קובץ שנשלט על ידי משתמש הוא פיסת מידע ייחודי מזהה משתמש בקידומת שם הקובץ (כגון uid של המשתמש) שניתן לבדוק כאשר הכלל מוערך:

// Only a user can upload their profile picture, but anyone can view it
match /users/{userId}/profilePicture.png {
  allow read;
  allow write: if request.auth.uid == userId;
}

קבוצה פרטית

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

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

// Allow reads if the group ID in your token matches the file metadata's `owner` property
// Allow writes if the group ID is in the user's custom token
match /files/{groupId}/{fileName} {
  allow read: if resource.metadata.owner == request.auth.token.groupId;
  allow write: if request.auth.token.groupId == groupId;
}

בקש הערכה

העלאות, הורדות, שינויים במטא נתונים ומחיקות מוערכים באמצעות request הנשלחת ל-Cloud Storage. בנוסף למזהה הייחודי של המשתמש ולעומס ה-Firebase Authentication באובייקט request.auth כמתואר לעיל, משתנה request מכיל את נתיב הקובץ שבו מתבצעת הבקשה, את השעה שבה הבקשה מתקבלת, ואת ערך resource החדש אם הבקשה היא כתיבה.

אובייקט request מכיל גם את המזהה הייחודי של המשתמש ואת מטען האימות של Firebase באובייקט 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 עבור 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 חוּט hash crc32c של האובייקט.
etag חוּט ה-Etag המשויך לאובייקט זה.
contentDisposition חוּט צורת התוכן המשויכת לאובייקט זה.
contentEncoding חוּט קידוד התוכן המשויך לאובייקט זה.
contentLanguage חוּט שפת התוכן המשויכת לאובייקט זה.
contentType חוּט סוג התוכן המשויך לאובייקט זה.
metadata map<string, string> צמדי מפתח/ערך של מטא נתונים נוספים בהתאמה אישית שצוינו על ידי מפתח.

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

שפר עם Cloud Firestore

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

באמצעות הפונקציות firestore.get() ו- firestore.exists() , כללי האבטחה שלך יכולים להעריך בקשות נכנסות מול מסמכים ב-Cloud Firestore. הפונקציות firestore.get() ו- firestore.exists() מצפות לנתיבי מסמך שצוינו במלואם. בעת שימוש במשתנים לבניית נתיבים עבור firestore.get() ו- firestore.exists() , עליך להימלט במפורש למשתנים באמצעות התחביר $(variable) .

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

service firebase.storage {
  match /b/{bucket}/o {
    match /users/{club}/files/{fileId} {
      allow read: if club in
        firestore.get(/databases/(default)/documents/users/$(request.auth.id)).memberships
    }
  }
}
בדוגמה הבאה, רק חברים של משתמש יכולים לראות את התמונות שלו.
service firebase.storage {
  match /b/{bucket}/o {
    match /users/{userId}/photos/{fileId} {
      allow read: if
        firestore.exists(/databases/(default)/documents/users/$(userId)/friends/$(request.auth.id))
    }
  }
}

לאחר שתיצור ותשמור את כללי האבטחה הראשונים של Cloud Storage המשתמשים בפונקציות האלה של Cloud Firestore, תתבקש במסוף Firebase או Firebase CLI לאפשר הרשאות לחיבור שני המוצרים.

אתה יכול להשבית את התכונה על ידי הסרת תפקיד IAM, כמתואר בניהול ופריסה של כללי אבטחה של Firebase .

אמת נתונים

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

service firebase.storage {
  match /b/{bucket}/o {
    match /images/{imageId} {
      // Only allow uploads of any image file that's less than 5MB
      allow write: if request.resource.size < 5 * 1024 * 1024
                   && request.resource.contentType.matches('image/.*');
    }
  }
}

פונקציות מותאמות אישית

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

  • פונקציות יכולות להכיל רק הצהרת return אחת. הם לא יכולים להכיל שום היגיון נוסף. לדוגמה, הם לא יכולים לבצע לולאות או להתקשר לשירותים חיצוניים.
  • פונקציות יכולות לגשת אוטומטית לפונקציות ומשתנים מההיקף שבו הן מוגדרות. לדוגמה, לפונקציה המוגדרת בהיקף service firebase.storage יש גישה למשתנה resource , ול-Cloud Firestore בלבד, פונקציות מובנות כגון get() ו- exists() .
  • פונקציות עשויות לקרוא לפונקציות אחרות אך לא יחזרו. עומק השיחות הכולל מוגבל ל-10.
  • בגרסה rules2 , פונקציות יכולות להגדיר משתנים באמצעות מילת המפתח let . לפונקציות יכולות להיות כל מספר של כריכות let, אבל חייבות להסתיים בהצהרת return.

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

service firebase.storage {
  match /b/{bucket}/o {
    // True if the user is signed in or the requested data is 'public'
    function signedInOrPublic() {
      return request.auth.uid != null || resource.data.visibility == 'public';
    }
    match /images/{imageId} {
      allow read, write: if signedInOrPublic();
    }
    match /mp3s/{mp3Ids} {
      allow read: if signedInOrPublic();
    }
  }
}

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

הצעדים הבאים

לאחר הדיון הזה בתנאים, יש לך הבנה מתוחכמת יותר של הכללים ואתה מוכן:

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