امنیت می تواند یکی از پیچیده ترین قطعات پازل توسعه اپلیکیشن باشد. در اکثر برنامهها، توسعهدهندگان باید سروری بسازند و اجرا کنند که احراز هویت (چه کسی کاربر است) و مجوز (آنچه کاربر میتواند انجام دهد) را مدیریت میکند.
Firebase Security Rules لایه میانی (سرور) را حذف می کند و به شما امکان می دهد مجوزهای مبتنی بر مسیر را برای کلاینت هایی که مستقیماً به داده های شما متصل می شوند مشخص کنید. از این راهنما برای کسب اطلاعات بیشتر در مورد نحوه اعمال قوانین در درخواست های دریافتی استفاده کنید.
یک محصول را انتخاب کنید تا در مورد قوانین آن بیشتر بدانید.
ساختار اساسی
Firebase Security Rules در Cloud Firestore و Cloud Storage از ساختار و نحو زیر استفاده می کنند:
service <<name>> {
// Match the resource path.
match <<path>> {
// Allow the request if the following conditions are true.
allow <<methods>> : if <<condition>>
}
}
مفاهیم کلیدی زیر هنگام ایجاد قوانین برای درک مهم هستند:
- Request: متد یا متدهای فراخوانی شده در دستور
allow
. اینها روشهایی هستند که شما به آنها اجازه اجرا می دهید. روش های استاندارد عبارتند از:get
،list
،create
،update
وdelete
. روشهای راحتread
وwrite
، دسترسی گسترده خواندن و نوشتن را در پایگاه داده یا مسیر ذخیرهسازی مشخص شده امکانپذیر میسازد. - Path: پایگاه داده یا محل ذخیره سازی که به عنوان یک مسیر URI نشان داده می شود.
- قانون: عبارت
allow
، که شامل شرطی است که در صورت ارزیابی صحیح، به درخواست اجازه می دهد.
قوانین امنیتی نسخه 2
از ماه می 2019، نسخه 2 قوانین امنیتی Firebase اکنون در دسترس است. نسخه 2 قوانین رفتار حروف عام بازگشتی {name=**}
را تغییر میدهد. اگر قصد استفاده از پرس و جوهای گروه مجموعه را دارید، باید از نسخه 2 استفاده کنید. شما باید با ایجاد rules_version = '2';
خط اول در قوانین امنیتی شما:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
مسیرهای منطبق
تمام عبارات تطبیق باید به اسناد اشاره کنند، نه مجموعه ها. یک عبارت مطابقت میتواند به یک سند خاص اشاره کند، مانند match /cities/SF
یا از علامتهای عام برای اشاره به هر سند در مسیر مشخص شده، مانند match /cities/{city}
استفاده کند.
در مثال، دستور تطبیق از نحو علامت {city}
استفاده می کند. این بدان معناست که این قانون برای هر سندی در مجموعه cities
، مانند /cities/SF
یا /cities/NYC
اعمال می شود. هنگامی که عبارات allow
در بیانیه تطابق ارزیابی می شوند، متغیر city
به نام سند شهر، مانند SF
یا NYC
حل می شود.
تطبیق زیر مجموعه ها
داده ها در Cloud Firestore در مجموعه هایی از اسناد سازماندهی می شوند و هر سند ممکن است سلسله مراتب را از طریق مجموعه های فرعی گسترش دهد. درک نحوه تعامل قوانین امنیتی با داده های سلسله مراتبی بسیار مهم است.
وضعیتی را در نظر بگیرید که در آن هر سند در مجموعه cities
شامل یک مجموعه فرعی landmarks
است. قوانین امنیتی فقط در مسیر منطبق اعمال می شود، بنابراین کنترل های دسترسی تعریف شده در مجموعه cities
برای زیر مجموعه landmarks
اعمال نمی شود. در عوض، قوانین صریح را برای کنترل دسترسی به مجموعههای فرعی بنویسید:
service cloud.firestore {
match /databases/{database}/documents {
match /cities/{city} {
allow read, write: if <condition>;
// Explicitly define rules for the 'landmarks' subcollection
match /landmarks/{landmark} {
allow read, write: if <condition>;
}
}
}
}
هنگام تودرتو کردن عبارات match
، مسیر بیانیه match
درونی همیشه نسبت به مسیر بیانیه match
بیرونی است. بنابراین مجموعه قوانین زیر معادل هستند:
service cloud.firestore {
match /databases/{database}/documents {
match /cities/{city} {
match /landmarks/{landmark} {
allow read, write: if <condition>;
}
}
}
}
service cloud.firestore {
match /databases/{database}/documents {
match /cities/{city}/landmarks/{landmark} {
allow read, write: if <condition>;
}
}
}
همپوشانی بیانیه های مسابقه
ممکن است یک سند با بیش از یک match
مطابقت داشته باشد. در مواردی که چندین عبارت allow
با یک درخواست مطابقت دارند، در صورتی که هر یک از شرایط true
باشد، دسترسی مجاز است:
service cloud.firestore {
match /databases/{database}/documents {
// Matches any document in the 'cities' collection.
match /cities/{city} {
allow read, write: if false;
}
// Matches any document in the 'cities' collection.
match /cities/{document} {
allow read, write: if true;
}
}
}
در مثال، همه خواندن و نوشتن در مجموعه cities
مجاز خواهند بود زیرا قانون دوم همیشه true
است، حتی اگر قانون اول همیشه false
باشد.
حروف عام بازگشتی
اگر میخواهید قوانین برای یک سلسله مراتب عمیق دلخواه اعمال شوند، از دستور عام بازگشتی، {name=**}
استفاده کنید:
service cloud.firestore {
match /databases/{database}/documents {
// Matches any document in the cities collection as well as any document
// in a subcollection.
match /cities/{document=**} {
allow read, write: if <condition>;
}
}
}
هنگام استفاده از دستور عام بازگشتی، متغیر wildcard شامل کل بخش مسیر منطبق خواهد بود، حتی اگر سند در یک زیر مجموعه عمیق تو در تو قرار داشته باشد. برای مثال، قوانین فهرست شده با سندی مطابقت دارد که در /cities/SF/landmarks/coit_tower
قرار دارد و مقدار متغیر document
SF/landmarks/coit_tower
خواهد بود.
با این حال، توجه داشته باشید که رفتار حروف عام بازگشتی به نسخه قوانین بستگی دارد.
قوانین امنیتی به طور پیش فرض از نسخه 1 استفاده می کنند. در نسخه 1، حروف عام بازگشتی با یک یا چند آیتم مسیر مطابقت دارند. آنها با یک مسیر خالی مطابقت ندارند، بنابراین match /cities/{city}/{document=**}
با اسناد موجود در زیر مجموعه ها مطابقت دارد اما در مجموعه cities
مطابقت ندارد، در حالی که match /cities/{document=**}
با هر دو سند در مجموعه cities
و زیر مجموعه ها مطابقت دارد.
نویسههای عام بازگشتی باید در انتهای یک بیانیه مسابقه بیایند.
در نسخه 2 قوانین امنیتی، حروف عام بازگشتی با صفر یا چند آیتم مسیر مطابقت دارند. match/cities/{city}/{document=**}
با اسناد موجود در هر زیر مجموعه و همچنین اسناد موجود در مجموعه cities
مطابقت دارد.
شما باید با افزودن rules_version = '2';
در بالای قوانین امنیتی شما:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Matches any document in the cities collection as well as any document
// in a subcollection.
match /cities/{city}/{document=**} {
allow read, write: if <condition>;
}
}
}
شما می توانید حداکثر یک علامت عام بازگشتی در هر عبارت مطابقت داشته باشید، اما در نسخه 2، می توانید این علامت عام را در هر جایی از بیانیه مطابقت قرار دهید. به عنوان مثال:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Matches any document in the songs collection group
match /{path=**}/songs/{song} {
allow read, write: if <condition>;
}
}
}
اگر از جستارهای گروه مجموعه استفاده می کنید، باید از نسخه 2 استفاده کنید، به ایمن سازی پرس و جوهای گروه مجموعه مراجعه کنید.
محدودیت قوانین امنیتی
همانطور که با قوانین امنیتی کار می کنید، به محدودیت های زیر توجه کنید:
محدود کنید | جزئیات |
---|---|
حداکثر تعداد فراخوانی exists() ، get() و getAfter() در هر درخواست |
تجاوز از هر یک از محدودیت ها منجر به خطای رد مجوز می شود. برخی از تماسهای دسترسی به اسناد ممکن است در حافظه پنهان باشند، و تماسهای ذخیرهشده در حافظه پنهان در محدودیتها حساب نمیشوند. |
حداکثر عمق بیانیه match تو در تو | 10 |
حداکثر طول مسیر، در بخشهای مسیر، در مجموعهای از عبارات match تودرتو مجاز است | 100 |
حداکثر تعداد متغیرهای ثبت مسیر در مجموعه ای از عبارات match تودرتو مجاز است | 20 |
حداکثر عمق فراخوانی تابع | 20 |
حداکثر تعداد آرگومان های تابع | 7 |
حداکثر تعداد اتصالات متغیر let در هر تابع | 10 |
حداکثر تعداد فراخوانی های تابع بازگشتی یا چرخه ای | 0 (مجاز نیست) |
حداکثر تعداد عبارات ارزیابی شده در هر درخواست | 1000 |
حداکثر اندازه یک مجموعه قوانین | مجموعه قوانین باید از دو محدودیت اندازه تبعیت کند:
|
ساختار اساسی
Firebase Security Rules در Cloud Firestore و Cloud Storage از ساختار و نحو زیر استفاده می کنند:
service <<name>> {
// Match the resource path.
match <<path>> {
// Allow the request if the following conditions are true.
allow <<methods>> : if <<condition>>
}
}
مفاهیم کلیدی زیر هنگام ایجاد قوانین برای درک مهم هستند:
- Request: متد یا متدهای فراخوانی شده در دستور
allow
. اینها روشهایی هستند که شما به آنها اجازه اجرا می دهید. روش های استاندارد عبارتند از:get
،list
،create
،update
وdelete
. روشهای راحتread
وwrite
، دسترسی گسترده خواندن و نوشتن را در پایگاه داده یا مسیر ذخیرهسازی مشخص شده امکانپذیر میسازد. - Path: پایگاه داده یا محل ذخیره سازی که به عنوان یک مسیر URI نشان داده می شود.
- قانون: عبارت
allow
، که شامل شرطی است که در صورت ارزیابی صحیح، به درخواست اجازه می دهد.
مسیرهای منطبق
Cloud Storage Security Rules با مسیرهای فایل مورد استفاده برای دسترسی به فایلها در Cloud Storage match
. قوانین می توانند دقیقاً با مسیرها یا مسیرهای عام match
و قوانین نیز می توانند تودرتو باشند. اگر هیچ قانون تطبیقی اجازه یک روش درخواست را نمی دهد، یا شرط به false
ارزیابی می شود، درخواست رد می شود.
مطابقت دقیق
// Exact match for "images/profilePhoto.png" match /images/profilePhoto.png { allow write: if <condition>; } // Exact match for "images/croppedProfilePhoto.png" match /images/croppedProfilePhoto.png { allow write: if <other_condition>; }
کبریت تو در تو
// Partial match for files that start with "images" match /images { // Exact match for "images/profilePhoto.png" match /profilePhoto.png { allow write: if <condition>; } // Exact match for "images/croppedProfilePhoto.png" match /croppedProfilePhoto.png { allow write: if <other_condition>; } }
منطبق با وایلد کارت
قوانین همچنین می توانند برای match
یک الگو با استفاده از حروف عام استفاده شوند. عام یک متغیر با نام است که یا یک رشته منفرد مانند profilePhoto.png
یا بخش های مسیر متعدد مانند images/profilePhoto.png
را نشان می دهد.
یک علامت عام با افزودن پرانتزهای فرفری در اطراف نام عام، مانند {string}
ایجاد میشود. با افزودن =**
به نام عام میتوان یک علامت عام بخش چندگانه، مانند {path=**}
را اعلام کرد:
// Partial match for files that start with "images" match /images { // Exact match for "images/*" // e.g. images/profilePhoto.png is matched match /{imageId} { // This rule only matches a single path segment (*) // imageId is a string that contains the specific segment matched allow read: if <condition>; } // 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
به درستی ارزیابی شود، در حالی که فایل "images/users/user:12345/profilePhoto.png" فقط مشمول نتیجه other_condition
است.
یک متغیر wildcard را می توان از داخل match
ارائه نام فایل یا مجوز مسیر ارجاع داد:
// Another way to restrict the name of a file match /images/{imageId} { allow read: if imageId == "profilePhoto.png"; }
Cloud Storage Security Rules آبشاری نمی شوند و قوانین تنها زمانی ارزیابی می شوند که مسیر درخواست با مسیری با قوانین مشخص شده مطابقت داشته باشد.
درخواست ارزیابی
بارگذاریها، بارگیریها، تغییرات فراداده، و حذفها با استفاده از request
ارسال شده به Cloud Storage ارزیابی میشوند. متغیر request
شامل مسیری است که درخواست در آن انجام می شود، زمان دریافت درخواست و مقدار resource
جدید اگر درخواست یک نوشتن باشد. هدرهای HTTP و وضعیت احراز هویت نیز گنجانده شده است.
شی request
همچنین شامل شناسه منحصر به فرد کاربر و بارگذاری Firebase Authentication در شی request.auth
است که در بخش Authentication اسناد توضیح بیشتری داده خواهد شد.
لیست کاملی از خواص در شی request
در زیر موجود است:
اموال | تایپ کنید | توضیحات |
---|---|---|
auth | نقشه<رشته، رشته> | زمانی که کاربر وارد سیستم میشود، uid ، شناسه منحصربهفرد کاربر، و token ، نقشهای از Firebase Authentication JWT را ارائه میکند. در غیر این صورت null خواهد شد. |
params | نقشه<رشته، رشته> | نقشه حاوی پارامترهای پرس و جو درخواست. |
path | مسیر | path نشان دهنده مسیری است که درخواست در آن انجام می شود. |
resource | نقشه<رشته، رشته> | مقدار منبع جدید، فقط در درخواستهای write وجود دارد. |
time | مهر زمانی | یک مهر زمانی که نشان دهنده زمان ارزیابی درخواست سرور است. |
ارزیابی منابع
هنگام ارزیابی قوانین، ممکن است بخواهید فراداده فایل در حال آپلود، دانلود، اصلاح یا حذف را نیز ارزیابی کنید. این به شما امکان میدهد قوانین پیچیده و قدرتمندی ایجاد کنید که کارهایی را انجام میدهند، مانند اینکه فقط فایلهایی با انواع محتوای خاص آپلود شوند یا فقط فایلهای بزرگتر از اندازه معین حذف شوند.
Firebase Security Rules برای Cloud Storage ابردادههای فایل را در شی resource
ارائه میکند، که شامل جفتهای کلید/مقدار از ابردادههای ظاهر شده در یک شی Cloud Storage است. این ویژگی ها را می توان در درخواست های read
یا write
برای اطمینان از یکپارچگی داده ها بررسی کرد.
در درخواستهای write
(مانند آپلود، بهروزرسانی ابرداده و حذف)، علاوه بر شی resource
، که حاوی فراداده فایل برای فایلی است که در مسیر درخواست وجود دارد، شما همچنین میتوانید از شی request.resource
استفاده کنید که حاوی زیرمجموعهای از فراداده فایل است که در صورت مجاز بودن نوشتن نوشته میشود. می توانید از این دو مقدار برای اطمینان از یکپارچگی داده ها یا اعمال محدودیت های برنامه مانند نوع یا اندازه فایل استفاده کنید.
فهرست کاملی از خواص در شی resource
موجود است:
اموال | تایپ کنید | توضیحات |
---|---|---|
name | رشته | نام کامل شی |
bucket | رشته | نام سطلی که این شی در آن قرار دارد. |
generation | بین المللی | تولید شیء Google Cloud Storage از این شی. |
metageneration | بین المللی | تولید متا شیء Google Cloud Storage از این شی. |
size | بین المللی | اندازه شی در بایت. |
timeCreated | مهر زمانی | مهر زمانی که نشان دهنده زمان ایجاد یک شی است. |
updated | مهر زمانی | مهر زمانی که نشاندهنده زمان آخرین بهروزرسانی یک شی است. |
md5Hash | رشته | هش MD5 از شی. |
crc32c | رشته | یک هش crc32c از شی. |
etag | رشته | تگ مرتبط با این شی. |
contentDisposition | رشته | محتوای محتوای مرتبط با این شی. |
contentEncoding | رشته | رمزگذاری محتوای مرتبط با این شی. |
contentLanguage | رشته | زبان محتوای مرتبط با این شی. |
contentType | رشته | نوع محتوای مرتبط با این شی. |
metadata | نقشه<رشته، رشته> | جفت کلید/مقدار متادیتای سفارشی اضافی و مشخص شده توسط توسعه دهنده. |
request.resource
شامل همه اینها به استثنای generation
, metageneration
, etag
, timeCreated
و updated
.
محدودیت های قوانین امنیتی
همانطور که با قوانین امنیتی کار می کنید، به محدودیت های زیر توجه کنید:
محدود کنید | جزئیات |
---|---|
حداکثر تعداد فراخوانی firestore.exists() و firestore.get() در هر درخواست | 2 برای درخواست های تک سند و درخواست های پرس و جو. تجاوز از این حد منجر به خطای رد مجوز می شود. تماسهای دسترسی به همان اسناد ممکن است در حافظه پنهان ذخیره شوند و تماسهای ذخیرهشده در حافظه پنهان در محدودیتها به حساب نمیآیند. |
مثال کامل
با کنار هم قرار دادن همه آنها، می توانید یک مثال کامل از قوانین برای راه حل ذخیره سازی تصویر ایجاد کنید:
service firebase.storage { match /b/{bucket}/o { match /images { // Allow write files to the path "images/*", subject to the constraints: // 1) File is less than 5MB // 2) Content type is an image // 3) Uploaded content type matches existing content type // 4) Filename (stored in imageId wildcard variable) is less than 32 characters match /{imageId} { allow read; allow write: if request.resource.size < 5 * 1024 * 1024 && request.resource.contentType.matches('image/.*') && request.resource.contentType == resource.contentType && imageId.size() < 32 } } } }
ساختار اساسی
در Realtime Database ، Firebase Security Rules از عبارات جاوا اسکریپت مانند موجود در یک سند JSON تشکیل شده است.
آنها از نحو زیر استفاده می کنند:
{
"rules": {
"<<path>>": {
// Allow the request if the condition for each method is true.
".read": <<condition>>,
".write": <<condition>>,
".validate": <<condition>>
}
}
}
سه عنصر اساسی در قانون وجود دارد:
- مسیر: محل پایگاه داده. این ساختار JSON پایگاه داده شما را منعکس می کند.
- درخواست: اینها روش هایی هستند که قانون برای اعطای دسترسی استفاده می کند. قوانین
read
وwrite
، دسترسی خواندن و نوشتن گسترده ای را اعطا می کنند، در حالی که قوانینvalidate
به عنوان یک تأیید ثانویه برای اعطای دسترسی بر اساس داده های ورودی یا موجود عمل می کنند. - شرط: شرطی که به یک درخواست اجازه می دهد در صورتی که درست ارزیابی شود.
نحوه اعمال قوانین در مسیرها
در Realtime Database ، Rules به صورت اتمی اعمال میشوند، به این معنی که قوانین در گرههای والد سطح بالاتر، قوانین را در گرههای فرزند خردتر نادیده میگیرند و قوانین در یک گره عمیقتر نمیتوانند به مسیر والد دسترسی داشته باشند. اگر قبلاً آن را برای یکی از مسیرهای والد اعطا کرده باشید، نمیتوانید دسترسی را در یک مسیر عمیقتر در ساختار پایگاه داده خود اصلاح یا لغو کنید.
قوانین زیر را در نظر بگیرید:
{ "rules": { "foo": { // allows read to /foo/* ".read": "data.child('baz').val() === true", "bar": { // ignored, since read was allowed already ".read": false } } } }
این ساختار امنیتی به /bar/
اجازه میدهد تا هر زمان که /foo/
حاوی یک baz
فرزند با مقدار true
باشد خوانده شود. قانون ".read": false
تحت /foo/bar/
در اینجا تأثیری ندارد، زیرا دسترسی را نمی توان با یک مسیر فرزند لغو کرد.
اگرچه ممکن است بلافاصله بصری به نظر نرسد، این بخش قدرتمندی از زبان قوانین است و اجازه می دهد تا امتیازات دسترسی بسیار پیچیده با حداقل تلاش اجرا شود. این به ویژه برای امنیت مبتنی بر کاربر مفید است.
با این حال، قوانین .validate
آبشاری نمی شوند. همه قوانین اعتبارسنجی باید در تمام سطوح سلسله مراتب رعایت شوند تا اجازه نوشتن داده شود.
علاوه بر این، از آنجایی که قوانین در مسیر والد اعمال نمی شوند، اگر قانونی در مکان درخواستی یا در یک مکان والد وجود نداشته باشد که اجازه دسترسی را می دهد، عملیات خواندن یا نوشتن با شکست مواجه می شود. حتی اگر هر مسیر کودک آسیبدیده قابل دسترسی باشد، خواندن در مکان والدین بهطور کامل با شکست مواجه میشود. این ساختار را در نظر بگیرید:
{ "rules": { "records": { "rec1": { ".read": true }, "rec2": { ".read": false } } } }
بدون درک اینکه قوانین به صورت اتمی ارزیابی می شوند، ممکن است به نظر برسد که واکشی مسیر /records/
rec1
برمی گرداند اما نه rec2
. با این حال، نتیجه واقعی یک خطا است:
var db = firebase.database(); db.ref("records").once("value", function(snap) { // success method is not called }, function(err) { // error callback triggered with PERMISSION_DENIED });
FIRDatabaseReference *ref = [[FIRDatabase database] reference]; [[_ref child:@"records"] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) { // success block is not called } withCancelBlock:^(NSError * _Nonnull error) { // cancel block triggered with PERMISSION_DENIED }];
var ref = FIRDatabase.database().reference() ref.child("records").observeSingleEventOfType(.Value, withBlock: { snapshot in // success block is not called }, withCancelBlock: { error in // cancel block triggered with PERMISSION_DENIED })
FirebaseDatabase database = FirebaseDatabase.getInstance(); DatabaseReference ref = database.getReference("records"); ref.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot snapshot) { // success method is not called } @Override public void onCancelled(FirebaseError firebaseError) { // error callback triggered with PERMISSION_DENIED }); });
curl https://docs-examples.firebaseio.com/rest/records/ # response returns a PERMISSION_DENIED error
از آنجایی که عملیات خواندن در /records/
اتمی است، و هیچ قانون خواندنی وجود ندارد که به همه دادههای زیر /records/
دسترسی داشته باشد، این یک خطای PERMISSION_DENIED
ایجاد میکند. اگر این قانون را در شبیه ساز امنیتی کنسول Firebase خود ارزیابی کنیم، می بینیم که عملیات خواندن رد شده است:
Attempt to read /records with auth=Success(null) / /records No .read rule allowed the operation. Read was denied.
این عملیات رد شد زیرا هیچ قانون خواندنی اجازه دسترسی به مسیر /records/
را نمی داد، اما توجه داشته باشید که قانون rec1
هرگز ارزیابی نشد زیرا در مسیر درخواستی ما نبود. برای واکشی rec1
، باید مستقیماً به آن دسترسی داشته باشیم:
var db = firebase.database(); db.ref("records/rec1").once("value", function(snap) { // SUCCESS! }, function(err) { // error callback is not called });
FIRDatabaseReference *ref = [[FIRDatabase database] reference]; [[ref child:@"records/rec1"] observeSingleEventOfType:FEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) { // SUCCESS! }];
var ref = FIRDatabase.database().reference() ref.child("records/rec1").observeSingleEventOfType(.Value, withBlock: { snapshot in // SUCCESS! })
FirebaseDatabase database = FirebaseDatabase.getInstance(); DatabaseReference ref = database.getReference("records/rec1"); ref.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot snapshot) { // SUCCESS! } @Override public void onCancelled(FirebaseError firebaseError) { // error callback is not called } });
curl https://docs-examples.firebaseio.com/rest/records/rec1 # SUCCESS!
متغیر مکان
Rules Realtime Database از یک متغیر $location
برای مطابقت با بخش های مسیر پشتیبانی می کند. از پیشوند $
در جلوی بخش مسیر خود استفاده کنید تا قانون خود را با گره های فرزند در طول مسیر مطابقت دهید.
{
"rules": {
"rooms": {
// This rule applies to any child of /rooms/, the key for each room id
// is stored inside $room_id variable for reference
"$room_id": {
"topic": {
// The room's topic can be changed if the room id has "public" in it
".write": "$room_id.contains('public')"
}
}
}
}
}
همچنین می توانید $variable
به صورت موازی با نام مسیرهای ثابت استفاده کنید.
{
"rules": {
"widget": {
// a widget can have a title or color attribute
"title": { ".validate": true },
"color": { ".validate": true },
// but no other child paths are allowed
// in this case, $other means any key excluding "title" and "color"
"$other": { ".validate": false }
}
}
}
امنیت می تواند یکی از پیچیده ترین قطعات پازل توسعه اپلیکیشن باشد. در اکثر برنامهها، توسعهدهندگان باید سروری بسازند و اجرا کنند که احراز هویت (چه کسی کاربر است) و مجوز (آنچه کاربر میتواند انجام دهد) را مدیریت میکند.
Firebase Security Rules لایه میانی (سرور) را حذف می کند و به شما امکان می دهد مجوزهای مبتنی بر مسیر را برای کلاینت هایی که مستقیماً به داده های شما متصل می شوند مشخص کنید. از این راهنما برای کسب اطلاعات بیشتر در مورد نحوه اعمال قوانین در درخواست های دریافتی استفاده کنید.
یک محصول را انتخاب کنید تا در مورد قوانین آن بیشتر بدانید.
ساختار اساسی
Firebase Security Rules در Cloud Firestore و Cloud Storage از ساختار و نحو زیر استفاده می کنند:
service <<name>> {
// Match the resource path.
match <<path>> {
// Allow the request if the following conditions are true.
allow <<methods>> : if <<condition>>
}
}
مفاهیم کلیدی زیر هنگام ایجاد قوانین برای درک مهم هستند:
- Request: متد یا متدهای فراخوانی شده در دستور
allow
. اینها روشهایی هستند که شما به آنها اجازه اجرا می دهید. روش های استاندارد عبارتند از:get
،list
،create
،update
وdelete
. روشهای راحتread
وwrite
، دسترسی گسترده خواندن و نوشتن را در پایگاه داده یا مسیر ذخیرهسازی مشخص شده امکانپذیر میسازد. - Path: پایگاه داده یا محل ذخیره سازی که به عنوان یک مسیر URI نشان داده می شود.
- قانون: عبارت
allow
، که شامل شرطی است که در صورت ارزیابی صحیح، به درخواست اجازه می دهد.
قوانین امنیتی نسخه 2
از ماه می 2019، نسخه 2 قوانین امنیتی Firebase اکنون در دسترس است. نسخه 2 قوانین رفتار حروف عام بازگشتی {name=**}
را تغییر میدهد. اگر قصد استفاده از پرس و جوهای گروه مجموعه را دارید، باید از نسخه 2 استفاده کنید. شما باید با ایجاد rules_version = '2';
خط اول در قوانین امنیتی شما:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
مسیرهای منطبق
تمام عبارات تطبیق باید به اسناد اشاره کنند، نه مجموعه ها. یک عبارت مطابقت میتواند به یک سند خاص اشاره کند، مانند match /cities/SF
یا از علامتهای عام برای اشاره به هر سند در مسیر مشخص شده، مانند match /cities/{city}
استفاده کند.
در مثال، دستور تطبیق از نحو علامت {city}
استفاده می کند. این بدان معناست که این قانون برای هر سندی در مجموعه cities
، مانند /cities/SF
یا /cities/NYC
اعمال می شود. هنگامی که عبارات allow
در بیانیه تطابق ارزیابی می شوند، متغیر city
به نام سند شهر، مانند SF
یا NYC
حل می شود.
تطبیق زیر مجموعه ها
داده ها در Cloud Firestore در مجموعه هایی از اسناد سازماندهی می شوند و هر سند ممکن است سلسله مراتب را از طریق مجموعه های فرعی گسترش دهد. درک نحوه تعامل قوانین امنیتی با داده های سلسله مراتبی بسیار مهم است.
وضعیتی را در نظر بگیرید که در آن هر سند در مجموعه cities
شامل یک مجموعه فرعی landmarks
است. قوانین امنیتی فقط در مسیر منطبق اعمال می شود، بنابراین کنترل های دسترسی تعریف شده در مجموعه cities
برای زیر مجموعه landmarks
اعمال نمی شود. در عوض، قوانین صریح را برای کنترل دسترسی به مجموعههای فرعی بنویسید:
service cloud.firestore {
match /databases/{database}/documents {
match /cities/{city} {
allow read, write: if <condition>;
// Explicitly define rules for the 'landmarks' subcollection
match /landmarks/{landmark} {
allow read, write: if <condition>;
}
}
}
}
هنگام تودرتو کردن عبارات match
، مسیر بیانیه match
درونی همیشه نسبت به مسیر بیانیه match
بیرونی است. بنابراین مجموعه قوانین زیر معادل هستند:
service cloud.firestore {
match /databases/{database}/documents {
match /cities/{city} {
match /landmarks/{landmark} {
allow read, write: if <condition>;
}
}
}
}
service cloud.firestore {
match /databases/{database}/documents {
match /cities/{city}/landmarks/{landmark} {
allow read, write: if <condition>;
}
}
}
همپوشانی بیانیه های مسابقه
ممکن است یک سند با بیش از یک match
مطابقت داشته باشد. در مواردی که چندین عبارت allow
با یک درخواست مطابقت دارند، در صورتی که هر یک از شرایط true
باشد، دسترسی مجاز است:
service cloud.firestore {
match /databases/{database}/documents {
// Matches any document in the 'cities' collection.
match /cities/{city} {
allow read, write: if false;
}
// Matches any document in the 'cities' collection.
match /cities/{document} {
allow read, write: if true;
}
}
}
در مثال، همه خواندن و نوشتن در مجموعه cities
مجاز خواهند بود زیرا قانون دوم همیشه true
است، حتی اگر قانون اول همیشه false
باشد.
حروف عام بازگشتی
اگر میخواهید قوانین برای یک سلسله مراتب عمیق دلخواه اعمال شوند، از دستور عام بازگشتی، {name=**}
استفاده کنید:
service cloud.firestore {
match /databases/{database}/documents {
// Matches any document in the cities collection as well as any document
// in a subcollection.
match /cities/{document=**} {
allow read, write: if <condition>;
}
}
}
هنگام استفاده از دستور عام بازگشتی، متغیر wildcard شامل کل بخش مسیر منطبق خواهد بود، حتی اگر سند در یک زیر مجموعه عمیق تو در تو قرار داشته باشد. برای مثال، قوانین فهرست شده با سندی مطابقت دارد که در /cities/SF/landmarks/coit_tower
قرار دارد و مقدار متغیر document
SF/landmarks/coit_tower
خواهد بود.
با این حال، توجه داشته باشید که رفتار حروف عام بازگشتی به نسخه قوانین بستگی دارد.
قوانین امنیتی به طور پیش فرض از نسخه 1 استفاده می کنند. در نسخه 1، حروف عام بازگشتی با یک یا چند آیتم مسیر مطابقت دارند. آنها با یک مسیر خالی مطابقت ندارند، بنابراین match /cities/{city}/{document=**}
با اسناد موجود در زیر مجموعه ها مطابقت دارد اما در مجموعه cities
مطابقت ندارد، در حالی که match /cities/{document=**}
با هر دو سند در مجموعه cities
و زیر مجموعه ها مطابقت دارد.
نویسههای عام بازگشتی باید در انتهای یک بیانیه مسابقه بیایند.
در نسخه 2 قوانین امنیتی، حروف عام بازگشتی با صفر یا چند آیتم مسیر مطابقت دارند. match/cities/{city}/{document=**}
با اسناد موجود در هر زیر مجموعه و همچنین اسناد موجود در مجموعه cities
مطابقت دارد.
شما باید با افزودن rules_version = '2';
در بالای قوانین امنیتی شما:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Matches any document in the cities collection as well as any document
// in a subcollection.
match /cities/{city}/{document=**} {
allow read, write: if <condition>;
}
}
}
شما می توانید حداکثر یک علامت عام بازگشتی در هر عبارت مطابقت داشته باشید، اما در نسخه 2، می توانید این علامت عام را در هر جایی از بیانیه مطابقت قرار دهید. به عنوان مثال:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Matches any document in the songs collection group
match /{path=**}/songs/{song} {
allow read, write: if <condition>;
}
}
}
اگر از جستارهای گروه مجموعه استفاده می کنید، باید از نسخه 2 استفاده کنید، به ایمن سازی پرس و جوهای گروه مجموعه مراجعه کنید.
محدودیت قوانین امنیتی
همانطور که با قوانین امنیتی کار می کنید، به محدودیت های زیر توجه کنید:
محدود کنید | جزئیات |
---|---|
حداکثر تعداد فراخوانی exists() ، get() و getAfter() در هر درخواست |
تجاوز از هر یک از محدودیت ها منجر به خطای رد مجوز می شود. برخی از تماسهای دسترسی به اسناد ممکن است در حافظه پنهان باشند، و تماسهای ذخیرهشده در حافظه پنهان در محدودیتها حساب نمیشوند. |
حداکثر عمق بیانیه match تو در تو | 10 |
حداکثر طول مسیر، در بخشهای مسیر، در مجموعهای از عبارات match تودرتو مجاز است | 100 |
حداکثر تعداد متغیرهای ثبت مسیر در مجموعه ای از عبارات match تودرتو مجاز است | 20 |
حداکثر عمق فراخوانی تابع | 20 |
حداکثر تعداد آرگومان های تابع | 7 |
حداکثر تعداد اتصالات متغیر let در هر تابع | 10 |
حداکثر تعداد فراخوانی های تابع بازگشتی یا چرخه ای | 0 (مجاز نیست) |
حداکثر تعداد عبارات ارزیابی شده در هر درخواست | 1000 |
حداکثر اندازه یک مجموعه قوانین | مجموعه قوانین باید از دو محدودیت اندازه تبعیت کند:
|
ساختار اساسی
Firebase Security Rules در Cloud Firestore و Cloud Storage از ساختار و نحو زیر استفاده می کنند:
service <<name>> {
// Match the resource path.
match <<path>> {
// Allow the request if the following conditions are true.
allow <<methods>> : if <<condition>>
}
}
مفاهیم کلیدی زیر هنگام ایجاد قوانین برای درک مهم هستند:
- Request: متد یا متدهای فراخوانی شده در دستور
allow
. اینها روشهایی هستند که شما به آنها اجازه اجرا می دهید. روش های استاندارد عبارتند از:get
،list
،create
،update
وdelete
. روشهای راحتread
وwrite
، دسترسی گسترده خواندن و نوشتن را در پایگاه داده یا مسیر ذخیرهسازی مشخص شده امکانپذیر میسازد. - Path: پایگاه داده یا محل ذخیره سازی که به عنوان یک مسیر URI نشان داده می شود.
- قانون: عبارت
allow
، که شامل شرطی است که در صورت ارزیابی صحیح، به درخواست اجازه می دهد.
مسیرهای منطبق
Cloud Storage Security Rules با مسیرهای فایل مورد استفاده برای دسترسی به فایلها در Cloud Storage match
. قوانین می توانند دقیقاً با مسیرها یا مسیرهای عام match
و قوانین نیز می توانند تودرتو باشند. اگر هیچ قانون تطبیقی اجازه یک روش درخواست را نمی دهد، یا شرط به false
ارزیابی می شود، درخواست رد می شود.
مطابقت دقیق
// Exact match for "images/profilePhoto.png" match /images/profilePhoto.png { allow write: if <condition>; } // Exact match for "images/croppedProfilePhoto.png" match /images/croppedProfilePhoto.png { allow write: if <other_condition>; }
کبریت تو در تو
// Partial match for files that start with "images" match /images { // Exact match for "images/profilePhoto.png" match /profilePhoto.png { allow write: if <condition>; } // Exact match for "images/croppedProfilePhoto.png" match /croppedProfilePhoto.png { allow write: if <other_condition>; } }
منطبق با وایلد کارت
قوانین همچنین می توانند برای match
یک الگو با استفاده از حروف عام استفاده شوند. عام یک متغیر با نام است که یا یک رشته منفرد مانند profilePhoto.png
یا بخش های مسیر متعدد مانند images/profilePhoto.png
را نشان می دهد.
یک علامت عام با افزودن پرانتزهای فرفری در اطراف نام عام، مانند {string}
ایجاد میشود. با افزودن =**
به نام عام میتوان یک علامت عام بخش چندگانه، مانند {path=**}
را اعلام کرد:
// Partial match for files that start with "images" match /images { // Exact match for "images/*" // e.g. images/profilePhoto.png is matched match /{imageId} { // This rule only matches a single path segment (*) // imageId is a string that contains the specific segment matched allow read: if <condition>; } // 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
به درستی ارزیابی شود، در حالی که فایل "images/users/user:12345/profilePhoto.png" فقط مشمول نتیجه other_condition
است.
یک متغیر wildcard را می توان از داخل match
ارائه نام فایل یا مجوز مسیر ارجاع داد:
// Another way to restrict the name of a file match /images/{imageId} { allow read: if imageId == "profilePhoto.png"; }
Cloud Storage Security Rules آبشاری نمی شوند و قوانین تنها زمانی ارزیابی می شوند که مسیر درخواست با مسیری با قوانین مشخص شده مطابقت داشته باشد.
درخواست ارزیابی
بارگذاریها، بارگیریها، تغییرات فراداده، و حذفها با استفاده از request
ارسال شده به Cloud Storage ارزیابی میشوند. متغیر request
شامل مسیری است که درخواست در آن انجام می شود، زمان دریافت درخواست و مقدار resource
جدید اگر درخواست یک نوشتن باشد. هدرهای HTTP و وضعیت احراز هویت نیز گنجانده شده است.
شی request
همچنین شامل شناسه منحصر به فرد کاربر و بارگذاری Firebase Authentication در شی request.auth
است که در بخش Authentication اسناد توضیح بیشتری داده خواهد شد.
لیست کاملی از خواص در شی request
در زیر موجود است:
اموال | تایپ کنید | توضیحات |
---|---|---|
auth | نقشه<رشته، رشته> | زمانی که کاربر وارد سیستم میشود، uid ، شناسه منحصربهفرد کاربر، و token ، نقشهای از Firebase Authentication JWT را ارائه میکند. در غیر این صورت null خواهد شد. |
params | نقشه<رشته، رشته> | نقشه حاوی پارامترهای پرس و جو درخواست. |
path | مسیر | path نشان دهنده مسیری است که درخواست در آن انجام می شود. |
resource | نقشه<رشته، رشته> | مقدار منبع جدید، فقط در درخواستهای write وجود دارد. |
time | مهر زمانی | یک مهر زمانی که نشان دهنده زمان ارزیابی درخواست سرور است. |
ارزیابی منابع
هنگام ارزیابی قوانین، ممکن است بخواهید فراداده فایل در حال آپلود، دانلود، اصلاح یا حذف را نیز ارزیابی کنید. این به شما امکان میدهد قوانین پیچیده و قدرتمندی ایجاد کنید که کارهایی را انجام میدهند، مانند اینکه فقط فایلهایی با انواع محتوای خاص آپلود شوند یا فقط فایلهای بزرگتر از اندازه معین حذف شوند.
Firebase Security Rules برای Cloud Storage ابردادههای فایل را در شی resource
ارائه میکند، که شامل جفتهای کلید/مقدار از ابردادههای ظاهر شده در یک شی Cloud Storage است. این ویژگی ها را می توان در درخواست های read
یا write
برای اطمینان از یکپارچگی داده ها بررسی کرد.
در درخواستهای write
(مانند آپلود، بهروزرسانی ابرداده و حذف)، علاوه بر شی resource
، که حاوی فراداده فایل برای فایلی است که در مسیر درخواست وجود دارد، شما همچنین میتوانید از شی request.resource
استفاده کنید که حاوی زیرمجموعهای از فراداده فایل است که در صورت مجاز بودن نوشتن نوشته میشود. می توانید از این دو مقدار برای اطمینان از یکپارچگی داده ها یا اعمال محدودیت های برنامه مانند نوع یا اندازه فایل استفاده کنید.
فهرست کاملی از خواص در شی resource
موجود است:
اموال | تایپ کنید | توضیحات |
---|---|---|
name | رشته | نام کامل شی |
bucket | رشته | نام سطلی که این شی در آن قرار دارد. |
generation | بین المللی | تولید شیء Google Cloud Storage از این شی. |
metageneration | بین المللی | تولید متا شیء Google Cloud Storage از این شی. |
size | بین المللی | اندازه شی در بایت. |
timeCreated | مهر زمانی | مهر زمانی که نشان دهنده زمان ایجاد یک شی است. |
updated | مهر زمانی | مهر زمانی که نشاندهنده زمان آخرین بهروزرسانی یک شی است. |
md5Hash | رشته | هش MD5 از شی. |
crc32c | رشته | یک هش crc32c از شی. |
etag | رشته | تگ مرتبط با این شی. |
contentDisposition | رشته | محتوای محتوای مرتبط با این شی. |
contentEncoding | رشته | رمزگذاری محتوای مرتبط با این شی. |
contentLanguage | رشته | زبان محتوای مرتبط با این شی. |
contentType | رشته | نوع محتوای مرتبط با این شی. |
metadata | نقشه<رشته، رشته> | جفت کلید/مقدار متادیتای سفارشی اضافی و مشخص شده توسط توسعه دهنده. |
request.resource
شامل همه اینها به استثنای generation
, metageneration
, etag
, timeCreated
و updated
.
محدودیت های قوانین امنیتی
همانطور که با قوانین امنیتی کار می کنید، به محدودیت های زیر توجه کنید:
محدود کنید | جزئیات |
---|---|
حداکثر تعداد فراخوانی firestore.exists() و firestore.get() در هر درخواست | 2 برای درخواست های تک سند و درخواست های پرس و جو. تجاوز از این حد منجر به خطای رد مجوز می شود. تماسهای دسترسی به همان اسناد ممکن است در حافظه پنهان ذخیره شوند و تماسهای ذخیرهشده در حافظه پنهان در محدودیتها به حساب نمیآیند. |
مثال کامل
با کنار هم قرار دادن همه آنها، می توانید یک مثال کامل از قوانین برای راه حل ذخیره سازی تصویر ایجاد کنید:
service firebase.storage { match /b/{bucket}/o { match /images { // Allow write files to the path "images/*", subject to the constraints: // 1) File is less than 5MB // 2) Content type is an image // 3) Uploaded content type matches existing content type // 4) Filename (stored in imageId wildcard variable) is less than 32 characters match /{imageId} { allow read; allow write: if request.resource.size < 5 * 1024 * 1024 && request.resource.contentType.matches('image/.*') && request.resource.contentType == resource.contentType && imageId.size() < 32 } } } }
ساختار اساسی
در Realtime Database ، Firebase Security Rules از عبارات جاوا اسکریپت مانند موجود در یک سند JSON تشکیل شده است.
آنها از نحو زیر استفاده می کنند:
{
"rules": {
"<<path>>": {
// Allow the request if the condition for each method is true.
".read": <<condition>>,
".write": <<condition>>,
".validate": <<condition>>
}
}
}
سه عنصر اساسی در قانون وجود دارد:
- مسیر: محل پایگاه داده. این ساختار JSON پایگاه داده شما را منعکس می کند.
- درخواست: اینها روش هایی هستند که قانون برای اعطای دسترسی استفاده می کند. قوانین
read
وwrite
، دسترسی خواندن و نوشتن گسترده ای را اعطا می کنند، در حالی که قوانینvalidate
به عنوان یک تأیید ثانویه برای اعطای دسترسی بر اساس داده های ورودی یا موجود عمل می کنند. - شرط: شرطی که به یک درخواست اجازه می دهد در صورتی که درست ارزیابی شود.
نحوه اعمال قوانین در مسیرها
در Realtime Database ، Rules به صورت اتمی اعمال میشوند، به این معنی که قوانین در گرههای والد سطح بالاتر، قوانین را در گرههای فرزند خردتر نادیده میگیرند و قوانین در یک گره عمیقتر نمیتوانند به مسیر والد دسترسی داشته باشند. اگر قبلاً آن را برای یکی از مسیرهای والد اعطا کرده باشید، نمیتوانید دسترسی را در یک مسیر عمیقتر در ساختار پایگاه داده خود اصلاح یا لغو کنید.
قوانین زیر را در نظر بگیرید:
{ "rules": { "foo": { // allows read to /foo/* ".read": "data.child('baz').val() === true", "bar": { // ignored, since read was allowed already ".read": false } } } }
این ساختار امنیتی به /bar/
اجازه میدهد تا هر زمان که /foo/
حاوی یک baz
فرزند با مقدار true
باشد خوانده شود. قانون ".read": false
تحت /foo/bar/
در اینجا تأثیری ندارد، زیرا دسترسی را نمی توان با یک مسیر فرزند لغو کرد.
اگرچه ممکن است بلافاصله بصری به نظر نرسد، این بخش قدرتمندی از زبان قوانین است و اجازه می دهد تا امتیازات دسترسی بسیار پیچیده با حداقل تلاش اجرا شود. این به ویژه برای امنیت مبتنی بر کاربر مفید است.
با این حال، قوانین .validate
آبشاری نمی شوند. همه قوانین اعتبارسنجی باید در تمام سطوح سلسله مراتب رعایت شوند تا اجازه نوشتن داده شود.
علاوه بر این، از آنجایی که قوانین در مسیر والد اعمال نمی شوند، اگر قانونی در مکان درخواستی یا در یک مکان والد وجود نداشته باشد که اجازه دسترسی را می دهد، عملیات خواندن یا نوشتن با شکست مواجه می شود. حتی اگر هر مسیر کودک آسیبدیده قابل دسترسی باشد، خواندن در مکان والدین بهطور کامل با شکست مواجه میشود. این ساختار را در نظر بگیرید:
{ "rules": { "records": { "rec1": { ".read": true }, "rec2": { ".read": false } } } }
بدون درک اینکه قوانین به صورت اتمی ارزیابی می شوند، ممکن است به نظر برسد که واکشی مسیر /records/
rec1
برمی گرداند اما نه rec2
. با این حال، نتیجه واقعی یک خطا است:
var db = firebase.database(); db.ref("records").once("value", function(snap) { // success method is not called }, function(err) { // error callback triggered with PERMISSION_DENIED });
FIRDatabaseReference *ref = [[FIRDatabase database] reference]; [[_ref child:@"records"] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) { // success block is not called } withCancelBlock:^(NSError * _Nonnull error) { // cancel block triggered with PERMISSION_DENIED }];
var ref = FIRDatabase.database().reference() ref.child("records").observeSingleEventOfType(.Value, withBlock: { snapshot in // success block is not called }, withCancelBlock: { error in // cancel block triggered with PERMISSION_DENIED })
FirebaseDatabase database = FirebaseDatabase.getInstance(); DatabaseReference ref = database.getReference("records"); ref.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot snapshot) { // success method is not called } @Override public void onCancelled(FirebaseError firebaseError) { // error callback triggered with PERMISSION_DENIED }); });
curl https://docs-examples.firebaseio.com/rest/records/ # response returns a PERMISSION_DENIED error
از آنجایی که عملیات خواندن در /records/
اتمی است، و هیچ قانون خواندنی وجود ندارد که به همه دادههای زیر /records/
دسترسی داشته باشد، این یک خطای PERMISSION_DENIED
ایجاد میکند. اگر این قانون را در شبیه ساز امنیتی کنسول Firebase خود ارزیابی کنیم، می بینیم که عملیات خواندن رد شده است:
Attempt to read /records with auth=Success(null) / /records No .read rule allowed the operation. Read was denied.
این عملیات رد شد زیرا هیچ قانون خواندنی اجازه دسترسی به مسیر /records/
را نمی داد، اما توجه داشته باشید که قانون rec1
هرگز ارزیابی نشد زیرا در مسیر درخواستی ما نبود. برای واکشی rec1
، باید مستقیماً به آن دسترسی داشته باشیم:
var db = firebase.database(); db.ref("records/rec1").once("value", function(snap) { // SUCCESS! }, function(err) { // error callback is not called });
FIRDatabaseReference *ref = [[FIRDatabase database] reference]; [[ref child:@"records/rec1"] observeSingleEventOfType:FEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) { // SUCCESS! }];
var ref = FIRDatabase.database().reference() ref.child("records/rec1").observeSingleEventOfType(.Value, withBlock: { snapshot in // SUCCESS! })
FirebaseDatabase database = FirebaseDatabase.getInstance(); DatabaseReference ref = database.getReference("records/rec1"); ref.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot snapshot) { // SUCCESS! } @Override public void onCancelled(FirebaseError firebaseError) { // error callback is not called } });
curl https://docs-examples.firebaseio.com/rest/records/rec1 # SUCCESS!
متغیر مکان
Rules Realtime Database از یک متغیر $location
برای مطابقت با بخش های مسیر پشتیبانی می کند. از پیشوند $
در جلوی بخش مسیر خود استفاده کنید تا قانون خود را با گره های فرزند در طول مسیر مطابقت دهید.
{
"rules": {
"rooms": {
// This rule applies to any child of /rooms/, the key for each room id
// is stored inside $room_id variable for reference
"$room_id": {
"topic": {
// The room's topic can be changed if the room id has "public" in it
".write": "$room_id.contains('public')"
}
}
}
}
}
همچنین می توانید $variable
به صورت موازی با نام مسیرهای ثابت استفاده کنید.
{
"rules": {
"widget": {
// a widget can have a title or color attribute
"title": { ".validate": true },
"color": { ".validate": true },
// but no other child paths are allowed
// in this case, $other means any key excluding "title" and "color"
"$other": { ".validate": false }
}
}
}
امنیت می تواند یکی از پیچیده ترین قطعات پازل توسعه اپلیکیشن باشد. در اکثر برنامهها، توسعهدهندگان باید سروری بسازند و اجرا کنند که احراز هویت (چه کسی کاربر است) و مجوز (آنچه کاربر میتواند انجام دهد) را مدیریت میکند.
Firebase Security Rules لایه میانی (سرور) را حذف می کند و به شما امکان می دهد مجوزهای مبتنی بر مسیر را برای کلاینت هایی که مستقیماً به داده های شما متصل می شوند مشخص کنید. از این راهنما برای کسب اطلاعات بیشتر در مورد نحوه اعمال قوانین در درخواست های دریافتی استفاده کنید.
یک محصول را انتخاب کنید تا در مورد قوانین آن بیشتر بدانید.
ساختار اساسی
Firebase Security Rules در Cloud Firestore و Cloud Storage از ساختار و نحو زیر استفاده می کنند:
service <<name>> {
// Match the resource path.
match <<path>> {
// Allow the request if the following conditions are true.
allow <<methods>> : if <<condition>>
}
}
مفاهیم کلیدی زیر هنگام ایجاد قوانین برای درک مهم هستند:
- Request: متد یا متدهای فراخوانی شده در دستور
allow
. اینها روشهایی هستند که شما به آنها اجازه اجرا می دهید. روش های استاندارد عبارتند از:get
،list
،create
،update
وdelete
. روشهای راحتread
وwrite
، دسترسی گسترده خواندن و نوشتن را در پایگاه داده یا مسیر ذخیرهسازی مشخص شده امکانپذیر میسازد. - Path: پایگاه داده یا محل ذخیره سازی که به عنوان یک مسیر URI نشان داده می شود.
- قانون: بیانیه
allow
، که شامل شرایطی است که در صورت ارزیابی صحیح ، درخواست را مجاز می کند.
قوانین امنیتی نسخه 2
از ماه مه 2019 ، نسخه 2 قوانین امنیتی Firebase اکنون در دسترس است. نسخه 2 از قوانین رفتار کارتهای وحشی بازگشتی {name=**}
را تغییر می دهد. اگر قصد دارید از نمایش داده های گروهی مجموعه استفاده کنید ، باید از نسخه 2 استفاده کنید. شما باید با ساخت rules_version = '2';
خط اول در قوانین امنیتی شما:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
مسیرهای تطبیق
تمام اظهارات مطابقت باید به اسناد اشاره کند ، نه مجموعه. یک بیانیه مسابقه می تواند به یک سند خاص اشاره کند ، مانند match /cities/SF
یا از کارتهای وحشی برای اشاره به هر سندی در مسیر مشخص شده ، مانند match /cities/{city}
استفاده کنید.
در مثال ، عبارت Match از Syntax Wildcard {city}
استفاده می کند. این بدان معنی است که این قانون در مورد هر سندی در مجموعه cities
، مانند /cities/SF
یا /cities/NYC
اعمال می شود. هنگامی که عبارات allow
در بیانیه مسابقه ارزیابی شود ، متغیر city
به نام سند شهر مانند SF
یا NYC
برطرف می شود.
تطبیق زیر مجموعه ها
داده ها در Cloud Firestore در مجموعه اسناد سازماندهی شده است و هر سند ممکن است سلسله مراتب را از طریق زیر مجموعه ها گسترش دهد. درک چگونگی تعامل قوانین امنیتی با داده های سلسله مراتبی مهم است.
وضعیتی را در نظر بگیرید که هر سند در مجموعه cities
شامل یک زیر مجموعه landmarks
است. قوانین امنیتی فقط در مسیر همسان اعمال می شود ، بنابراین کنترل های دسترسی تعریف شده در مجموعه cities
برای زیر مجموعه landmarks
اعمال نمی شوند. در عوض ، برای کنترل دسترسی به زیر مجموعه ها ، قوانین صریح را بنویسید:
service cloud.firestore {
match /databases/{database}/documents {
match /cities/{city} {
allow read, write: if <condition>;
// Explicitly define rules for the 'landmarks' subcollection
match /landmarks/{landmark} {
allow read, write: if <condition>;
}
}
}
}
هنگام اظهارات match
با لانه سازی ، مسیر بیانیه match
داخلی همیشه نسبت به مسیر بیانیه match
بیرونی است. بنابراین قوانین زیر معادل هستند:
service cloud.firestore {
match /databases/{database}/documents {
match /cities/{city} {
match /landmarks/{landmark} {
allow read, write: if <condition>;
}
}
}
}
service cloud.firestore {
match /databases/{database}/documents {
match /cities/{city}/landmarks/{landmark} {
allow read, write: if <condition>;
}
}
}
اظهارات مسابقه همپوشانی
این امکان وجود دارد که یک سند با بیش از یک جمله match
مطابقت داشته باشد. در موردی که چندین بیان allow
با یک درخواست مطابقت داشته باشد ، در صورت true
هر یک از شرایط ، دسترسی مجاز است:
service cloud.firestore {
match /databases/{database}/documents {
// Matches any document in the 'cities' collection.
match /cities/{city} {
allow read, write: if false;
}
// Matches any document in the 'cities' collection.
match /cities/{document} {
allow read, write: if true;
}
}
}
به عنوان مثال ، تمام خوانده شده و می نویسد برای مجموعه cities
مجاز خواهد بود زیرا قانون دوم همیشه true
است ، حتی اگر قانون اول همیشه false
باشد.
کارتهای وحشی بازگشتی
اگر می خواهید قوانینی برای یک سلسله مراتب عمیق خودسرانه اعمال شود ، از نحو بازگشتی Wildcard استفاده کنید ، {name=**}
:
service cloud.firestore {
match /databases/{database}/documents {
// Matches any document in the cities collection as well as any document
// in a subcollection.
match /cities/{document=**} {
allow read, write: if <condition>;
}
}
}
متغیر Wildcard هنگام استفاده از نحو Wildcard بازگشتی ، کل بخش مسیر تطبیق را شامل می شود ، حتی اگر این سند در یک زیر مجموعه عمیق توخالی قرار داشته باشد. به عنوان مثال ، قوانین ذکر شده با سندی که در /cities/SF/landmarks/coit_tower
قرار دارد مطابقت دارد و مقدار متغیر document
SF/landmarks/coit_tower
خواهد بود.
با این حال ، توجه داشته باشید که رفتار کارتهای بازگشتی بازگشتی بستگی به نسخه قوانین دارد.
قوانین امنیتی به طور پیش فرض از نسخه 1 استفاده می کنند. در نسخه 1 ، کارتهای وحشی بازگشتی با یک یا چند مورد مسیر مطابقت دارند. آنها با یک مسیر خالی مطابقت ندارند ، بنابراین match /cities/{city}/{document=**}
incomes اسناد را در زیر مجموعه ها مطابقت می دهد اما در مجموعه cities
نیست ، در حالی که match /cities/{document=**}
هر دو اسناد را در مجموعه cities
و جمع آوری مطابقت می دهد.
کارتهای وحشی بازگشتی باید در پایان بیانیه مسابقه بیایند.
در نسخه 2 قوانین امنیتی ، کارتهای وحشی بازگشتی با صفر یا بیشتر موارد مسیر مطابقت دارند. match/cities/{city}/{document=**}
اسناد را در هر زیر مجموعه و همچنین اسناد موجود در مجموعه cities
مطابقت می دهد.
شما باید با اضافه کردن rules_version = '2';
در بالای قوانین امنیتی شما:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Matches any document in the cities collection as well as any document
// in a subcollection.
match /cities/{city}/{document=**} {
allow read, write: if <condition>;
}
}
}
شما می توانید حداکثر یک کارت وحشی بازگشتی در هر بیانیه مسابقه داشته باشید ، اما در نسخه 2 می توانید این کارت وحشی را در هر نقطه از بیانیه مسابقه قرار دهید. به عنوان مثال:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Matches any document in the songs collection group
match /{path=**}/songs/{song} {
allow read, write: if <condition>;
}
}
}
اگر از نمایش داده های گروهی مجموعه استفاده می کنید ، باید از نسخه 2 استفاده کنید ، به نمایش داده های گروه جمع آوری مراجعه کنید.
محدودیت قانون امنیتی
همانطور که با قوانین امنیتی کار می کنید ، محدودیت های زیر را یادداشت کنید:
محدود کنید | جزئیات |
---|---|
حداکثر تعداد exists() ، get() و getAfter() در هر درخواست |
بیش از هر دو حد منجر به خطای مجازات مجاز می شود. برخی از تماس های دسترسی به اسناد ممکن است ذخیره شوند ، و تماس های ذخیره شده به سمت محدودیت ها حساب نمی شوند. |
حداکثر عمق بیانیه match تو در تو | 10 |
حداکثر طول مسیر ، در بخش های مسیر ، در مجموعه ای از بیانیه های match تو در تو مجاز است | 100 |
حداکثر تعداد متغیرهای ضبط مسیر مجاز در مجموعه ای از بیانیه های match تو در تو | 20 |
حداکثر عمق تماس عملکرد | 20 |
حداکثر تعداد آرگومانهای عملکرد | 7 |
حداکثر تعداد let متغیر در هر عملکرد | 10 |
حداکثر تعداد تماس های عملکردی بازگشتی یا چرخه ای | 0 (مجاز نیست) |
حداکثر تعداد عبارات ارزیابی شده در هر درخواست | 1000 |
حداکثر اندازه یک قانون | قوانین باید از محدوده دو اندازه پیروی کنند:
|
ساختار اساسی
Firebase Security Rules در Cloud Firestore و Cloud Storage از ساختار و نحو زیر استفاده می کنند:
service <<name>> {
// Match the resource path.
match <<path>> {
// Allow the request if the following conditions are true.
allow <<methods>> : if <<condition>>
}
}
مفاهیم کلیدی زیر برای درک قوانین مهم هستند:
- درخواست: روش یا روشهای فراخوانی شده در بیانیه
allow
. اینها روشهایی است که شما اجازه اجرای آن را دارید. روشهای استاندارد عبارتند از:get
،list
،create
،update
وdelete
. روشهای راحتیread
وwrite
دسترسی گسترده به خواندن و نوشتن را در پایگاه داده یا مسیر ذخیره سازی مشخص می کند. - مسیر: پایگاه داده یا محل ذخیره سازی ، به عنوان یک مسیر URI نشان داده شده است.
- قانون: بیانیه
allow
، که شامل شرایطی است که در صورت ارزیابی صحیح ، درخواست را مجاز می کند.
مسیرهای تطبیق
Cloud Storage Security Rules با مسیرهای فایل مورد استفاده برای دسترسی به پرونده ها در Cloud Storage match
. قوانین می توانند با مسیرهای دقیق یا مسیرهای کارت وحشی match
و قوانین نیز می توانند لانه شوند. اگر هیچ قانون مسابقه اجازه یک روش درخواست را نداشته باشد یا شرط آن را به false
ارزیابی کند ، درخواست رد می شود.
مطابقت دقیق
// Exact match for "images/profilePhoto.png" match /images/profilePhoto.png { allow write: if <condition>; } // Exact match for "images/croppedProfilePhoto.png" match /images/croppedProfilePhoto.png { allow write: if <other_condition>; }
مسابقات تو در تو
// Partial match for files that start with "images" match /images { // Exact match for "images/profilePhoto.png" match /profilePhoto.png { allow write: if <condition>; } // Exact match for "images/croppedProfilePhoto.png" match /croppedProfilePhoto.png { allow write: if <other_condition>; } }
مسابقات Wildcard
همچنین می توان از قوانین برای match
یک الگوی با استفاده از کارتهای وحشی استفاده کرد. Wildcard یک متغیر نامگذاری شده است که یا یک رشته واحد مانند profilePhoto.png
یا بخش های مختلف مسیر مانند images/profilePhoto.png
را نشان می دهد.
کارت وحشی با افزودن بریس های مجعد در اطراف نام کارت وحشی ، مانند {string}
ایجاد می شود. با افزودن =**
به نام Wildcard ، مانند {path=**}
: یک کارت وحشی چند قطعه را می توان اعلام کرد:
// Partial match for files that start with "images" match /images { // Exact match for "images/*" // e.g. images/profilePhoto.png is matched match /{imageId} { // This rule only matches a single path segment (*) // imageId is a string that contains the specific segment matched allow read: if <condition>; } // 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
است.
در قوانین ، پرونده "تصاویر/profilephoto.png" می تواند خوانده شود اگر condition
یا other_condition
به درستی ارزیابی شود ، در حالی که پرونده "تصاویر/کاربران/کاربر: 12345/profilephoto.png" فقط در معرض نتیجه other_condition
است.
یک متغیر کارت ویزیت را می توان از داخل match
ارجاع داد. نام پرونده یا مجوز مسیر را ارائه می دهد:
// Another way to restrict the name of a file match /images/{imageId} { allow read: if imageId == "profilePhoto.png"; }
Cloud Storage Security Rules آبشار نمی شوند ، و قوانین فقط زمانی ارزیابی می شوند که مسیر درخواست با یک مسیر با قوانین مشخص شده مطابقت داشته باشد.
درخواست ارزیابی
بارگذاری ، بارگیری ، تغییرات ابرداده و حذف با استفاده از request
ارسال شده به Cloud Storage ارزیابی می شود. متغیر request
شامل مسیری است که درخواست در آن انجام می شود ، زمان دریافت درخواست و مقدار resource
جدید در صورت درخواست است. هدرهای HTTP و وضعیت احراز هویت نیز گنجانده شده است.
شیء request
همچنین حاوی شناسه منحصر به فرد کاربر و بار تأیید Firebase Authentication در شیء request.auth
است .
لیست کاملی از خصوصیات موجود در شی request
در زیر موجود است:
اموال | تایپ کنید | توضیحات |
---|---|---|
auth | نقشه<رشته، رشته> | هنگامی که یک کاربر وارد سیستم شده است ، uid ، شناسه منحصر به فرد کاربر و token را ارائه می دهد ، نقشه ای از Firebase Authentication JWT ادعا می کند. در غیر این صورت ، null خواهد بود. |
params | نقشه<رشته، رشته> | نقشه حاوی پارامترهای پرس و جو درخواست. |
path | مسیر | path مسیری را که درخواست در آن انجام می شود ، نشان می دهد. |
resource | نقشه<رشته، رشته> | مقدار منبع جدید ، فقط در درخواست های write ارائه می شود. |
time | مهر زمانی | Timestamp نمایانگر زمان سرور است که درخواست در آن ارزیابی می شود. |
ارزیابی منابع
هنگام ارزیابی قوانین ، ممکن است بخواهید ابرداده فایل بارگذاری شده ، بارگیری ، اصلاح یا حذف را ارزیابی کنید. این امر به شما امکان می دهد قوانین پیچیده و قدرتمندی ایجاد کنید که فقط کارهایی را انجام می دهد که فقط پرونده هایی با انواع محتوای خاص را بارگذاری می کنند ، یا فقط پرونده های بزرگتر از اندازه خاص حذف می شوند.
Firebase Security Rules برای Cloud Storage ابرداده پرونده را در شیء resource
فراهم می کند ، که حاوی جفت های کلیدی/با ارزش ابرداده است که در یک شیء Cloud Storage ظاهر می شود. برای اطمینان از یکپارچگی داده ها ، این خصوصیات را می توان در درخواست های read
یا write
بازرسی کرد.
در درخواست های write
(مانند بارگذاری ، به روزرسانی های ابرداده و حذف) ، علاوه بر شیء resource
، که حاوی ابرداده فایل برای پرونده ای است که در مسیر درخواست وجود دارد ، شما همچنین توانایی استفاده از request.resource
را دارید. Resource Object ، که شامل زیر مجموعه ای از متاداتای پرونده است اگر نوشتن مجاز باشد. می توانید از این دو مقدار برای اطمینان از یکپارچگی داده یا اجرای محدودیت های برنامه مانند نوع پرونده یا اندازه استفاده کنید.
لیست کاملی از خصوصیات موجود در شیء resource
موجود است:
اموال | تایپ کنید | توضیحات |
---|---|---|
name | رشته | نام کامل شیء |
bucket | رشته | نام سطل این شیء در آن ساکن است. |
generation | بین المللی | Google Cloud Storage Object این شیء. |
metageneration | بین المللی | Google Cloud Storage Object Generation از این شی. |
size | بین المللی | اندازه شی در بایت. |
timeCreated | مهر زمانی | یک جدول زمانی که نمایانگر زمان ایجاد یک شی بود. |
updated | مهر زمانی | یک جدول زمانی که آخرین بار یک شیء به روز شده است. |
md5Hash | رشته | یک هش MD5 از شی. |
crc32c | رشته | یک هش CRC32C از شی. |
etag | رشته | اتاگ مرتبط با این شی. |
contentDisposition | رشته | تمایل به محتوای مرتبط با این شی. |
contentEncoding | رشته | رمزگذاری محتوا مرتبط با این شی. |
contentLanguage | رشته | زبان محتوای مرتبط با این شی. |
contentType | رشته | نوع محتوای مرتبط با این شی. |
metadata | نقشه<رشته، رشته> | جفت های کلید/مقدار اضافی ، توسعه دهنده ابرداده سفارشی. |
request.resource
شامل همه این موارد به استثنای generation
، metageneration
، etag
، timeCreated
و updated
.
محدودیت قوانین امنیتی
همانطور که با قوانین امنیتی کار می کنید ، محدودیت های زیر را یادداشت کنید:
محدود کنید | جزئیات |
---|---|
حداکثر تعداد firestore.exists() و firestore.get() در هر درخواست تماس | 2 برای درخواست های تک مستند و درخواست های پرس و جو. فراتر از این حد منجر به خطای انکار شده مجوز می شود. تماس های دسترسی به همان اسناد ممکن است ذخیره شوند ، و تماس های ذخیره شده به سمت محدودیت ها حساب نمی شوند. |
مثال کامل
با هم قرار دادن همه ، می توانید یک نمونه کامل از قوانین برای یک راه حل ذخیره سازی تصویر ایجاد کنید:
service firebase.storage { match /b/{bucket}/o { match /images { // Allow write files to the path "images/*", subject to the constraints: // 1) File is less than 5MB // 2) Content type is an image // 3) Uploaded content type matches existing content type // 4) Filename (stored in imageId wildcard variable) is less than 32 characters match /{imageId} { allow read; allow write: if request.resource.size < 5 * 1024 * 1024 && request.resource.contentType.matches('image/.*') && request.resource.contentType == resource.contentType && imageId.size() < 32 } } } }
ساختار اساسی
در Realtime Database ، Firebase Security Rules از عبارات مانند جاوا اسکریپت موجود در یک سند JSON تشکیل شده است.
آنها از نحو زیر استفاده می کنند:
{
"rules": {
"<<path>>": {
// Allow the request if the condition for each method is true.
".read": <<condition>>,
".write": <<condition>>,
".validate": <<condition>>
}
}
}
سه عنصر اساسی در این قاعده وجود دارد:
- مسیر: محل پایگاه داده. این ساختار JSON پایگاه داده شما را آینه می کند.
- درخواست: این روشهایی است که قانون برای دسترسی به آنها استفاده می کند. قوانین
read
وwrite
دسترسی گسترده ای را برای خواندن و نوشتن ارائه می دهد ، در حالی که قوانینvalidate
به عنوان یک تأیید ثانویه برای اعطای دسترسی بر اساس داده های ورودی یا موجود عمل می کنند. - شرط: شرایطی که در صورت ارزیابی صحیح ، درخواست را مجاز می کند.
چگونه قوانین در مسیرها اعمال می شود
در Realtime Database ، Rules به صورت اتمی اعمال می شوند ، به این معنی که قوانین در گره های والدین سطح بالاتر قوانین را در گره های کودک گرانول تر و قوانین در یک گره عمیق تر رد می کنند ، نمی توانند به مسیر والدین دسترسی پیدا کنند. اگر قبلاً آن را برای یکی از مسیرهای والدین اعطا کرده اید ، نمی توانید دسترسی را در یک مسیر عمیق تر در ساختار پایگاه داده خود اصلاح یا لغو کنید.
قوانین زیر را در نظر بگیرید:
{ "rules": { "foo": { // allows read to /foo/* ".read": "data.child('baz').val() === true", "bar": { // ignored, since read was allowed already ".read": false } } } }
این ساختار امنیتی اجازه می دهد تا از هر زمان /foo/
/bar/
یک کودک baz
ارزش true
خوانده شود. ".read": false
تحت /foo/bar/
در اینجا هیچ تاثیری ندارد ، زیرا دسترسی را نمی توان با مسیر کودک ابطال کرد.
در حالی که ممکن است بلافاصله بصری به نظر نرسد ، این بخش قدرتمندی از زبان قوانین است و اجازه می دهد تا امتیازات دسترسی بسیار پیچیده ای با حداقل تلاش انجام شود. این امر به ویژه برای امنیت مبتنی بر کاربر مفید است.
با این حال ، قوانین .validate
آبشار نیست. کلیه قوانین معتبر باید در تمام سطوح سلسله مراتب راضی شوند تا یک نوشتن مجاز باشد.
علاوه بر این ، از آنجا که قوانین در مسیر والدین اعمال نمی شوند ، در صورت عدم وجود قاعده در محل درخواست شده یا در محل والدین که دسترسی به آنها را اعطا می کند ، عملیات را بخوانید یا بنویسید. حتی اگر هر مسیر کودک آسیب دیده در دسترس باشد ، خواندن در محل والدین کاملاً از بین می رود. این ساختار را در نظر بگیرید:
{ "rules": { "records": { "rec1": { ".read": true }, "rec2": { ".read": false } } } }
بدون درک اینکه قوانین به صورت اتمی ارزیابی می شوند ، ممکن است به نظر برسد که واکشی /records/
مسیر rec1
برمی گرداند اما rec2
نیست. نتیجه واقعی ، با این حال ، یک خطا است:
var db = firebase.database(); db.ref("records").once("value", function(snap) { // success method is not called }, function(err) { // error callback triggered with PERMISSION_DENIED });
FIRDatabaseReference *ref = [[FIRDatabase database] reference]; [[_ref child:@"records"] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) { // success block is not called } withCancelBlock:^(NSError * _Nonnull error) { // cancel block triggered with PERMISSION_DENIED }];
var ref = FIRDatabase.database().reference() ref.child("records").observeSingleEventOfType(.Value, withBlock: { snapshot in // success block is not called }, withCancelBlock: { error in // cancel block triggered with PERMISSION_DENIED })
FirebaseDatabase database = FirebaseDatabase.getInstance(); DatabaseReference ref = database.getReference("records"); ref.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot snapshot) { // success method is not called } @Override public void onCancelled(FirebaseError firebaseError) { // error callback triggered with PERMISSION_DENIED }); });
curl https://docs-examples.firebaseio.com/rest/records/ # response returns a PERMISSION_DENIED error
از آنجا که عملکرد خوانده شده در /records/
اتمی است ، و هیچ قانون خوانده شده وجود ندارد که دسترسی به تمام داده های تحت /records/
را اعطا کند ، این یک خطای PERMISSION_DENIED
به وجود می آورد. اگر این قانون را در شبیه ساز امنیتی در کنسول Firebase خود ارزیابی کنیم ، می توانیم ببینیم که عملیات خواندن رد شده است:
Attempt to read /records with auth=Success(null) / /records No .read rule allowed the operation. Read was denied.
این عملیات رد شد زیرا هیچ قانون خوانده شده اجازه دسترسی به /records/
مسیر را نمی داد ، اما توجه داشته باشید که قانون برای rec1
هرگز ارزیابی نشده است زیرا در مسیری که ما درخواست کردیم نبود. برای واکشی rec1
، ما باید مستقیماً به آن دسترسی پیدا کنیم:
var db = firebase.database(); db.ref("records/rec1").once("value", function(snap) { // SUCCESS! }, function(err) { // error callback is not called });
FIRDatabaseReference *ref = [[FIRDatabase database] reference]; [[ref child:@"records/rec1"] observeSingleEventOfType:FEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) { // SUCCESS! }];
var ref = FIRDatabase.database().reference() ref.child("records/rec1").observeSingleEventOfType(.Value, withBlock: { snapshot in // SUCCESS! })
FirebaseDatabase database = FirebaseDatabase.getInstance(); DatabaseReference ref = database.getReference("records/rec1"); ref.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot snapshot) { // SUCCESS! } @Override public void onCancelled(FirebaseError firebaseError) { // error callback is not called } });
curl https://docs-examples.firebaseio.com/rest/records/rec1 # SUCCESS!
متغیر مکان
Rules Realtime Database از یک متغیر $location
برای مطابقت با بخش های مسیر پشتیبانی می کند. از پیشوند $
در مقابل بخش مسیر خود استفاده کنید تا قانون خود را با هر گره کودک در طول مسیر مطابقت دهید.
{
"rules": {
"rooms": {
// This rule applies to any child of /rooms/, the key for each room id
// is stored inside $room_id variable for reference
"$room_id": {
"topic": {
// The room's topic can be changed if the room id has "public" in it
".write": "$room_id.contains('public')"
}
}
}
}
}
همچنین می توانید از $variable
به موازات نام مسیر ثابت استفاده کنید.
{
"rules": {
"widget": {
// a widget can have a title or color attribute
"title": { ".validate": true },
"color": { ".validate": true },
// but no other child paths are allowed
// in this case, $other means any key excluding "title" and "color"
"$other": { ".validate": false }
}
}
}
امنیت می تواند یکی از پیچیده ترین قطعات معمای توسعه برنامه باشد. در اکثر برنامه ها ، توسعه دهندگان باید سرور را بسازند که تأیید هویت (چه کسی کاربر باشد) و مجوز (آنچه کاربر می تواند انجام دهد).
Firebase Security Rules لایه میانی (سرور) را حذف کرده و به شما امکان می دهد مجوزهای مبتنی بر مسیر را برای مشتریانی که مستقیماً به داده های شما متصل می شوند ، مشخص کنید. از این راهنما برای کسب اطلاعات بیشتر در مورد نحوه اعمال قوانین در درخواست های دریافتی استفاده کنید.
برای کسب اطلاعات بیشتر در مورد قوانین آن ، محصولی را انتخاب کنید.
ساختار اساسی
Firebase Security Rules در Cloud Firestore و Cloud Storage از ساختار و نحو زیر استفاده می کنند:
service <<name>> {
// Match the resource path.
match <<path>> {
// Allow the request if the following conditions are true.
allow <<methods>> : if <<condition>>
}
}
مفاهیم کلیدی زیر برای درک قوانین مهم هستند:
- درخواست: روش یا روشهای فراخوانی شده در بیانیه
allow
. اینها روشهایی است که شما اجازه اجرای آن را دارید. روشهای استاندارد عبارتند از:get
،list
،create
،update
وdelete
. روشهای راحتیread
وwrite
دسترسی گسترده به خواندن و نوشتن را در پایگاه داده یا مسیر ذخیره سازی مشخص می کند. - مسیر: پایگاه داده یا محل ذخیره سازی ، به عنوان یک مسیر URI نشان داده شده است.
- قانون: بیانیه
allow
، که شامل شرایطی است که در صورت ارزیابی صحیح ، درخواست را مجاز می کند.
قوانین امنیتی نسخه 2
از ماه مه 2019 ، نسخه 2 قوانین امنیتی Firebase اکنون در دسترس است. نسخه 2 از قوانین رفتار کارتهای وحشی بازگشتی {name=**}
را تغییر می دهد. اگر قصد دارید از نمایش داده های گروهی مجموعه استفاده کنید ، باید از نسخه 2 استفاده کنید. شما باید با ساخت rules_version = '2';
خط اول در قوانین امنیتی شما:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
مسیرهای تطبیق
تمام اظهارات مطابقت باید به اسناد اشاره کند ، نه مجموعه. یک بیانیه مسابقه می تواند به یک سند خاص اشاره کند ، مانند match /cities/SF
یا از کارتهای وحشی برای اشاره به هر سندی در مسیر مشخص شده ، مانند match /cities/{city}
استفاده کنید.
در مثال ، عبارت Match از Syntax Wildcard {city}
استفاده می کند. این بدان معنی است که این قانون در مورد هر سندی در مجموعه cities
، مانند /cities/SF
یا /cities/NYC
اعمال می شود. هنگامی که عبارات allow
در بیانیه مسابقه ارزیابی شود ، متغیر city
به نام سند شهر مانند SF
یا NYC
برطرف می شود.
تطبیق زیر مجموعه ها
داده ها در Cloud Firestore در مجموعه اسناد سازماندهی شده است و هر سند ممکن است سلسله مراتب را از طریق زیر مجموعه ها گسترش دهد. درک چگونگی تعامل قوانین امنیتی با داده های سلسله مراتبی مهم است.
وضعیتی را در نظر بگیرید که هر سند در مجموعه cities
شامل یک زیر مجموعه landmarks
است. قوانین امنیتی فقط در مسیر همسان اعمال می شود ، بنابراین کنترل های دسترسی تعریف شده در مجموعه cities
برای زیر مجموعه landmarks
اعمال نمی شوند. در عوض ، برای کنترل دسترسی به زیر مجموعه ها ، قوانین صریح را بنویسید:
service cloud.firestore {
match /databases/{database}/documents {
match /cities/{city} {
allow read, write: if <condition>;
// Explicitly define rules for the 'landmarks' subcollection
match /landmarks/{landmark} {
allow read, write: if <condition>;
}
}
}
}
هنگام اظهارات match
با لانه سازی ، مسیر بیانیه match
داخلی همیشه نسبت به مسیر بیانیه match
بیرونی است. بنابراین قوانین زیر معادل هستند:
service cloud.firestore {
match /databases/{database}/documents {
match /cities/{city} {
match /landmarks/{landmark} {
allow read, write: if <condition>;
}
}
}
}
service cloud.firestore {
match /databases/{database}/documents {
match /cities/{city}/landmarks/{landmark} {
allow read, write: if <condition>;
}
}
}
اظهارات مسابقه همپوشانی
این امکان وجود دارد که یک سند با بیش از یک جمله match
مطابقت داشته باشد. در موردی که چندین بیان allow
با یک درخواست مطابقت داشته باشد ، در صورت true
هر یک از شرایط ، دسترسی مجاز است:
service cloud.firestore {
match /databases/{database}/documents {
// Matches any document in the 'cities' collection.
match /cities/{city} {
allow read, write: if false;
}
// Matches any document in the 'cities' collection.
match /cities/{document} {
allow read, write: if true;
}
}
}
به عنوان مثال ، تمام خوانده شده و می نویسد برای مجموعه cities
مجاز خواهد بود زیرا قانون دوم همیشه true
است ، حتی اگر قانون اول همیشه false
باشد.
کارتهای وحشی بازگشتی
اگر می خواهید قوانینی برای یک سلسله مراتب عمیق خودسرانه اعمال شود ، از نحو بازگشتی Wildcard استفاده کنید ، {name=**}
:
service cloud.firestore {
match /databases/{database}/documents {
// Matches any document in the cities collection as well as any document
// in a subcollection.
match /cities/{document=**} {
allow read, write: if <condition>;
}
}
}
متغیر Wildcard هنگام استفاده از نحو Wildcard بازگشتی ، کل بخش مسیر تطبیق را شامل می شود ، حتی اگر این سند در یک زیر مجموعه عمیق توخالی قرار داشته باشد. به عنوان مثال ، قوانین ذکر شده با سندی که در /cities/SF/landmarks/coit_tower
قرار دارد مطابقت دارد و مقدار متغیر document
SF/landmarks/coit_tower
خواهد بود.
با این حال ، توجه داشته باشید که رفتار کارتهای بازگشتی بازگشتی بستگی به نسخه قوانین دارد.
قوانین امنیتی به طور پیش فرض از نسخه 1 استفاده می کنند. در نسخه 1 ، کارتهای وحشی بازگشتی با یک یا چند مورد مسیر مطابقت دارند. آنها با یک مسیر خالی مطابقت ندارند ، بنابراین match /cities/{city}/{document=**}
incomes اسناد را در زیر مجموعه ها مطابقت می دهد اما در مجموعه cities
نیست ، در حالی که match /cities/{document=**}
هر دو اسناد را در مجموعه cities
و جمع آوری مطابقت می دهد.
کارتهای وحشی بازگشتی باید در پایان بیانیه مسابقه بیایند.
در نسخه 2 قوانین امنیتی ، کارتهای وحشی بازگشتی با صفر یا بیشتر موارد مسیر مطابقت دارند. match/cities/{city}/{document=**}
اسناد را در هر زیر مجموعه و همچنین اسناد موجود در مجموعه cities
مطابقت می دهد.
شما باید با اضافه کردن rules_version = '2';
در بالای قوانین امنیتی شما:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Matches any document in the cities collection as well as any document
// in a subcollection.
match /cities/{city}/{document=**} {
allow read, write: if <condition>;
}
}
}
شما می توانید حداکثر یک کارت وحشی بازگشتی در هر بیانیه مسابقه داشته باشید ، اما در نسخه 2 می توانید این کارت وحشی را در هر نقطه از بیانیه مسابقه قرار دهید. به عنوان مثال:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Matches any document in the songs collection group
match /{path=**}/songs/{song} {
allow read, write: if <condition>;
}
}
}
اگر از نمایش داده های گروهی مجموعه استفاده می کنید ، باید از نسخه 2 استفاده کنید ، به نمایش داده های گروه جمع آوری مراجعه کنید.
محدودیت قانون امنیتی
همانطور که با قوانین امنیتی کار می کنید ، محدودیت های زیر را یادداشت کنید:
محدود کنید | جزئیات |
---|---|
حداکثر تعداد exists() ، get() و getAfter() در هر درخواست |
بیش از هر دو حد منجر به خطای مجازات مجاز می شود. برخی از تماس های دسترسی به اسناد ممکن است ذخیره شوند ، و تماس های ذخیره شده به سمت محدودیت ها حساب نمی شوند. |
حداکثر عمق بیانیه match تو در تو | 10 |
حداکثر طول مسیر ، در بخش های مسیر ، در مجموعه ای از بیانیه های match تو در تو مجاز است | 100 |
حداکثر تعداد متغیرهای ضبط مسیر مجاز در مجموعه ای از بیانیه های match تو در تو | 20 |
حداکثر عمق تماس عملکرد | 20 |
حداکثر تعداد آرگومانهای عملکرد | 7 |
حداکثر تعداد let متغیر در هر عملکرد | 10 |
حداکثر تعداد تماس های عملکردی بازگشتی یا چرخه ای | 0 (مجاز نیست) |
حداکثر تعداد عبارات ارزیابی شده در هر درخواست | 1000 |
حداکثر اندازه یک قانون | قوانین باید از محدوده دو اندازه پیروی کنند:
|
ساختار اساسی
Firebase Security Rules در Cloud Firestore و Cloud Storage از ساختار و نحو زیر استفاده می کنند:
service <<name>> {
// Match the resource path.
match <<path>> {
// Allow the request if the following conditions are true.
allow <<methods>> : if <<condition>>
}
}
مفاهیم کلیدی زیر برای درک قوانین مهم هستند:
- درخواست: روش یا روشهای فراخوانی شده در بیانیه
allow
. اینها روشهایی است که شما اجازه اجرای آن را دارید. روشهای استاندارد عبارتند از:get
،list
،create
،update
وdelete
. روشهای راحتیread
وwrite
دسترسی گسترده به خواندن و نوشتن را در پایگاه داده یا مسیر ذخیره سازی مشخص می کند. - مسیر: پایگاه داده یا محل ذخیره سازی ، به عنوان یک مسیر URI نشان داده شده است.
- قانون: بیانیه
allow
، که شامل شرایطی است که در صورت ارزیابی صحیح ، درخواست را مجاز می کند.
مسیرهای تطبیق
Cloud Storage Security Rules با مسیرهای فایل مورد استفاده برای دسترسی به پرونده ها در Cloud Storage match
. قوانین می توانند با مسیرهای دقیق یا مسیرهای کارت وحشی match
و قوانین نیز می توانند لانه شوند. اگر هیچ قانون مسابقه اجازه یک روش درخواست را نداشته باشد یا شرط آن را به false
ارزیابی کند ، درخواست رد می شود.
مطابقت دقیق
// Exact match for "images/profilePhoto.png" match /images/profilePhoto.png { allow write: if <condition>; } // Exact match for "images/croppedProfilePhoto.png" match /images/croppedProfilePhoto.png { allow write: if <other_condition>; }
مسابقات تو در تو
// Partial match for files that start with "images" match /images { // Exact match for "images/profilePhoto.png" match /profilePhoto.png { allow write: if <condition>; } // Exact match for "images/croppedProfilePhoto.png" match /croppedProfilePhoto.png { allow write: if <other_condition>; } }
مسابقات Wildcard
همچنین می توان از قوانین برای match
یک الگوی با استفاده از کارتهای وحشی استفاده کرد. Wildcard یک متغیر نامگذاری شده است که یا یک رشته واحد مانند profilePhoto.png
یا بخش های مختلف مسیر مانند images/profilePhoto.png
را نشان می دهد.
کارت وحشی با افزودن بریس های مجعد در اطراف نام کارت وحشی ، مانند {string}
ایجاد می شود. با افزودن =**
به نام Wildcard ، مانند {path=**}
: یک کارت وحشی چند قطعه را می توان اعلام کرد:
// Partial match for files that start with "images" match /images { // Exact match for "images/*" // e.g. images/profilePhoto.png is matched match /{imageId} { // This rule only matches a single path segment (*) // imageId is a string that contains the specific segment matched allow read: if <condition>; } // 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
است.
در قوانین ، پرونده "تصاویر/profilephoto.png" می تواند خوانده شود اگر condition
یا other_condition
به درستی ارزیابی شود ، در حالی که پرونده "تصاویر/کاربران/کاربر: 12345/profilephoto.png" فقط در معرض نتیجه other_condition
است.
یک متغیر کارت ویزیت را می توان از داخل match
ارجاع داد. نام پرونده یا مجوز مسیر را ارائه می دهد:
// Another way to restrict the name of a file match /images/{imageId} { allow read: if imageId == "profilePhoto.png"; }
Cloud Storage Security Rules آبشار نمی شوند ، و قوانین فقط زمانی ارزیابی می شوند که مسیر درخواست با یک مسیر با قوانین مشخص شده مطابقت داشته باشد.
درخواست ارزیابی
بارگذاری ، بارگیری ، تغییرات ابرداده و حذف با استفاده از request
ارسال شده به Cloud Storage ارزیابی می شود. متغیر request
شامل مسیری است که درخواست در آن انجام می شود ، زمان دریافت درخواست و مقدار resource
جدید در صورت درخواست است. هدرهای HTTP و وضعیت احراز هویت نیز گنجانده شده است.
شیء request
همچنین حاوی شناسه منحصر به فرد کاربر و بار تأیید Firebase Authentication در شیء request.auth
است .
لیست کاملی از خصوصیات موجود در شی request
در زیر موجود است:
اموال | تایپ کنید | توضیحات |
---|---|---|
auth | نقشه<رشته، رشته> | هنگامی که یک کاربر وارد سیستم شده است ، uid ، شناسه منحصر به فرد کاربر و token را ارائه می دهد ، نقشه ای از Firebase Authentication JWT ادعا می کند. در غیر این صورت ، null خواهد بود. |
params | نقشه<رشته، رشته> | نقشه حاوی پارامترهای پرس و جو درخواست. |
path | مسیر | path مسیری را که درخواست در آن انجام می شود ، نشان می دهد. |
resource | نقشه<رشته، رشته> | مقدار منبع جدید ، فقط در درخواست های write ارائه می شود. |
time | مهر زمانی | Timestamp نمایانگر زمان سرور است که درخواست در آن ارزیابی می شود. |
ارزیابی منابع
هنگام ارزیابی قوانین ، ممکن است بخواهید ابرداده فایل بارگذاری شده ، بارگیری ، اصلاح یا حذف را ارزیابی کنید. این امر به شما امکان می دهد قوانین پیچیده و قدرتمندی ایجاد کنید که فقط کارهایی را انجام می دهد که فقط پرونده هایی با انواع محتوای خاص را بارگذاری می کنند ، یا فقط پرونده های بزرگتر از اندازه خاص حذف می شوند.
Firebase Security Rules برای Cloud Storage ابرداده پرونده را در شیء resource
فراهم می کند ، که حاوی جفت های کلیدی/با ارزش ابرداده است که در یک شیء Cloud Storage ظاهر می شود. برای اطمینان از یکپارچگی داده ها ، این خصوصیات را می توان در درخواست های read
یا write
بازرسی کرد.
در درخواست های write
(مانند بارگذاری ، به روزرسانی های ابرداده و حذف) ، علاوه بر شیء resource
، که حاوی ابرداده فایل برای پرونده ای است که در مسیر درخواست وجود دارد ، شما همچنین توانایی استفاده از request.resource
را دارید. Resource Object ، که شامل زیر مجموعه ای از متاداتای پرونده است اگر نوشتن مجاز باشد. می توانید از این دو مقدار برای اطمینان از یکپارچگی داده یا اجرای محدودیت های برنامه مانند نوع پرونده یا اندازه استفاده کنید.
لیست کاملی از خصوصیات موجود در شیء resource
موجود است:
اموال | تایپ کنید | توضیحات |
---|---|---|
name | رشته | نام کامل شیء |
bucket | رشته | نام سطل این شیء در آن ساکن است. |
generation | بین المللی | Google Cloud Storage Object این شیء. |
metageneration | بین المللی | Google Cloud Storage Object Generation از این شی. |
size | بین المللی | اندازه شی در بایت. |
timeCreated | مهر زمانی | یک جدول زمانی که نمایانگر زمان ایجاد یک شی بود. |
updated | مهر زمانی | یک جدول زمانی که آخرین بار یک شیء به روز شده است. |
md5Hash | رشته | یک هش MD5 از شی. |
crc32c | رشته | یک هش CRC32C از شی. |
etag | رشته | اتاگ مرتبط با این شی. |
contentDisposition | رشته | تمایل به محتوای مرتبط با این شی. |
contentEncoding | رشته | رمزگذاری محتوا مرتبط با این شی. |
contentLanguage | رشته | زبان محتوای مرتبط با این شی. |
contentType | رشته | نوع محتوای مرتبط با این شی. |
metadata | نقشه<رشته، رشته> | جفت های کلید/مقدار اضافی ، توسعه دهنده ابرداده سفارشی. |
request.resource
شامل همه این موارد به استثنای generation
، metageneration
، etag
، timeCreated
و updated
.
محدودیت قوانین امنیتی
همانطور که با قوانین امنیتی کار می کنید ، محدودیت های زیر را یادداشت کنید:
محدود کنید | جزئیات |
---|---|
حداکثر تعداد firestore.exists() و firestore.get() در هر درخواست تماس | 2 برای درخواست های تک مستند و درخواست های پرس و جو. فراتر از این حد منجر به خطای انکار شده مجوز می شود. تماس های دسترسی به همان اسناد ممکن است ذخیره شوند ، و تماس های ذخیره شده به سمت محدودیت ها حساب نمی شوند. |
مثال کامل
با هم قرار دادن همه ، می توانید یک نمونه کامل از قوانین برای یک راه حل ذخیره سازی تصویر ایجاد کنید:
service firebase.storage { match /b/{bucket}/o { match /images { // Allow write files to the path "images/*", subject to the constraints: // 1) File is less than 5MB // 2) Content type is an image // 3) Uploaded content type matches existing content type // 4) Filename (stored in imageId wildcard variable) is less than 32 characters match /{imageId} { allow read; allow write: if request.resource.size < 5 * 1024 * 1024 && request.resource.contentType.matches('image/.*') && request.resource.contentType == resource.contentType && imageId.size() < 32 } } } }
ساختار اساسی
در Realtime Database ، Firebase Security Rules از عبارات مانند جاوا اسکریپت موجود در یک سند JSON تشکیل شده است.
آنها از نحو زیر استفاده می کنند:
{
"rules": {
"<<path>>": {
// Allow the request if the condition for each method is true.
".read": <<condition>>,
".write": <<condition>>,
".validate": <<condition>>
}
}
}
سه عنصر اساسی در این قاعده وجود دارد:
- مسیر: محل پایگاه داده. این ساختار JSON پایگاه داده شما را آینه می کند.
- درخواست: این روشهایی است که قانون برای دسترسی به آنها استفاده می کند. قوانین
read
وwrite
دسترسی گسترده ای را برای خواندن و نوشتن ارائه می دهد ، در حالی که قوانینvalidate
به عنوان یک تأیید ثانویه برای اعطای دسترسی بر اساس داده های ورودی یا موجود عمل می کنند. - شرط: شرایطی که در صورت ارزیابی صحیح ، درخواست را مجاز می کند.
چگونه قوانین در مسیرها اعمال می شود
در Realtime Database ، Rules به صورت اتمی اعمال می شوند ، به این معنی که قوانین در گره های والدین سطح بالاتر قوانین را در گره های کودک گرانول تر و قوانین در یک گره عمیق تر رد می کنند ، نمی توانند به مسیر والدین دسترسی پیدا کنند. اگر قبلاً آن را برای یکی از مسیرهای والدین اعطا کرده اید ، نمی توانید دسترسی را در یک مسیر عمیق تر در ساختار پایگاه داده خود اصلاح یا لغو کنید.
قوانین زیر را در نظر بگیرید:
{ "rules": { "foo": { // allows read to /foo/* ".read": "data.child('baz').val() === true", "bar": { // ignored, since read was allowed already ".read": false } } } }
این ساختار امنیتی اجازه می دهد تا از هر زمان /foo/
/bar/
یک کودک baz
ارزش true
خوانده شود. ".read": false
تحت /foo/bar/
در اینجا هیچ تاثیری ندارد ، زیرا دسترسی را نمی توان با مسیر کودک ابطال کرد.
در حالی که ممکن است بلافاصله بصری به نظر نرسد ، این بخش قدرتمندی از زبان قوانین است و اجازه می دهد تا امتیازات دسترسی بسیار پیچیده ای با حداقل تلاش انجام شود. این امر به ویژه برای امنیت مبتنی بر کاربر مفید است.
با این حال ، قوانین .validate
آبشار نیست. کلیه قوانین معتبر باید در تمام سطوح سلسله مراتب راضی شوند تا یک نوشتن مجاز باشد.
علاوه بر این ، از آنجا که قوانین در مسیر والدین اعمال نمی شوند ، در صورت عدم وجود قاعده در محل درخواست شده یا در محل والدین که دسترسی به آنها را اعطا می کند ، عملیات را بخوانید یا بنویسید. حتی اگر هر مسیر کودک آسیب دیده در دسترس باشد ، خواندن در محل والدین کاملاً از بین می رود. این ساختار را در نظر بگیرید:
{ "rules": { "records": { "rec1": { ".read": true }, "rec2": { ".read": false } } } }
بدون درک اینکه قوانین به صورت اتمی ارزیابی می شوند ، ممکن است به نظر برسد که واکشی /records/
مسیر rec1
برمی گرداند اما rec2
نیست. نتیجه واقعی ، با این حال ، یک خطا است:
var db = firebase.database(); db.ref("records").once("value", function(snap) { // success method is not called }, function(err) { // error callback triggered with PERMISSION_DENIED });
FIRDatabaseReference *ref = [[FIRDatabase database] reference]; [[_ref child:@"records"] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) { // success block is not called } withCancelBlock:^(NSError * _Nonnull error) { // cancel block triggered with PERMISSION_DENIED }];
var ref = FIRDatabase.database().reference() ref.child("records").observeSingleEventOfType(.Value, withBlock: { snapshot in // success block is not called }, withCancelBlock: { error in // cancel block triggered with PERMISSION_DENIED })
FirebaseDatabase database = FirebaseDatabase.getInstance(); DatabaseReference ref = database.getReference("records"); ref.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot snapshot) { // success method is not called } @Override public void onCancelled(FirebaseError firebaseError) { // error callback triggered with PERMISSION_DENIED }); });
curl https://docs-examples.firebaseio.com/rest/records/ # response returns a PERMISSION_DENIED error
از آنجا که عملکرد خوانده شده در /records/
اتمی است ، و هیچ قانون خوانده شده وجود ندارد که دسترسی به تمام داده های تحت /records/
را اعطا کند ، این یک خطای PERMISSION_DENIED
به وجود می آورد. اگر این قانون را در شبیه ساز امنیتی در کنسول Firebase خود ارزیابی کنیم ، می توانیم ببینیم که عملیات خواندن رد شده است:
Attempt to read /records with auth=Success(null) / /records No .read rule allowed the operation. Read was denied.
این عملیات رد شد زیرا هیچ قانون خوانده شده اجازه دسترسی به /records/
مسیر را نمی داد ، اما توجه داشته باشید که قانون برای rec1
هرگز ارزیابی نشده است زیرا در مسیری که ما درخواست کردیم نبود. برای واکشی rec1
، ما باید مستقیماً به آن دسترسی پیدا کنیم:
var db = firebase.database(); db.ref("records/rec1").once("value", function(snap) { // SUCCESS! }, function(err) { // error callback is not called });
FIRDatabaseReference *ref = [[FIRDatabase database] reference]; [[ref child:@"records/rec1"] observeSingleEventOfType:FEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) { // SUCCESS! }];
var ref = FIRDatabase.database().reference() ref.child("records/rec1").observeSingleEventOfType(.Value, withBlock: { snapshot in // SUCCESS! })
FirebaseDatabase database = FirebaseDatabase.getInstance(); DatabaseReference ref = database.getReference("records/rec1"); ref.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot snapshot) { // SUCCESS! } @Override public void onCancelled(FirebaseError firebaseError) { // error callback is not called } });
curl https://docs-examples.firebaseio.com/rest/records/rec1 # SUCCESS!
متغیر مکان
Rules Realtime Database از یک متغیر $location
برای مطابقت با بخش های مسیر پشتیبانی می کند. از پیشوند $
در مقابل بخش مسیر خود استفاده کنید تا قانون خود را با هر گره کودک در طول مسیر مطابقت دهید.
{
"rules": {
"rooms": {
// This rule applies to any child of /rooms/, the key for each room id
// is stored inside $room_id variable for reference
"$room_id": {
"topic": {
// The room's topic can be changed if the room id has "public" in it
".write": "$room_id.contains('public')"
}
}
}
}
}
همچنین می توانید از $variable
به موازات نام مسیر ثابت استفاده کنید.
{
"rules": {
"widget": {
// a widget can have a title or color attribute
"title": { ".validate": true },
"color": { ".validate": true },
// but no other child paths are allowed
// in this case, $other means any key excluding "title" and "color"
"$other": { ".validate": false }
}
}
}