תנאי הכתיבה לכללי האבטחה של Cloud Firestore

המדריך הזה מבוסס על המדריך למבנה כללי האבטחה כדי להראות איך להוסיף תנאים לCloud Firestore Security Rules. אם אתם לא מכירים את העקרונות הבסיסיים של Cloud Firestore Security Rules במאמר איך מתחילים? מותאמת אישית.

אבן הבניין הראשית של Cloud Firestore Security Rules היא התנאי. א' הוא ביטוי בוליאני שקובע אם פעולה מסוימת מותר או לדחות. משתמשים בכללי אבטחה כדי לכתוב תנאים לבדוק אימות משתמשים, לאמת נתונים נכנסים או אפילו לגשת לחלקים אחרים מסד הנתונים.

אימות

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

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to access documents in the "cities" collection
    // only if they are authenticated.
    match /cities/{city} {
      allow read, write: if request.auth != null;
    }
  }
}

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

service cloud.firestore {
  match /databases/{database}/documents {
    // Make sure the uid of the requesting user matches name of the user
    // document. The wildcard expression {userId} makes the userId variable
    // available in rules.
    match /users/{userId} {
      allow read, update, delete: if request.auth != null && request.auth.uid == userId;
      allow create: if request.auth != null;
    }
  }
}

אם באפליקציה שלכם נעשה שימוש באימות ב-Firebase או ב-Google Cloud Identity Platform, המשתנה request.auth מכיל את פרטי האימות של הלקוח שמבקש את הנתונים. מידע נוסף על request.auth זמין במסמכי העזרה.

אימות נתונים

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

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to read data if the document has the 'visibility'
    // field set to 'public'
    match /cities/{city} {
      allow read: if resource.data.visibility == 'public';
    }
  }
}

המשתנה resource מתייחס למסמך המבוקש, והמשתנה resource.data הוא מפה של כל השדות והערכים השמורים במסמך. לקבלת מידע נוסף מידע על המשתנה resource, ראו מקור המידע תיעוד.

כשכותבים נתונים, מומלץ להשוות נתונים נכנסים לנתונים קיימים. במקרה כזה, אם כללי המדיניות מאפשרים את הכתיבה בהמתנה, המשתנה request.resource מכיל את המצב העתידי של המסמך. בפעולות update שמשנה רק קבוצת משנה של שדות המסמך, המשתנה request.resource יכיל את מצב המסמך בהמתנה אחרי הפעולה. אפשר לבדוק את השדה ערכים ב-request.resource כדי למנוע עדכונים לא רצויים או לא עקביים של נתונים:

service cloud.firestore {
  match /databases/{database}/documents {
    // Make sure all cities have a positive population and
    // the name is not changed
    match /cities/{city} {
      allow update: if request.resource.data.population > 0
                    && request.resource.data.name == resource.data.name;
    }
  }
}

גישה למסמכים אחרים

באמצעות הפונקציות get() ו-exists(), כללי האבטחה יכולים להעריך בקשות נכנסות כנגד מסמכים אחרים במסד הנתונים. הפונקציות get() ו-exists() מצפות לנתיבי מסמכים שצוינו במלואם. בזמן השימוש כדי ליצור נתיבים בשביל get() ו-exists(), צריך משתני escape באמצעות התחביר $(variable).

בדוגמה הבאה, המשתנה database נתפס באמצעות ההתאמה הצהרה match /databases/{database}/documents ומשמשת ליצירת הנתיב:

service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      // Make sure a 'users' document exists for the requesting user before
      // allowing any writes to the 'cities' collection
      allow create: if request.auth != null && exists(/databases/$(database)/documents/users/$(request.auth.uid));

      // Allow the user to delete cities if their user document has the
      // 'admin' field set to 'true'
      allow delete: if request.auth != null && get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true;
    }
  }
}

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

גישה למגבלות של שיחות

יש מגבלה על מספר הקריאות לגישה למסמך לכל הערכה של קבוצת כללים:

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

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

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

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

גישה לשיחות ולתמחור

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

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

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

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

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

service cloud.firestore {
  match /databases/{database}/documents {
    // 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 /cities/{city} {
      allow read, write: if signedInOrPublic();
    }

    match /users/{user} {
      allow read, write: if signedInOrPublic();
    }
  }
}

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

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

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

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

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to read data if the document has the 'visibility'
    // field set to 'public'
    match /cities/{city} {
      allow read: if resource.data.visibility == 'public';
    }
  }
}

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

דפי אינטרנט
db.collection("cities").get()
    .then(function(querySnapshot) {
        querySnapshot.forEach(function(doc) {
            console.log(doc.id, " => ", doc.data());
    });
});

מותר: הכלל הזה מאפשר את השאילתה הבאה כי התנאי where("visibility", "==", "public") מבטיח שקבוצת התוצאות עומדת בתנאי הכלל:

דפי אינטרנט
db.collection("cities").where("visibility", "==", "public").get()
    .then(function(querySnapshot) {
        querySnapshot.forEach(function(doc) {
            console.log(doc.id, " => ", doc.data());
        });
    });

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

השלבים הבאים