استخدِم هذا الدليل للتعرّف على الثغرات الأمنية الشائعة في عمليات ضبط Firebase Security Rules، ومراجعة قواعدك وتأمينها بشكل أفضل، واختبار التغييرات قبل نشرها.
إذا تلقّيت تنبيهًا بأنّ بياناتك غير محمية بشكل صحيح، راجِع الأخطاء الشائعة التالية وعدِّل أي قواعد معرَّضة للخطر.
الوصول إلى Firebase Security Rules
للاطّلاع على Rules الحالي، استخدِم إما واجهة سطر الأوامر Firebase أو وحدة تحكّم Firebase. احرص على تعديل قواعدك باستخدام الطريقة نفسها بشكل متّسق لتجنُّب استبدال التعديلات عن طريق الخطأ. إذا لم تكن متأكدًا مما إذا كانت القواعد المحدّدة محليًا تعكس آخر التعديلات، تعرض وحدة تحكّم Firebase دائمًا الإصدار الأخير الذي تم نشره من Firebase Security Rules.
للوصول إلى قواعدك من وحدة تحكّم Firebase، اختَر مشروعك، ثم انتقِل إلى Realtime Database أو Cloud Firestore أو مساحة التخزين. انقر على القواعد بعد الانتقال إلى قاعدة البيانات أو حزمة التخزين الصحيحة.
للوصول إلى قواعدك من واجهة سطر الأوامر Firebase، انتقِل إلى ملف القواعد المذكور في ملف 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 cascade، مع قواعد في مسارات أصلية أكثر سطحية تتجاوز القواعد في عقد تابعة أعمق. عند كتابة قاعدة في عقدة فرعية، تذكَّر أنّه لا يمكنها منح امتيازات إضافية إلا. لا يمكنك تحسين أو إبطال إذن الوصول إلى البيانات في مسار أعمق في قاعدة البيانات.
غير محبَّذ: تحسين القواعد في مسارات العناصر التابعة
{ "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 و"وظائف السحابة الإلكترونية" الوصول إلى قاعدة البيانات. استخدِم هذه القواعد عندما تريد استخدام Cloud Firestore أو Realtime Database كخادم خلفي فقط بالتزامن مع حزمة Firebase Admin SDK. على الرغم من أنّها آمنة، عليك اختبار ما إذا كان بإمكان عملاء تطبيقك استرداد البيانات بشكل سليم.
يمكنك الاطّلاع على مزيد من المعلومات حول Cloud Firestore Security Rules وطريقة عملها في مقالة كيفية بدء استخدام Cloud Firestore Security Rules.
اختبار Cloud Firestore Security Rules
للتحقّق من سلوك تطبيقك والتأكّد من صحة إعدادات Cloud Firestore Security Rules، استخدِم محاكي Firebase. استخدِم Cloud Firestoreالمحاكي لتشغيل اختبارات الوحدات وأتمتتها في بيئة محلية قبل نشر أي تغييرات.
للتحقّق بسرعة من صحة Firebase Security Rules في وحدة تحكّم Firebase، استخدِم محاكي قواعد Firebase.