Skip to content

Latest commit

 

History

History
124 lines (86 loc) · 10.2 KB

csrf.md

File metadata and controls

124 lines (86 loc) · 10.2 KB

الحماية من الطلبات المزورة عبر المواقع

مقدمة

تزوير الطلبات عبر المواقع هو نوع من الثغرات الضارة حيث يتم تنفيذ أوامر غير مصرح بها نيابة عن المستخدم الموثق (authenticated user). لكن ولحسن الحظ، يقوم إطار عمل لارافيل بتسهيل حماية تطبيقك من الطلبات المزورة عبر المواقع أو مايعرف بهجمات الطلبات المزورة عبر المواقع (CSRF attacks).

شرح للثغرة

في حال أنك لم تسمع من قبل بالطلبات المزورة عبر الموقع، لنناقش مثالاً عن كيفية استغلال هذه الثغرة. لنتخيل بأن تطبيقك يحتوي المسار (route) التالي /user/email ويقبل طلب من الطريقة POST وهدفه تغيير عنوان البريد الالكتروني للمستخدم الموثق (authenticated user). غالباً هذا المسار (route) يقبل عنوان بريد الكتروني email كحقل إدخال يحوي على عنوان البريد الالكتروني للمستخدم الذي يود المستخدم البدء باستخدامه.

بدون الحماية من الطلبات المزورة عبر المواقع (CSRF protection)، يمكن لأي موقع ضار إنشاء استمارة (HTML form) تشير للمسار (route) التالي /user/email في تطبيقك، فيقوم عندها المخترق بإرسل عنوان بريد الكتروني خاص به ليستبدل عنوان المستخدم الضحية في تطبيقك:

<form action="https://your-application.com/user/email" method="POST">
    <input type="email" value="malicious-email@example.com">
</form>

<script>
    document.forms[0].submit();
</script>

إذا كان الموقع الضار يقوم اتوماتيكياً بإرسال الاستمارة (form) السابقة فور تحميل الصفحة، فإن المخترق يحتاج فقط لجذب المستخدم غير الحذر لزيارة موقعه وبمجرد زيارته للموقع الضار سيتم فوراً تغيير بريده الاكتروني في تطبيقك.

لمنع هذه الثغرة، نحتاج لفحص الطلبات من نوع POST، PUT، PATCH، أو DELETE القادمة للتطبيق إن كانت تحتوي على قيمة سرية خاصة بالجلسة (session)، حيث لا يمكن للتطبيقات الضارة الوصول لها.

منع الطلبات المزورة عبر المواقع

يقوم إطار عمل لارافيل اوتوماتيكياً بإنشاء "رمز" لمنع الطلبات المزورة عبر المواقع (CSRF token) لكل جلسة مستخدم نشطة تتم إدارتها من قبل التطبيق. هذا الرمز (token) يستخدم للتحقق من أن المستخدم الموثق (authenticated user) هو الذي يقوم بإرسال الطلبات للتطبيق. وباعتبار أن هذا الرمز (token) مخزن في جلسة المستخدم ويتغير في كل مرة يتم فيها إعادة إنشاء الجلسة، فإن التطبيق الضار لا يستطيع الوصول لها.

رمز منع الطلبات المزورة عبر المواقع (CSRF token) الحالي يمكن الوصول إليه بواسطة الطلب الخاص بالجلسة (request's session) أو بواسطة التابع المساعد (helper function) csrf_token:

use Illuminate\Http\Request;

Route::get('/token', function (Request $request) {
    $token = $request->session()->token();

    $token = csrf_token();

    // ...
});

في كل مرة تقوم فيها بإنشاء استمارة (HTML form) تحتوي على طلبات من نوع POST، PUT، PATCH، أو DELETE في تطبيقك، يجب عليك تضمين حقل مخفي لرمز ( CSRF _token) في الاستمارة (form) بحيث يمكن للبرمجية الوسيطة للحماية من الطلبات المزورة عبر المواقع (CSRF protection middleware) التحقق من الطلب. ولتسهيل تلك العملية، يمكنك استخدام الموجه (Blade directive) التالي @csrf الذي سيقوم بإنشاء حقل إدخال مخفي لرمز ( CSRF _token):

<form method="POST" action="/profile">
    @csrf

    <!-- Equivalent to... -->
    <input type="hidden" name="_token" value="{{ csrf_token() }}" />
</form>

البرمجية الوسيطة (middleware) App\Http\Middleware\VerifyCsrfToken والمضمنة بشكل افتراضي في مجموعة البرمجيات الوسيطة web أي (web middleware group)ستقوم بشكل تلقائي من التحقق من تطابق الرمز (CSRF token) الموجود ضمن الطلب والرمز المخزن ضمن الجلسة. وفي حال تطابق الرمزين يكون المستخدم هو من أرسل الطلب.

رموز الحماية من الطلبات المزورة عبر المواقع وتطبيقات الصفحة الواحدة (SPA)

في حال كان تطبيقك تطبيق بصفحة واحدة (SPA) يستخدم لارفيل كواجهة خلفية للتطبيق (backend API)، فعليك مراجعة توثيق نظام المصادقة لارافيل سانكتوم (Laravel Sanctum) لمزيد من المعلومات حول المصادقة بالواجهة التطبيقية لبرنامجك (API) وحمايتها من ثغرات الطلبات المزورة عبر المواقع.

استثناء الروابط (URI) من الحماية من الطلبات المزورة عبر المواقع

في بعض الأحيان تحتاج لاستثناء مجموعة روابط (URIs) من الحماية من الطلبات المزورة عبر المواقع (CSRF protection). على سبيل المثال، اذا كنت تستخدم سترايب (Stripe) لمعالجة عمليات الدفع وتستفيد من نظام روابط الويب هوك (webhook system) الخاص به، فسوف تحتاج لاستثناء مسار معالج روابط الويب هوك الخاصة بسترايب (Stripe webhook handler route) من هذه الحماية لأن سترايب لا يعلم ما هو رمز (CSRF token) الذي يجب ارساله لمساراتك (routes).

عادة، لاستثناء هذا النوع من المسارات (routes) يجب عليك وضعها خارج مجموعة البرمجيات الوسيطة (web middleware group) التي يقوم App\Providers\RouteServiceProvider بتطبيقها على جميع المسارات (routes) الموجودة في الملف routes/web.php. ولكن وبكل الأحوال يمكنك أيضاً استثناء المسارات (routes) بطريقة أخرى عبر وضع روابطها (URIs) في الخاصية $except في البرمجية الوسيطة (middleware) VerifyCsrfToken:

<?php

namespace App\Http\Middleware;

use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;

class VerifyCsrfToken extends Middleware
{
    /**
     * The URIs that should be excluded from CSRF verification.
     *
     * @var array
     */
    protected $except = [
        'stripe/*',
        'http://example.com/foo/bar',
        'http://example.com/foo/*',
    ];
}

{tip} للسهولة، تكون البرمجية الوسيطة معطلة تلقائياً لكل المسارات (routes) عند إجراء الاختبارات.

رمز (X-CSRF-TOKEN)

بالإضافة للتحقق من رمز (CSRF token) كوسيط في طريقة الإرسال POST ستقوم البرمجية الوسيطة App\Http\Middleware\VerifyCsrfToken أيضاً من بالتحقق من الترويسة (header) X-CSRF-TOKEN في الطلب، على سبيل المثال يمكنك تخزين الرمز في عنصر meta الخاص بلغة HTML:

<meta name="csrf-token" content="{{ csrf_token() }}">

من ثم يمكنك استعمال مكتبة مثل جي كويري (jQuery) لإضافة الرمز (token) تلقائياً لجميع ترويسات الطلبات. مما يوفر حماية سهلة وبسيطة من الطلبات المزورة عبر المواقع لتطبيقك الذي يعتمد على اجاكس (AJAX) باستعمال تقنية قديمة لجافاسكريبت (JavaScript) :

$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    }
});

رمز (X-XSRF-TOKEN)

يقوم إطار عمل لارافيل بتخزين رمز (CSRF token) ضمن كوكي (cookie) كرمز مشفر XSRF-TOKEN ويقوم بتضمينها في كل رد يقوم بانشائه. حيث يمكنك استعمال قيمة الكوكي (cookie) تلك كقيمة لترويسة X-XSRF-TOKEN ضمن الطلب.

يتم إرسال هذه الكوكي (cookie) بشكل أساسي لتسهيل عمل المطور حيث أن بعض اطر عمل ومكتبات جافاسكريبت (JavaScript) مثل أنغيولر (Angular) وأكسيوس (Axios)، تقوم بشكل تلقائي بوضع قيمة الترويسة X-XSRF-TOKEN على الطلبات من نفس المصدر.

{tip} بشكل افترضي، يحتوي الملف resources/js/bootstrap.js على مكتبة HTTP الخاصة باكسيوس (Axios) التي ستقوم وبشكل تلقائي بإرسال ترويسة X-XSRF-TOKEN لك.