از شرایط در قوانین امنیتی Firebase Cloud Storage استفاده کنید

این راهنما بر اساس «یادگیری نحو اصلی» راهنمای زبان Firebase Security Rules ساخته شده است تا نحوه افزودن شرط‌ها به Firebase Security Rules برای Cloud Storage را نشان دهد.

بلوک اصلی سازنده‌ی Cloud Storage Security Rules شرط است. شرط یک عبارت بولی است که تعیین می‌کند آیا یک عملیات خاص باید مجاز یا رد شود. برای قوانین پایه، استفاده از لیترال‌های true و false به عنوان شرط کاملاً خوب عمل می‌کند. اما زبان Firebase Security Rules برای Cloud Storage ، روش‌هایی را برای نوشتن شرط‌های پیچیده‌تر ارائه می‌دهد که می‌توانند:

  • بررسی احراز هویت کاربر
  • اعتبارسنجی داده‌های ورودی

احراز هویت

Firebase Security Rules برای Cloud Storage با Firebase Authentication ادغام می‌شود تا احراز هویت قدرتمند مبتنی بر کاربر را برای Cloud Storage فراهم کند. این امر امکان کنترل دسترسی جزئی و دقیق را بر اساس ادعاهای یک توکن Firebase Authentication فراهم می‌کند.

وقتی یک کاربر احراز هویت شده درخواستی را به Cloud Storage ارسال می‌کند، متغیر request.auth با شناسه کاربری uid کاربر ( request.auth.uid ) و همچنین ادعاهای JWT Firebase Authentication ( request.auth.token ) پر می‌شود.

علاوه بر این، هنگام استفاده از احراز هویت سفارشی، ادعاهای اضافی در فیلد request.auth.token نمایش داده می‌شوند.

وقتی یک کاربر احراز هویت نشده درخواستی را انجام می‌دهد، متغیر request.auth null است.

با استفاده از این داده‌ها، چندین روش رایج برای استفاده از احراز هویت برای ایمن‌سازی فایل‌ها وجود دارد:

  • عمومی: request.auth نادیده بگیرید
  • خصوصیِ احراز هویت‌شده: بررسی کنید که request.auth null نباشد.
  • کاربر خصوصی: بررسی کنید که request.auth.uid برابر با uid مسیر باشد.
  • گروه خصوصی: ادعاهای توکن سفارشی را برای مطابقت با یک ادعای انتخاب شده بررسی کنید، یا فراداده فایل را بخوانید تا ببینید آیا فیلد فراداده‌ای وجود دارد یا خیر

عمومی

هر قانونی که زمینه request.auth را در نظر نگیرد، می‌تواند یک قانون public در نظر گرفته شود، زیرا زمینه احراز هویت کاربر را در نظر نمی‌گیرد. این قوانین می‌توانند برای نمایش داده‌های عمومی مانند دارایی‌های بازی، فایل‌های صوتی یا سایر محتوای استاتیک مفید باشند.

// Anyone to read a public image if the file is less than 100kB
// Anyone can upload a public file ending in '.txt'
match /public/{imageId} {
  allow read: if resource.size < 100 * 1024;
  allow write: if imageId.matches(".*\\.txt");
}

خصوصیِ احراز هویت‌شده

در موارد خاص، ممکن است بخواهید داده‌ها توسط همه کاربران احراز هویت شده برنامه شما قابل مشاهده باشند، اما توسط کاربران احراز هویت نشده قابل مشاهده نباشند. از آنجایی که متغیر request.auth برای همه کاربران احراز هویت نشده null است، تنها کاری که باید انجام دهید این است که بررسی کنید متغیر request.auth وجود دارد تا احراز هویت الزامی شود:

// Require authentication on all internal image reads
match /internal/{imageId} {
  allow read: if request.auth != null;
}

کاربر خصوصی

تاکنون رایج‌ترین کاربرد request.auth ، ارائه مجوزهای جزئی به کاربران در فایل‌هایشان بوده است: از آپلود تصاویر پروفایل گرفته تا خواندن اسناد خصوصی.

از آنجایی که فایل‌ها در Cloud Storage دارای یک «مسیر» کامل به فایل هستند، تنها چیزی که برای کنترل یک فایل توسط یک کاربر لازم است، یک قطعه اطلاعات منحصر به فرد و شناسایی کاربر در پیشوند نام فایل (مانند uid کاربر) است که می‌تواند هنگام ارزیابی قانون بررسی شود:

// Only a user can upload their profile picture, but anyone can view it
match /users/{userId}/profilePicture.png {
  allow read;
  allow write: if request.auth.uid == userId;
}

گروه خصوصی

یکی دیگر از موارد استفاده رایج، اعطای مجوزهای گروهی به یک شیء است، مانند اجازه دادن به چندین عضو تیم برای همکاری در یک سند مشترک. چندین رویکرد برای انجام این کار وجود دارد:

  • یک توکن سفارشی Firebase Authentication ایجاد کنید که حاوی اطلاعات اضافی در مورد اعضای گروه (مانند شناسه گروه) باشد.
  • اطلاعات گروه (مانند شناسه گروه یا فهرست uid کاربری مجاز) را در فراداده فایل قرار دهید.

پس از ذخیره این داده‌ها در توکن یا فراداده فایل، می‌توان از درون یک قانون به آن ارجاع داد:

// Allow reads if the group ID in your token matches the file metadata's `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;
}

درخواست ارزیابی

آپلودها، دانلودها، تغییرات متادیتا و حذف‌ها با استفاده از request ارسال شده به Cloud Storage ارزیابی می‌شوند. علاوه بر شناسه منحصر به فرد کاربر و بار داده Firebase Authentication در شیء request.auth همانطور که در بالا توضیح داده شد، متغیر request شامل مسیر فایلی است که درخواست در آن انجام می‌شود، زمان دریافت درخواست و مقدار resource جدید در صورتی که درخواست از نوع نوشتن باشد.

شیء request همچنین شامل شناسه منحصر به فرد کاربر و بار داده Firebase Authentication در شیء request.auth است که در بخش امنیت مبتنی بر کاربر در مستندات بیشتر توضیح داده خواهد شد.

لیست کاملی از ویژگی‌های موجود در شیء 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 رشته برچسب الکترونیکی (etag) مرتبط با این شیء.
contentDisposition رشته وضعیت محتوایی مرتبط با این شیء.
contentEncoding رشته کدگذاری محتوای مرتبط با این شیء.
contentLanguage رشته زبان محتوای مرتبط با این شیء.
contentType رشته نوع محتوای مرتبط با این شیء.
metadata نقشه<رشته، رشته> جفت‌های کلید/مقدار از فراداده‌های سفارشی اضافی و مشخص‌شده توسط توسعه‌دهنده.

request.resource شامل همه این موارد به استثنای generation ، metageneration ، etag ، timeCreated و updated .

با Cloud Firestore پیشرفت کنید

برای ارزیابی سایر معیارهای مجوز، می‌توانید به اسناد موجود در Cloud Firestore دسترسی پیدا کنید.

با استفاده از توابع firestore.get() و firestore.exists() ، قوانین امنیتی شما می‌توانند درخواست‌های ورودی را در برابر اسناد موجود در Cloud Firestore ارزیابی کنند. توابع firestore.get() و firestore.exists() هر دو انتظار مسیرهای سند کاملاً مشخص شده را دارند. هنگام استفاده از متغیرها برای ساخت مسیر برای firestore.get() و firestore.exists() ، باید با استفاده از سینتکس $(variable) به طور صریح از متغیرها escape کنید.

در مثال زیر، قاعده‌ای را می‌بینیم که دسترسی خواندن فایل‌ها را به کاربرانی که عضو باشگاه‌های خاصی هستند محدود می‌کند.

service firebase.storage {
  match /b/{bucket}/o {
    match /users/{club}/files/{fileId} {
      allow read: if club in
        firestore.get(/databases/(default)/documents/users/$(request.auth.id)).data.memberships
    }
  }
}
در مثال بعدی، فقط دوستان یک کاربر می‌توانند عکس‌های او را ببینند.
service firebase.storage {
  match /b/{bucket}/o {
    match /users/{userId}/photos/{fileId} {
      allow read: if
        firestore.exists(/databases/(default)/documents/users/$(userId)/friends/$(request.auth.id))
    }
  }
}

پس از ایجاد و ذخیره اولین Cloud Storage Security Rules خود که از این توابع Cloud Firestore استفاده می‌کنند، در کنسول Firebase یا Firebase CLI از شما خواسته می‌شود تا مجوزهای اتصال دو محصول را فعال کنید.

شما می‌توانید این ویژگی را با حذف یک نقش IAM غیرفعال کنید، همانطور که در مدیریت و استقرار Firebase Security Rules توضیح داده شده است.

اعتبارسنجی داده‌ها

Firebase Security Rules برای Cloud Storage همچنین می‌توانند برای اعتبارسنجی داده‌ها، از جمله اعتبارسنجی نام و مسیر فایل و همچنین ویژگی‌های فراداده فایل مانند contentType و size ، استفاده شوند.

service firebase.storage {
  match /b/{bucket}/o {
    match /images/{imageId} {
      // Only allow uploads of any image file that's less than 5MB
      allow write: if request.resource.size < 5 * 1024 * 1024
                   && request.resource.contentType.matches('image/.*');
    }
  }
}

توابع سفارشی

با پیچیده‌تر شدن Firebase Security Rules ، ممکن است بخواهید مجموعه‌ای از شرایط را در توابعی قرار دهید که بتوانید در سراسر مجموعه قوانین خود از آنها استفاده مجدد کنید. قوانین امنیتی از توابع سفارشی پشتیبانی می‌کنند. سینتکس توابع سفارشی کمی شبیه جاوا اسکریپت است، اما توابع Firebase Security Rules به زبانی خاص دامنه نوشته می‌شوند که محدودیت‌های مهمی دارد:

  • توابع می‌توانند فقط شامل یک دستور return باشند. آن‌ها نمی‌توانند هیچ منطق اضافی داشته باشند. برای مثال، آن‌ها نمی‌توانند حلقه‌ها را اجرا کنند یا سرویس‌های خارجی را فراخوانی کنند.
  • توابع می‌توانند به طور خودکار به توابع و متغیرها از محدوده‌ای که در آن تعریف شده‌اند دسترسی داشته باشند. به عنوان مثال، تابعی که در محدوده service firebase.storage تعریف شده است، به متغیر resource دسترسی دارد و فقط برای Cloud Firestore ، توابع داخلی مانند get() و exists() .
  • توابع می‌توانند توابع دیگر را فراخوانی کنند اما نمی‌توانند به صورت بازگشتی عمل کنند. عمق کل پشته فراخوانی به 10 محدود شده است.
  • در نسخه rules2 ، توابع می‌توانند متغیرها را با استفاده از کلمه کلیدی let تعریف کنند. توابع می‌توانند هر تعداد let binding داشته باشند، اما باید با یک دستور return خاتمه یابند.

یک تابع با کلمه کلیدی function تعریف می‌شود و هیچ یا چند آرگومان می‌گیرد. برای مثال، ممکن است بخواهید دو نوع شرط استفاده شده در مثال‌های بالا را در یک تابع واحد ترکیب کنید:

service firebase.storage {
  match /b/{bucket}/o {
    // True if the user is signed in or the requested data is 'public'
    function signedInOrPublic() {
      return request.auth.uid != null || resource.data.visibility == 'public';
    }
    match /images/{imageId} {
      allow read, write: if signedInOrPublic();
    }
    match /mp3s/{mp3Ids} {
      allow read: if signedInOrPublic();
    }
  }
}

استفاده از توابع در Firebase Security Rules شما، با افزایش پیچیدگی قوانین، آنها را قابل نگهداری‌تر می‌کند.

مراحل بعدی

بعد از این بحث در مورد شرایط، شما درک پیچیده‌تری از قوانین دارید و آماده‌اید تا:

یاد بگیرید که چگونه موارد استفاده اصلی را مدیریت کنید و گردش کار را برای توسعه، آزمایش و استقرار قوانین بیاموزید: