היכרות עם התחביר העיקרי של כללי האבטחה של Firebase לשפה של Cloud Storage

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

במדריך הזה מוסבר על התחביר והמבנה הבסיסיים של Cloud Storage Security Rules ליצירת כללי כלל מלאים.

הצהרה על שירותים ומסדי נתונים

Firebase Security Rules עבור Cloud Storage תמיד מתחילה בהצהרה הבאה:

service firebase.storage {
    // ...
}

ההצהרה service firebase.storage מגבילה את ההיקף של הכללים ל-Cloud Storage, ומונעת התנגשויות בין Cloud Storage Security Rules לבין כללים של מוצרים אחרים, כמו Cloud Firestore.

כללי קריאה/כתיבה בסיסיים

כללים בסיסיים מורכבים מטענת match שמזהה את הקטגוריות של Cloud Storage, טענת התאמה שמציינת שם קובץ וביטוי allow שמפרט מתי מותר לקרוא את הנתונים שצוינו. ביטויים של allow מצביעים על שיטות הגישה (למשל, קריאה, כתיבה) ועל התנאים שבהם הגישה מותרת או נדחית.

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

service firebase.storage {
  // The {bucket} wildcard indicates we match files in all Cloud Storage buckets
  match /b/{bucket}/o {
    // Match filename
    match /filename {
      allow read: if <condition>;
      allow write: if <condition>;
    }
  }
}

כל הצהרות ההתאמה מפנות לקבצים. משפט התאמה יכול להפנות לקובץ ספציפי, כמו match /images/profilePhoto.png.

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

בנוסף להפניה לקובץ יחיד, אפשר להשתמש ב-Rules עם תווים כלליים לחיפוש כדי להפנות לכל קובץ עם קידומת מחרוזת נתונה בשם שלו, כולל קווים נטויים, כמו ב-match /images/{imageId}.

בדוגמה שלמעלה, משפט ההתאמה משתמש בתחביר של תו המשתנה הלא ידוע {imageId}. כלומר, הכלל חל על כל קובץ ש-/images/ מופיע בתחילת השם שלו, כמו /images/profilePhoto.png או /images/croppedProfilePhoto.png. כשמבצעים הערכה של הביטויים allow בהצהרת ההתאמה, המשתנה imageId יתורגם לשם קובץ התמונה, למשל profilePhoto.png או croppedProfilePhoto.png.

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

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

נתונים היררכיים

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

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

service firebase.storage {
  match /b/{bucket}/o {
    match /images/{imageId} {
      allow read, write: if <condition>;
    }

    // Explicitly define rules for the 'mp3s' pattern
    match /mp3s/{mp3Id} {
      allow read, write: if <condition>;
    }
  }
}

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

service firebase.storage {
  match /b/{bucket}/o {
    match /images {
      // Exact match for "images/profilePhoto.png"
      match /profilePhoto.png {
        allow write: if <condition>;
      }
    }
  }
}
service firebase.storage {
  match /b/{bucket}/o {
    // Exact match for "images/profilePhoto.png"
    match /images/profilePhoto.png {
      allow write: if <condition>;
      }
  }
}

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

בנוסף לתווים כלליים לחיפוש שתואמים למחרוזות בסוף שם הקובץ ומחזירים אותן, אפשר להצהיר על תו כללי לחיפוש עם כמה קטעים להתאמה מורכבת יותר. לשם כך, מוסיפים את הערך =** לשם של תו הכללי לחיפוש, כמו {path=**}:

// Partial match for files that start with "images"
match /images {

  // 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.

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

גרסה 1

Firebase Security Rules משתמשים בגרסה 1 כברירת מחדל. בגרסה 1, תווים כלליים רפלקסיביים תואמים לרכיב אחד או יותר של שם הקובץ, ולא לאפס רכיבים או יותר. לכן, match /images/{filenamePrefixWildcard}/{imageFilename=**} תואם לשם קובץ כמו ‎ /images/profilePics/profile.png, אבל לא ל-‎ /images/badge.png. במקום זאת, אתם צריכים להשתמש ב-/images/{imagePrefixorFilename=**}.

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

מומלץ להשתמש בגרסה 2 בגלל התכונות המתקדמות יותר שלה.

גרסה 2

בגרסה 2 של Firebase Security Rules, תווים כלליים לחיפוש רסורסיביים תואמים לאפס או יותר פריטים בנתיב. לכן, הערך /images/{filenamePrefixWildcard}/{imageFilename=**} תואם לשמות הקבצים ‎ /images/profilePics/profile.png ו-‎ /images/badge.png.

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

rules_version = '2';
service cloud.storage {
  match /b/{bucket}/o {
   ...
 }
}

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

rules_version = '2';
service firebase.storage {
 match /b/{bucket}/o {
   // Matches any file in a songs "subdirectory" under the
   // top level of your Cloud Storage bucket.
   match /{prefixSegment=**}/songs/{mp3filenames} {
     allow read, write: if <condition>;
   }
  }
}

פעולות מפורטות

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

אפשר לפצל פעולת read ל-get ול-list.

אפשר לפצל כלל write ל-create, ל-update ול-delete:

service firebase.storage {
  match /b/{bucket}/o {
    // A read rule can be divided into read and list rules
    match /images/{imageId} {
      // Applies to single file read requests
      allow get: if <condition>;
      // Applies to list and listAll requests (Rules Version 2)
      allow list: if <condition>;

    // A write rule can be divided into create, update, and delete rules
    match /images/{imageId} {
      // Applies to writes to file contents
      allow create: if <condition>;

      // Applies to updates to (pre-existing) file metadata
      allow update: if <condition>;

      // Applies to delete operations
      allow delete: if <condition>;
    }
  }
 }
}

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

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

service firebase.storage {
  match b/{bucket}/o {
    // Matches file names directly inside of '/images/'.
    match /images/{imageId} {
      allow read, write: if false;
    }

    // Matches file names anywhere under `/images/`
    match /images/{imageId=**} {
      allow read, write: if true;
    }
  }
}

בדוגמה שלמעלה, כל הקריאות והכתובות בקבצים שהשם שלהם מתחיל ב-/images/ מותרות כי הכלל השני הוא תמיד true, גם כשהכלל הראשון הוא false.

כללים הם לא מסננים

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

לדוגמה, ניקח את כלל האבטחה הבא:

service firebase.storage {
  match /b/{bucket}/o {
    // Allow the client to read files with contentType 'image/png'
    match /aFileNamePrefix/{aFileName} {
      allow read: if resource.contentType == 'image/png';
    }
  }
}

נדחתה: הכלל הזה דוחה את הבקשה הבאה כי קבוצת התוצאות יכולה לכלול קבצים שבהם הערך של contentType הוא לא image/png:

אינטרנט
filesRef = storage.ref().child("aFilenamePrefix");

filesRef.listAll()
    .then(function(result) {
      console.log("Success: ", result.items);
    })
});

הכללים ב-Cloud Storage Security Rules מעריכים כל שאילתה לפי התוצאה האפשרית שלה, ומכשלים את הבקשה אם היא עלולה להחזיר קובץ שללקוח אין הרשאה לקרוא. בקשות הגישה חייבות לעמוד באילוצים שהוגדרו בכללים.

השלבים הבאים

אפשר להעמיק את ההבנה של Firebase Security Rules עבור Cloud Storage:

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

  • כדאי לעיין בתרחישים לדוגמה בתחום האבטחה ובהגדרות Firebase Security Rules שרלוונטיות להם.

אפשר לעיין בתרחישי לדוגמה של Firebase Security Rules שספציפיים ל-Cloud Storage: