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

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

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

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

Realtime Database סקירה כללית על אבטחה

ב-Firebase Realtime Database יש קבוצה מלאה של כלים לניהול האבטחה של האפליקציה. בעזרת הכלים האלה קל לאמת את המשתמשים, לאכוף את הרשאות המשתמשים ולאמת את הקלט.

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

אימות

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

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

הרשאה

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

{
  "rules": {
    "foo": {
      ".read": true,
      ".write": false
    }
  }
}

הכללים .read ו-.write פועלים ברצף, כך שמערכת הכללים הזו מעניקה גישה לקריאה לכל הנתונים בנתיב /foo/ וגם לנתיבי עומק יותר, כמו /foo/bar/baz. חשוב לזכור שכללי .read ו-.write שנמצאים בחלק העליון של מסד הנתונים מבטלים כללים שנמצאים בחלק התחתון, כך שגישת קריאה ל-/foo/bar/baz עדיין תתקבל בדוגמה הזו גם אם כלל בנתיב /foo/bar/baz הוערך כ-false.

כללי האבטחה של Realtime Database כוללים משתנים מובנים ופונקציות שמאפשרות להפנות לנתיבים אחרים, לחותמות זמן בצד השרת, לפרטי אימות ועוד. זו דוגמה לכלל שמעניק למשתמשים מאומתים גישה לכתיבה ב-/users/<uid>/, כאשר <uid> הוא המזהה של המשתמש שהתקבל דרך Firebase Authentication.

{
  "rules": {
    "users": {
      "$uid": {
        ".write": "$uid === auth.uid"
      }
    }
  }
}

אימות נתונים

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

הכללים האלה אוכפים את הדרישה שהנתונים שנכתבים ב-/foo/ יהיו מחרוזת של פחות מ-100 תווים:

{
  "rules": {
    "foo": {
      ".validate": "newData.isString() && newData.val().length < 100"
    }
  }
}

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

הגדרת אינדקסים של מסדי נתונים

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

אפשר לציין את האינדקסים באמצעות הכלל .indexOn. דוגמה להצהרת אינדקס שתוסיף לאינדקס את השדות height ו-length של רשימה של דינוזאורים:

{
  "rules": {
    "dinosaurs": {
      ".indexOn": ["height", "length"]
    }
  }
}

השלבים הבאים