המדריך הזה מבוסס על המדריך ללימוד התחביר הבסיסי של שפת Firebase Security Rules, ומסביר איך להוסיף תנאים ל-Firebase Security Rules עבור Cloud Storage.
אבן הבניין העיקרית של Cloud Storage Security Rules היא התנאי. תנאי הוא ביטוי בוליאני שקובע אם צריך לאפשר או לדחות פעולה מסוימת. בכללים בסיסיים, שימוש במאפיינים true
ו-false
כמחרוזות מילוליות בתנאים פועל בצורה מושלמת. אבל Firebase Security Rules בשפת Cloud Storage
מאפשר לכם לכתוב תנאים מורכבים יותר שיכולים:
- בדיקת אימות משתמשים
- אימות נתונים נכנסים
אימות
Firebase Security Rules ל-Cloud Storage משתלב עם Firebase Authentication כדי לספק אימות עוצמתי מבוסס-משתמש ל-Cloud Storage. כך אפשר להגדיר בקרת גישה מפורטת על סמך הצהרות של אסימון Firebase Authentication.
כשמשתמש מאומת שולח בקשה אל Cloud Storage, המשתנה request.auth
מאוכלס בuid
של המשתמש (request.auth.uid
) וגם בהצהרות של אסימון ה-JWT Firebase Authentication (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; }
קבוצה פרטית
תרחיש שימוש נפוץ נוסף הוא מתן הרשאות לקבוצה באובייקט, למשל מתן אפשרות לכמה חברי צוות לשתף פעולה במסמך משותף. יש כמה גישות לביצוע הפעולה הזו:
- יצירת Firebase Authentication אסימון בהתאמה אישית שמכיל מידע נוסף על חבר בקבוצה (כמו מזהה קבוצה)
- לכלול את פרטי הקבוצה (כמו מזהה קבוצה או רשימה של
uid
ים מורשים) במטא-נתונים של הקובץ
אחרי שהנתונים האלה מאוחסנים במטא-נתונים של האסימון או הקובץ, אפשר להפנות אליהם מתוך כלל:
// 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. בנוסף למזהה הייחודי של המשתמש ולמטען הייעודי (payload) Firebase Authentication באובייקט request.auth
, כפי שמתואר למעלה, המשתנה request
מכיל את נתיב הקובץ שבו מתבצעת הבקשה, את השעה שבה הבקשה מתקבלת ואת הערך החדש resource
אם הבקשה היא בקשת כתיבה.
אובייקט request
מכיל גם את המזהה הייחודי של המשתמש ואת מטען הייעודי (payload) של Firebase Authentication באובייקט request.auth
, שיוסבר בהמשך בקטע אבטחה מבוססת-משתמש במסמכים.
בהמשך מופיעה רשימה מלאה של המאפיינים באובייקט request
:
נכס | סוג | תיאור |
---|---|---|
auth |
map<string, string> | כשמשתמש מחובר לחשבון, הוא מספק את uid , המזהה הייחודי של המשתמש, ואת token , מיפוי של הצהרות JWT של Firebase Authentication. אחרת, הוא יהיה
null . |
params |
map<string, string> | מפה שמכילה את פרמטרים של השאילתה של הבקשה. |
path |
נתיב | מחרוזת path שמייצגת את הנתיב שבו הבקשה מבוצעת. |
resource |
map<string, string> | ערך המשאב החדש, שמופיע רק בבקשות write .
|
time |
חותמת זמן | חותמת זמן שמייצגת את זמן השרת שבו הבקשה מוערכת. |
הערכת משאבים
כשמעריכים כללים, כדאי גם להעריך את המטא-נתונים של הקובץ שמועלה, מורד, משתנה או נמחק. כך תוכלו ליצור כללים מורכבים ועוצמתיים שיאפשרו לכם, למשל, להעלות רק קבצים עם סוגי תוכן מסוימים, או למחוק רק קבצים שגדולים מגודל מסוים.
Firebase Security Rules עבור Cloud Storage מספק מטא-נתונים של קובץ באובייקט resource
, שמכיל צמדי מפתח/ערך של המטא-נתונים שמוצגים באובייקט Cloud Storage. אפשר לבדוק את המאפיינים האלה בבקשות אל read
או אל write
כדי לוודא את שלמות הנתונים.
בבקשות write
(כמו העלאות, עדכוני מטא-נתונים ומחיקות), בנוסף לאובייקט write
, שמכיל מטא-נתונים של הקובץ שקיים כרגע בנתיב הבקשה, יש לכם גם אפשרות להשתמש באובייקט request.resource
, שמכיל קבוצת משנה של מטא-נתונים של הקובץ שייכתבו אם הכתיבה תאושר.resource
אפשר להשתמש בשני הערכים האלה כדי לוודא את שלמות הנתונים או לאכוף מגבלות על האפליקציה, כמו סוג או גודל הקובץ.
בהמשך מופיעה רשימה מלאה של המאפיינים באובייקט resource
:
נכס | סוג | תיאור |
---|---|---|
name |
מחרוזת | השם המלא של האובייקט |
bucket |
מחרוזת | שם הקטגוריה שבה נמצא האובייקט. |
generation |
int | Google Cloud Storageמספר הגנרציה של האובייקט. |
metageneration |
int | Google Cloud Storageמספר המטא-גנרציה של האובייקט. |
size |
int | גודל האובייקט בבייטים. |
timeCreated |
חותמת זמן | חותמת זמן שמייצגת את הזמן שבו נוצר אובייקט. |
updated |
חותמת זמן | חותמת זמן שמייצגת את הזמן שבו אובייקט עודכן בפעם האחרונה. |
md5Hash |
מחרוזת | גיבוב MD5 של האובייקט. |
crc32c |
מחרוזת | גיבוב (hash) מסוג crc32c של האובייקט. |
etag |
מחרוזת | תג ה-etag שמשויך לאובייקט הזה. |
contentDisposition |
מחרוזת | המאפיין content-disposition שמשויך לאובייקט הזה. |
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 Security Rules הראשון שמשתמש בפונקציות Cloud Firestore האלה, מוצגת בקשה במסוף Firebase או ב-CLI של Firebase להפעיל הרשאות לקישור בין שני המוצרים.
כדי להשבית את התכונה, צריך להסיר תפקיד IAM, כמו שמתואר במאמר ניהול ופריסה של Firebase Security Rules.
אימות נתונים
אפשר להשתמש ב-Firebase Security Rules עבור Cloud Storage גם לאימות נתונים, כולל אימות של שם הקובץ והנתיב שלו, וגם של מאפייני המטא-נתונים של הקובץ, כמו 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 Security Rules יהפכו למורכבות יותר, יכול להיות שתרצו להשתמש בפונקציות כדי לעטוף קבוצות של תנאים, כך שתוכלו להשתמש בהן שוב בכללי ה-ruleset. כללי אבטחה תומכים בפונקציות בהתאמה אישית. התחביר של פונקציות בהתאמה אישית דומה ל-JavaScript, אבל פונקציות Firebase Security Rules נכתבות בשפה ספציפית לתחום עם כמה מגבלות חשובות:
- פונקציות יכולות להכיל רק הצהרת
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 Security Rules מאפשר לכם לתחזק אותן בקלות רבה יותר ככל שהכללים נעשים מורכבים יותר.
השלבים הבאים
אחרי ההסבר הזה על תנאים, יש לכם הבנה מעמיקה יותר של כללים ואתם מוכנים:
איך מטפלים בתרחישי שימוש מרכזיים, ואיך מתבצע תהליך העבודה לפיתוח, לבדיקה ולפריסה של כללים:
- כותבים כללים שמתייחסים לתרחישים נפוצים.
- כדי להרחיב את הידע, מומלץ לעיין במצבים שבהם צריך לזהות כללים לא מאובטחים ולהימנע מהם.
- בודקים את הכללים באמצעות אמולטור Cloud Storage וספריית בדיקה ייעודית של כללי אבטחה.
- כדאי לעיין בשיטות הזמינות לפריסת Rules.