استخدِم هذا الدليل للتعرّف على الثغرات الشائعة في إعدادات Firebase Security Rules ومراجعة قواعدك وتأمينها بشكلٍ أفضل، واختبار التغييرات قبل نشرها.
إذا تلقّيت تنبيهًا يفيد بأنّ بياناتك غير آمنة بشكلٍ صحيح، راجِع هذه الأخطاء الشائعة وعدِّل أي قواعد معرّضة للاختراق.
الوصول إلى Firebase Security Rules
للاطّلاع على Rules الحالية، استخدِم إما واجهة سطر أوامر Firebase أو وحدة تحكّم Firebase. احرص على تعديل القواعد باستخدام الطريقة نفسها باستمرار لتجنّب استبدال التعديلات عن طريق الخطأ. إذا لم تكن متأكّدًا مما إذا كانت القواعد المحدّدة محليًا تعكس آخر التعديلات، تعرض وحدة التحكّم في Firebase دائمًا أحدث إصدار تم نشره من Firebase Security Rules.
للوصول إلى قواعدك من وحدة تحكّم Firebase، اختَر مشروعك، ثم انتقِل إلى Realtime Database أو Cloud Firestore أو مساحة التخزين. انقر على القواعد بعد الوصول إلى قاعدة البيانات أو ملف التخزين الصحيحَين.
للوصول إلى قواعدك من Firebase CLI، انتقِل إلىملف rules المُشار إليه في ملف firebase.json.
فهم Firebase Security Rules
Firebase Security Rules حماية بياناتك من المستخدمين الضارّين عند إنشاء مثيل قاعدة بيانات أو حزمة Cloud Storage في وحدة تحكّم Firebase، يمكنك اختيار إما رفض الوصول إلى جميع المستخدمين (الوضع المُقفَل) أو منح إذن الوصول إلى جميع المستخدمين (الوضع التجريبي). على الرغم من أنّك قد تحتاج إلى إعدادات أكثر انفتاحًا أثناء مرحلة تطوير التطبيق، احرص على تخصيص الوقت لضبط القواعد بشكل صحيح وتأمين بياناتك قبل نشر التطبيق.
أثناء تطوير تطبيقك واختبار إعدادات مختلفة لقواعدك، استخدِم أحد محاكيات Firebase المحلية لتشغيل تطبيقك في بيئة تطوير محلية.
السيناريوهات الشائعة للقواعد غير الآمنة
يجب مراجعة وتعديل Rules الذي ربما تكون قد أعددته تلقائيًا أو أثناء عملك في البداية على تطوير تطبيقك، وذلك قبل نشر تطبيقك. تأكَّد من تأمين بيانات المستخدمين بشكلٍ سليم من خلال تجنُّب الأخطاء الشائعة التالية.
الوصول المفتوح
أثناء إعداد مشروعك على Firebase، ربما تكون قد أعددت قواعدك للسماح بالوصول المفتوح أثناء التطوير. قد تعتقد أنّك المستخدم الوحيد لتطبيقك، ولكن إذا كنت قد طرحته، سيكون متاحًا على الإنترنت. إذا لم تكن تتم مصادقة المستخدمين وضبط قواعد الأمان، يمكن لأي شخص يخمن رقم تعريف مشروعك سرقة البيانات أو تعديلها أو حذفها.
غير مستحسن: إذن بالقراءة والكتابة
لجميع المستخدمين
// Allow read/write access to all users under any conditions // Warning: **NEVER** use this ruleset in production; it allows // anyone to overwrite your entire database. service cloud.firestore { match /databases/{database}/documents { match /{document=**} { allow read, write: if true; } } } { // Allow read/write access to all users under any conditions // Warning: **NEVER** use this ruleset in production; it allows // anyone to overwrite your entire database. "rules": { ".read": true, ".write": true } } // Anyone can read or write to the bucket, even non-users of your app. // Because it is shared with App Engine, this will also make // files uploaded using App Engine public. // Warning: This rule makes every file in your Cloud Storage bucket accessible to any user. // Apply caution before using it in production, since it means anyone // can overwrite all your files. service firebase.storage { match /b/{bucket}/o { match /{allPaths=**} { allow read, write; } } } |
الحل: القواعد التي تحدّ من الوصول إلى القراءة
والكتابة
أنشئ قواعد منطقية للتسلسل الهرمي لبياناتك. ومن بين الحلول الشائعة لمعالجة هذا النقص في الأمان، الأمان المستنِد إلى المستخدم باستخدام Firebase Authentication. مزيد من المعلومات عن مصادقة المستخدمين باستخدام القواعد مالك المحتوى فقطservice cloud.firestore { match /databases/{database}/documents { // Allow only authenticated content owners access match /some_collection/{document} { // Allow reads and deletion if the current user owns the existing document allow read, delete: if request.auth.uid == resource.data.author_uid; // Allow creation if the current user owns the new document allow create: if request.auth.uid == request.resource.data.author_uid; // Allow updates by the owner, and prevent change of ownership allow update: if request.auth.uid == request.resource.data.author_uid && request.auth.uid == resource.data.author_uid; } } } أذونات وصول مختلطة عامة وخاصةservice cloud.firestore { match /databases/{database}/documents { // Allow public read access, but only content owners can write match /some_collection/{document} { // Allow public reads allow read: if true // Allow creation if the current user owns the new document allow create: if request.auth.uid == request.resource.data.author_uid; // Allow updates by the owner, and prevent change of ownership allow update: if request.auth.uid == request.resource.data.author_uid && request.auth.uid == resource.data.author_uid; // Allow deletion if the current user owns the existing document allow delete: if request.auth.uid == resource.data.author_uid; } } } مالك المحتوى فقط{ "rules": { "some_path": { "$uid": { // Allow only authenticated content owners access to their data ".read": "auth !== null && auth.uid === $uid", ".write": "auth !== null && auth.uid === $uid" } } } } أذونات وصول مختلطة عامة وخاصة{ // Allow anyone to read data, but only authenticated content owners can // make changes to their data "rules": { "some_path/$uid": { ".read": true, // or ".read": "auth.uid !== null" for only authenticated users ".write": "auth.uid === $uid" } } } مالك المحتوى فقط// Grants a user access to a node matching their user ID service firebase.storage { match /b/{bucket}/o { // Files look like: "user/<UID>/file.txt" match /user/{userId}/{fileName} { allow read, write: if request.auth.uid == userId; } } } أذونات وصول مختلطة عامة وخاصةservice firebase.storage { match /b/{bucket}/o { // Files look like: "user/<UID>/file.txt" match /user/{userId}/{fileName} { allow read; allow write: if request.auth.uid == userId; } } } |
إمكانية الوصول لأي مستخدم تمّت مصادقته
في بعض الأحيان، يتحقّق Rules من تسجيل دخول المستخدم، ولكن لا يفرض المزيد من
قيود الوصول استنادًا إلى عملية المصادقة هذه. إذا كانت إحدى قواعدك تتضمّن
auth != null
، تأكَّد من أنّك تريد أن يتمكّن أي مستخدم سجّل الدخول من الوصول إلى
البيانات.
غير مستحسن: يحصل أي مستخدم سجّل الدخول على إذن بالقراءة
والكتابة في قاعدة بياناتك بالكامل.
service cloud.firestore { match /databases/{database}/documents { match /some_collection/{document} { allow read, write: if request.auth.uid != null; } } } { "rules": { ".read": "auth.uid !== null", ".write": "auth.uid !== null" } } // Only authenticated users can read or write to the bucket service firebase.storage { match /b/{bucket}/o { match /{allPaths=**} { allow read, write: if request.auth != null; } } } |
الحلّ: يمكنك تضييق نطاق الوصول باستخدام شروط
الأمان.
عند التحقّق من المصادقة، قد تحتاج أيضًا إلى استخدام إحدى سمات المصادقة لفرض مزيد من القيود على الوصول إلى مستخدمين معيّنين لمجموعات بيانات معيّنة. مزيد من المعلومات حول خصائص المصادقة المختلفة الوصول المستنِد إلى الدورservice cloud.firestore { match /databases/{database}/documents { // Assign roles to all users and refine access based on user roles match /some_collection/{document} { allow read: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == "Reader" allow write: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == "Writer" // Note: Checking for roles in your database using `get` (as in the code // above) or `exists` carry standard charges for read operations. } } } الوصول المستنِد إلى السمات// Give each user in your database a particular attribute // and set it to true/false // Then, use that attribute to grant access to subsets of data // For example, an "administrator" attribute set // to "true" grants write access to data service cloud.firestore { match /databases/{database}/documents { match /some_collection/{document} { allow write: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true; allow read: true; } } } أذونات وصول مختلطة عامة وخاصةservice cloud.firestore { match /databases/{database}/documents { // Allow public read access, but only content owners can write match /some_collection/{document} { allow read: if true allow write: if request.auth.uid == request.resource.data.author_uid } } } مالك المحتوى فقط{ "rules": { "some_path": { "$uid": { // Allow only authenticated content owners access to their data ".read": "auth.uid === $uid", ".write": "auth.uid === $uid" } } } } الوصول المحدَّد بالمسار{ "rules": { "some_path/$uid": { ".write": "auth.uid === $uid", // Create a "public" subpath in your dataset "public": { ".read": true // or ".read": "auth.uid !== null" }, // Create a "private" subpath in your dataset "private": { ".read": "auth.uid === $uid" } } } } أذونات وصول مختلطة عامة وخاصة{ // Allow anyone to read data, but only authenticated content owners can // make changes to their data "rules": { "some_path/$uid": { ".read": true, // or ".read": "auth.uid !== null" for only authenticated users ".write": "auth.uid === $uid" } } } الوصول المستنِد إلى المجموعة// Allow reads if the group ID in your token matches the file metadata `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; } مالك المحتوى فقط// Grants a user access to a node matching their user ID service firebase.storage { match /b/{bucket}/o { // Files look like: "user/<UID>/file.txt" match /user/{userId}/{fileName} { allow read, write: if request.auth.uid == userId; } } } أذونات وصول مختلطة عامة وخاصةservice firebase.storage { match /b/{bucket}/o { // Files look like: "user/<UID>/file.txt" match /user/{userId}/{fileName} { allow read; allow write: if request.auth.uid == userId; } } } |
(Realtime Database) القواعد المكتسَبة بشكل غير صحيح
Realtime Database Security Rules التسلسل، مع إلغاء القواعد في مسارات العناصر الرئيسية الأقل عمقًا للقواعد في العقد الفرعية الأكثر عمقًا عند كتابة قاعدة في عقدة فرعية، تذكَّر أنّه لا يمكنها منح سوى امتيازات إضافية. لا يمكنك تحسين أو سحب إذن الوصول إلى البيانات في مسار أعمق في قاعدة بياناتك.
غير مُستحسَن: تحسين القواعد في مسارات العناصر الفرعية
{ "rules": { "foo": { // allows read to /foo/* ".read": "data.child('baz').val() === true", "bar": { /* ignored, since read was allowed already */ ".read": false } } } } |
الحلّ: اكتب قواعد في مسارات العناصر الرئيسية تكون واسعة النطاق، وامنح امتيازات أكثر تحديدًا في مسارات العناصر الفرعية إذا كانت احتياجات الوصول إلى البيانات تتطلّب مزيدًا من الدقة، حافظ على دقة قواعدك. اطّلِع على مزيد من المعلومات عن التسلسل الهرمي لـ Realtime Database Security Rules في البنية الأساسية لـ Realtime Database Security Rules. |
الوصول المغلق
أثناء تطوير تطبيقك، من الأساليب الشائعة الأخرى إبقاء بياناتك مقفلة. يعني ذلك عادةً أنّك أوقفت إمكانية قراءة وتعديل الملف لدى جميع المستخدمين، على النحو التالي:
// Deny read/write access to all users under any conditions service cloud.firestore { match /databases/{database}/documents { match /{document=**} { allow read, write: if false; } } }
{ "rules": { ".read": false, ".write": false } }
// Access to files through Cloud Storage is completely disallowed. // Files may still be accessible through App Engine or Google Cloud Storage APIs. service firebase.storage { match /b/{bucket}/o { match /{allPaths=**} { allow read, write: if false; } } }
سيظل بإمكان حِزم تطوير البرامج (SDK) الخاصة بمشرفي Firebase و"وظائف Firebase السحابية" الوصول إلى قاعدة بياناتك. استخدِم هذه القواعد عندما تريد استخدام Cloud Firestore أو Realtime Database كخلفية للخوادم فقط مع "حزمة تطوير البرامج (SDK) لخدمة Firebase Admin". على الرغم من أنّه آمن، يجب اختبار إمكانية استرداد العملاء لبيانات تطبيقك بشكلٍ صحيح.
اطّلِع على مزيد من المعلومات حول Cloud Firestore Security Rules وطريقة عملها في مقالة البدء في استخدام Cloud Firestore Security Rules.
اختبار Cloud Firestore Security Rules
للتحقّق من سلوك تطبيقك والتأكّد من إعدادات Cloud Firestore Security Rules، استخدِم محاكي Firebase. استخدِم Cloud Firestore المحاكي لتشغيل اختبارات الوحدة وأتمتة هذه الاختبارات في بيئة محلية قبل نشر أي تغييرات.
للتحقّق بسرعة من Firebase Security Rules في وحدة تحكّم Firebase، استخدِم محاكي قواعد Firebase.