برنامه‌نویسی

احراز‌هویت و لاراول Airlock/Sanctum:

احراز‌هویت در لاراول

درخواست‌های HTTP بدون‌وضعیت (stateless) هستند، شاید برای شما سوال باشد بدون‌وضعیت به‌چه معناست؟ به‌طور کلی می‌توان گفت، سرور اطلاعات وضعی هرکاربر را نگهداری نمی‌کند و بدین شکل مفهوم بدون‌وضعیت شکل می‌گیرد. شما برای تایید هویت کاربر می‌بایست بدانید، هرکدام از درخواست های ارسالی از سمت چه کسی برای سرور شما ارسال می‌شود. برای این امر، می‌توانیم با ارسال توکن که اطلاعاتی از هر کاربر را شامل می‌شود یا با ایجاد یک نشست (session) مخصوص هرکاربر به سمت سرور، به مقصود خود برسیم.

توکن‌ها یک روش انعطاف‌‌ پذیر برای تایید‌هویت کاربر هستند، اما باید نگران محل ذخیره‌سازی توکن‌ها در سمت‌کاربر و ایمنی آن باشید. بخصوص اگر این توکن‌ها در اپلیکیشن‌های جاوااسکریپتی مورد استفاده قرار بگیرد، نگرانی شما را دوچندان می‌کند. از طرف دیگر، نشست‌ها در سمت‌ سرور ذخیره می‌شوند، بنابراین از امنیت بیشتری برخوردارند. با این حال لازم است نگران فضای ذخیره‌سازی و این واقعیت باشید که اطلاعات فقط در اپلیکیشن‌های فعلی، که در همان دامنه قرار دارند در دسترس است.

لاراول Sanctum:

Sanctum یک سیستم احرازهویت سبک برای لاراول است. شما با استفاده از این سیستم می‌توانید اطمینان حاصل کنید درخواست‌هایی که به سمت API شما می‌آیند دارای یک توکن یا نشستی معتبر برای احرازهویت کاربران است.

درنظر بگیرید، بخش فرانت‌اند اپلیکیشن شما در‌همان دامنه‌ای است که API میزبانی می‌شود، شایدهم یک ساب‌دامنه مجزا. Sanctum به شما این قابلیت را می‌دهد به عنوان یک محافظ، از وضعیت اعتبار درخواست‌هایی که به سمت API ارسال می‌شوند، اطمینان حاصل کنید. بخش فرانت‌اند شما نیاز خواهد داشت درخواست POST را به مسیر /login ارسال کند و اگر آن درخواست صحیح بود، لاراول یک نشست حاوی شناسه‌کاربر را ذخیره و برای تایید اعتبار کلیه درخواست‌ها در آینده از آن استفاده می‌کند.

اگر درخواست‌های ارسالی ازیک منبع قابل اعتماد باشند، پکیج Sanctum اطمینان حاصل می‌کند: درپاسخ، مسیر‌های API در وضعیتی stateful، پاسخگوی درخواست‌ها باشند. (stateful سرویسی برای پاسخ‌گویی به درخواست‌ها است که از وضعیت داخلی خود استفاده می‌کند و به‌ازای هر درخواست، به دیتابیس کوئری نمی‌زند).

Sanctum صحت درخواست‌ها را در middleware ای به نام EnsureFrontendRequestsAreStateful چک می‌کند. بررسی به این شکل اتفاق می‌افتد که sanctum درخواست را با دامنه‌ای که قبلا در airlock.stateful پیکربندی شده، مقایسه می‌کند. اگر از دامنه‌ای یکسان بود، درخواست را از طریق middleware های زیر ارسال خواهد کرد:

  • EncryptCookies
  • AddQueuedCookiesToResponse
  • StartSession
  • VerifyCsrfToken

این کار باعث می‌شود، web guard مرتبا، درکنار لاراول تا زمانی که بخواهد به نشست شما دسترسی یابد، کارکند. در صورتی که درخواست شما دارای وضعیت نبود، نشست مورد نظر برای درخواست‌دهنده غیرقابل دسترس است.

تمام آن‌چیزی که به آن نیاز دارید، تغییر authentication guard از auth:api به auth:airlock در فایل api.php است. این محافظ بررسی می‌کند که اگر احرازهویت نشست صحیح بود، به درخواست اجازه استفاده از API موردنظر را بدهد. دیگر هیچ توکن‌ی در بخش کاربر ذخیره نمی‌شود، حتی دراین حالت به ارسال توکن نیازی نیست. فقط یک احرازهویت معمولی مبتنی بر نشست، بصورت ایمن اتفاق می‌افتد.

پیکربندی نشست:

Sanctum به کمک شما می‌آید و نگرانی بعدی مارا هم رفع می‌کند. با تنظیم مقدار‌های زیر نشست‌های شما به صورت ایمن در سرور ذخیره می‌شوند:

    session.http_only: true
    session.same_site: lax

هنگامی که شما مقدار session.http_only را برابر true قرار می‌دهید، Sanctum اطمینان حاصل می‌کند مرورگر کاربر به شناسه‌نشست مورد نظر، از طریق کوکی دست پیدا نکند و این مقدار فقط در سرور قابل دسترس است.

همچنین با قرار دادن مقدار session.same_site برابر با lax اطمینان حاصل می‌شود، کوکی فقط در صورتی که کاربر دروبسایت شما باشد ارسال شود، اگر کاربر درحال مشاهده یک iframe از وبسایت شما باشد یا درخواست ajax از یک میزبان دیگر، غیراز شما باشد از ارسال آن جلوگیری می‌کند.

شناسه نشست:

هنگام ارسال درخواست کاربر باید بتواند شناسه‌نشست را به سمت‌سرور ارسال کند، برای این کار شما می‌بایست چند کار انجام دهید:

1. برای اپلیکیشنی که برروی API شما خدمات می‌دهند، session.domain مناسبی را دربخش پیکربندی تنظیم کنید. اگر شما مقدار آن‌را .domain.com قراردهید، تمامی درخواست‌هایی که از آن دامنه یا ساب‌دامنه می‌آیند، شناسه نشست خواهند‌داشت و کاربران می‌توانند درخواست‌هایشان را ارسال کنند.

2. در قدم دوم مقدار withCredentials درخواست‌های HTTP کاربر را true قراردهید. این اقدام موجب می‌شود مرورگر کاربران کوکی را همراه با درخواست‌هایشان، به سمت‌سرور اپلیکیشن ارسال کنند. درغیراینصورت اگر SPA (Single Page Application) یا به عبارت دیگر اپلیکیشن‌تک‌صحفه‌ای شما در یک ساب‌دامنه مجزا باشد، این کار امکان پذیر نیست.

به همین دلیل است که شما نمی‌توانید، API را هنگامی که روی دامنه اصلی است از طریق اپلیکیشن‌تان در ساب‌دامنه استفاده کنید. نیاز است هردو آن‌ها برروی یک دامنه قراربگیرند تا شناسه‌نشست یکسانی را دریافت کنند.

محافظت از حملات CSRF:

    به صورت پیش‌فرض ارسال درخواست‌های POST,PATCH,PUT,DELETE  به سمت API مجاز است. بااین حال که Sanctum از طریق نشست هویت کاربران را تایید می‌کند، نیازاست مطمئن شویم این درخواست ها از سمت SPA شما ارسال شده، به همین خاطر Sanctum میدل‌ویر (middleware) VerifyCsrfToken را می‌افزاید.

قبل از تأیید اعتبار کاربر شما می‌بایست یک درخواست GET به مسیر /airlock/csrf-cookie ارسال کنید. پاسخی که دریافت می‌شود شامل کوکی با مقدار XSRF-TOKEN است که در مرورگر کاربر ذخیره می‌شود و ازطریق درخواست‌های HTTP کاربر، در آینده (برای‌نمونه: axios) به سمت‌سرور ارسال می‌شود.

لاراول مقادیر این توکن را دریافت و آن‌را با توکن ذخیره‌شده در نشست مطابقت می‌دهد. اگر میخواهید بیشتر درباره عملکرد CSRF Protection در لاراول بدانید، می‌توانید فیلم زیر را تماشا کنید.

آدرس ویدئو

CORS (cross-origin resource sharing)

مرورگر‌های مدرن امروزی برای محافظت از ربوده شدن اطلاعات کاربران، سیاست‌های‌امنیتی را به‌کار گرفتند. اگر شما از وبسایت domain.com بازدید‌کنید و آن وبسایت سعی در ارسال درخواست به another-domain.com داشته باشد، آن مرورگر، از ایمن بودن محتوای آن وبسایت اطمینان حاصل می‌کند.

اگر API شما برروی api.domain.com میزبانی می‌شود و SPA شما بر روی spa.domain.com قرار دارد، بدلیل اینکه هردوی آن‌ها برروی یک دامنه نیستند، شما نیازدارید به ارتباط بین API و SPA مجوز دهید.

شما می‌توانید از پکیج fruitcake/laravel-cors استفاده کنید تا به شما کمک کند.

در این قسمت به پیکربندی این پکیج می‌پردازیم:

return [
 'paths' => [
  'api/*',
  'login',
  'airlock/csrf-cookie'
 ],

 'allowed_origins' => [
  'https://spa.domain.com',
  'https://third.party.com'
 ],

 'supports_credentials' => true,
];

در کدهای بالا، CORS را برای مسیرها مشخص شده در بخش ‘path’ فعال می‌کنیم. تمامی قوانین CORS دراین مسیرها اعمال می‌شود. درمرحله بعد، ما فقط برای origin های مورد اعتماد در بخش ‘allowed_origins’ اجازه صادر می‌کنیم.

سرانجام ما به لاراول دستور می‌دهیم، درهر پاسخ HEADER: Acecess-Control-Alow-Credentials را به کاربر ارسال کند، این امر باعث می‌شود مرورگر، کوکی‌های ارسال شده با برنامه جاوااسکریپتی را با ما به اشتراک بگذارد.

اگر هنوز هم این مسائل برای شما گیج‌کننده هستند، در ویدئو زیر با جزئیات به توضیح این سیاست‌امنیتی می‌پردازیم.

آدرس ویدئو

صدور توکن

اگر کاربرانتان از یک برنامه جاوااسکریپتی استفاده کنند شما در تاییدهویت کاربرانتان به استفاده از نشست‌ها و همچنین قرار داشتن آن اپلیکیشن، در همان دامنه یا ساب‌دامنه محدود هستید، به این دلیل، Sanctum به شما این اجازه را می‌دهد توکن های شخصی بسازید و آن را دراختیار دستگاه‌هایی که به نشست دسترسی ندارند، بدهید.

$user->createToken(
 'laravel-forge', 
 ['server:create', 'server:delete']
);

با استفاده از این قطعه کد کوچک، شما می‌توانید توکن‌ی با نام laravel-forge و ایجاد کنید که قابلیت ایجاد و حذف سرور را داراست.

بصورت زیر می‌توانید از قابلیت توکن استفاده کنید:

$user->tokenCan('server:create');

همچنین با استفاده از کدزیر می‌توانید توکن خود را لغو (Revoke) کنید:

$user->tokens()->whereName('laravel-forge')->delete();

یا حتی می‌توانید توکن درحال استفاده را لغو کنید (همراه با بیرون انداختن کاربر):

auth()->user()->currentAccessToken()->delete();

توکن ها با استفاده از الگوریتم SHA-256 هش ودر دیتابیس ذخیره می‌شوند. Sanctum توکن های ارسال شده در HEADER با نام Authorization را بررسی و از وجود و اعتبار آن در دیتابیس اطمینان حاصل می‌کند. شما می‌توانید تاریخ انقضای توکن‌هارا در تنظیمات airlock.expiration پیکربندی کنید.

توکن‌های وب JSON

توکن‌های تولیدشده توسط Sanctum، از نوع JWT نیستند. مقداری که شما در HEADER برای ارزشیابی به قسمت authorization ارسال می‌کنید، یک رشته تصادفی است که token key آن در دیتابیس قرار دارد.

تمام جزئیات مربوط به توکن فقط در دیتابیس موجود است. این باعث می‌شود بروزرسانی نام و قابلیت‌های توکن در دیتابیس به آسانی انجام‌پذیر باشد.

Passport

درصورتی که به گواهی اعتبار کاربر (Client Credential grant) برای برقراری ارتباط ماشین به ماشین (machine-to-machine) یا کد مجوز (Authorization Code grant) نیازی ندارید، می‌توانید به‌جای passport از Sanctum استفاده کنید، زیرا این نوع ارتباطات به تکنیک های پیشرفته‌تر تایید‌اعتبار احتیاج دارند و Sanctum برای این امر ساخته نشده است.

در زمینه‌های دیگر Sanctum گزینه مناسبی برای تایید کاربران بدون نیاز به تنظیم کامل سرور برای اجرای سناریو OAuth2 است.

اگر دراستفاده از Airlock/Sanctum مشکلی دارید در ویدئو زیر تمام مشکلات احتمالی با راه‌حل توضیح داده شده‌اند.

آدرس ویدئو

منبع: https://divinglaravel.com/authentication-and-laravel-airlock