CSRF و CORS: تأمين طلبات المتصفح بالطريقة الصحيحة
لقد أنشأت تطبيق ويب بواجهة برمجة تطبيقات نظيفة، ولكنك لاحظت طلبات غريبة في السجلات — أو الأسوأ، أشار ماسح أمني إلى موقعك بسبب أخطاء في إعدادات CSRF و CORS. غالبًا ما يتم الخلط بين هذين المصطلحين، لكنهما يحلان مشكلات مختلفة. سوء الفهم قد يعرّض مستخدميك للخطر أو يعطّل طلبات شرعية عبر المصادر.
في هذا المقال، سنوضح ما هي CSRF و CORS فعليًا، وكيف تتفاعل مع أمان المتصفح، ونقدم لك خطوات ملموسة لتأمين تطبيقاتك دون كسر الوظائف.
ما هو CSRF ولماذا يجب أن تهتم؟
تزوير الطلبات عبر المواقع (CSRF) هو هجوم يخدع متصفح المستخدم لإرسال طلب إلى موقع تمت المصادقة عليه. تخيل أنك مسجل الدخول إلى بنكك على bank.com. ثم تزور موقعًا ضارًا يحتوي على وسم صورة مثل <img src="https://bank.com/transfer?to=attacker&amount=1000">. سيقوم متصفحك تلقائيًا بتضمين كوكيز البنك مع الطلب، وإذا لم يكن لدى البنك حماية CSRF، فسيتم التحويل.
النقطة الأساسية: يستغل CSRF ثقة الموقع في متصفح المستخدم. لا يحتاج المهاجم إلى سرقة جلستك؛ كل ما يحتاجه هو أن يقوم متصفحك بطلب نيابة عنك.
كيف تعمل هجمات CSRF
لكي ينجح هجوم CSRF، يجب توفر ثلاثة شروط:
- يجب أن يكون الضحية مصادقًا عليه (مثل امتلاك كوكي جلسة صالح).
- يجب أن يعرف المهاجم بنية الطلب (نقطة النهاية، المعلمات).
- يجب ألا يتضمن الطلب أي معلمات غير متوقعة لا يستطيع المهاجم تخمينها.
الأهداف الشائعة هي العمليات التي تغير الحالة: تغيير البريد الإلكتروني، تحويل الأموال، نشر المحتوى، أو تعديل الأذونات.
ما هو CORS ولماذا يوجد؟
مشاركة الموارد عبر المصادر (CORS) هي آلية في المتصفح تسمح أو تمنع صفحات الويب من إرسال طلبات إلى نطاق مختلف عن النطاق الذي قدم الصفحة. إنها امتداد لسياسة المصدر الواحد (SOP)، التي تقيد كيفية تفاعل مستند أو نص برمجي تم تحميله من مصدر واحد مع موارد من مصدر آخر.
بدون CORS، يمكن لموقع ضار استخدام JavaScript لقراءة البيانات من واجهة برمجة تطبيقات بنكك إذا كنت مسجل الدخول. يمنح CORS الخوادم طريقة للسماح صراحة بطلبات معينة عبر المصادر.
سياسة المصدر الواحد (SOP)
يكون عنوانان URL من نفس المصدر إذا تطابق البروتوكول والمضيف والمنفذ. على سبيل المثال، https://example.com/app و https://example.com/api يشتركان في نفس المصدر، لكن http://example.com (بروتوكول مختلف) و https://api.example.com (مضيف مختلف) لا يشتركان.
تمنع SOP النصوص البرمجية من مصدر واحد من قراءة الردود من مصدر آخر. يخفف CORS هذا القيد بإضافة ترويسات HTTP تخبر المتصفح ما إذا كان يجب السماح بالطلب.
CSRF مقابل CORS: الاختلافات الرئيسية
من الضروري فهم أن CSRF و CORS ليسا متضادين؛ بل يعالجان مخاوف أمنية مختلفة. CSRF يتعلق بمنع الطلبات غير المصرح بها التي تغير الحالة، بينما CORS يتعلق بالتحكم في المصادر التي يمكنها قراءة الردود.
| الجانب | CSRF | CORS |
|---|---|---|
| الهدف الأساسي | منع الطلبات المزورة | التحكم في القراءات عبر المصادر |
| ناقل الهجوم | موقع ضار يطلق طلبات | موقع ضار يقرأ الردود |
| آلية الدفاع | الرموز، كوكيز SameSite | ترويسات HTTP (Access-Control-*) |
| تنفيذ المتصفح | لا يوجد (يجب على الخادم التحقق) | نعم (المتصفح يحظر القراءات) |
كيفية الدفاع ضد CSRF
هناك عدة استراتيجيات مثبتة للتخفيف من CSRF. لا تحتاج إليها كلها، لكن تطبيق طبقات دفاعية متعددة أمر حكيم.
1. استخدام رموز مكافحة CSRF
أقوى دفاع هو تضمين رمز فريد وغير متوقع في كل طلب يغير الحالة. يتحقق الخادم من الرمز قبل المعالجة. يجب ربط الرموز بجلسة المستخدم وعدم تعريضها في عناوين URL (لتجنب تسريبها عبر ترويسات المُحيل).
// مثال: إنشاء والتحقق من رمز CSRF في Node.js/Express
const csrf = require('csurf');
const csrfProtection = csrf({ cookie: true });
app.get('/form', csrfProtection, (req, res) => {
res.render('form', { csrfToken: req.csrfToken() });
});
app.post('/process', csrfProtection, (req, res) => {
// يتم التحقق من الرمز تلقائيًا
res.send('OK');
});
2. تعيين كوكيز SameSite
تدعم المتصفحات الحديثة سمة SameSite للكوكيز. تعيينها إلى Lax أو Strict يمنع المتصفح من إرسال الكوكيز في الطلبات عبر المواقع، مما يحظر العديد من هجمات CSRF. يسمح Lax بالكوكيز في التنقلات من المستوى الأعلى (مثل النقر على رابط)، بينما يحظر Strict جميع الطلبات عبر المواقع.
Set-Cookie: sessionId=abc123; SameSite=Lax; Secure; HttpOnly
3. التحقق من ترويسات Origin و Referer
تحقق من ترويسة Origin أو Referer في الطلبات الواردة. إذا لم تتطابق مع النطاق المتوقع، ارفض الطلب. هذه طبقة إضافية بسيطة لكنها فعالة.
4. استخدام ترويسات مخصصة لـ AJAX
إذا كانت واجهة برمجة التطبيقات الخاصة بك تُستهلك عبر JavaScript، فاطلب ترويسة مخصصة مثل X-Requested-With. تفرض المتصفحات فحص CORS المسبق للترويسات المخصصة، لذا لن يتضمن نموذج POST بسيط من موقع ضار هذه الترويسة.
تكوين CORS بشكل صحيح
يمكن أن تؤدي أخطاء تكوين CORS أيضًا إلى مشكلات أمنية. الخطأ الأكثر شيوعًا هو تعيين Access-Control-Allow-Origin: * مع السماح أيضًا ببيانات الاعتماد. هذا المزيج محظور من قبل المتصفحات، لكن المطورين يحاولون أحيانًا التحايل عليه بشكل غير آمن.
أفضل الممارسات لترويسات CORS
- حدد مصادر دقيقة بدلاً من أحرف البدل عند تضمين بيانات الاعتماد.
- اقصر الطرق المسموح بها على ما تدعمه واجهة برمجة التطبيقات فقط (مثل
GET, POST). - اقصر الترويسات المسموح بها على تلك التي يستخدمها تطبيقك فعليًا.
- عيّن
Access-Control-Max-Ageلتخزين ردود الفحص المسبق مؤقتًا وتقليل الحمل. - تجنب عكس ترويسة
Originبشكل أعمى؛ تحقق منها مقابل قائمة بيضاء.
# مثال: تكوين Nginx لـ CORS
location /api/ {
if ($http_origin ~* (https://(app|admin)\.example\.com)) {
add_header 'Access-Control-Allow-Origin' $http_origin;
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
}
if ($request_method = 'OPTIONS') {
return 204;
}
}
تذكر أن CORS يتم فرضه من قبل المتصفح، وليس الخادم. إنه ليس بديلاً عن المصادقة أو التفويض؛ إنه طريقة لتخفيف سياسة المصدر الواحد بأمان.
تجميع كل شيء معًا
يتطلب تأمين طلبات المتصفح نهجًا متعدد الطبقات. إليك قائمة مراجعة سريعة:
- استخدم رموز مكافحة CSRF لجميع العمليات التي تغير الحالة.
- عيّن كوكيز SameSite إلى
LaxأوStrict. - تحقق من ترويسات Origin/Referer على الخادم.
- كوّن CORS بدقة: قائمة بيضاء للمصادر، حدد الطرق، وتجنب أحرف البدل مع بيانات الاعتماد.
- اختبر بانتظام تطبيقك باستخدام ماسحات أمنية وفحوصات يدوية.
من خلال فهم الأدوار المتميزة لـ CSRF و CORS، يمكنك تجنب المزالق الشائعة وبناء تطبيق ويب أكثر أمانًا.
الأسئلة الشائعة
هل يمكن لـ CORS منع هجمات CSRF؟
لا، لا يمنع CORS هجمات CSRF. لا تعتمد هجمات CSRF على قراءة الردود؛ بل تطلق الطلبات فقط. يتحكم CORS في المصادر التي يمكنها قراءة الردود، لكنه لا يمنع إرسال الطلب. لمنع CSRF، تحتاج إلى رموز، أو كوكيز SameSite، أو التحقق من المصدر.
هل من الآمن تعيين Access-Control-Allow-Origin إلى '*'؟
تعيينه إلى '*' آمن فقط إذا كانت واجهة برمجة التطبيقات الخاصة بك لا تستخدم بيانات الاعتماد (الكوكيز، مصادقة HTTP). إذا كانت بيانات الاعتماد متضمنة، سترفض المتصفحات الرد. لواجهات برمجة التطبيقات التي تتطلب مصادقة، حدد دائمًا مصادر دقيقة.
هل أحتاج إلى حماية CSRF إذا استخدمت JWT في ترويسات Authorization؟
إذا كنت تخزن JWT في الكوكيز، فلا تزال بحاجة إلى حماية CSRF لأن الكوكيز تُرسل تلقائيًا. إذا كنت تخزن JWT في الذاكرة وترسلها عبر ترويسة Authorization، فإن CSRF ليس مصدر قلق لأن المهاجم لا يمكنه تعيين ترويسات مخصصة عبر المصادر. ومع ذلك، يجب عليك الحماية ضد XSS للحفاظ على أمان الرمز.
هل أنت مستعد لاختبار ترويسات CORS لواجهة برمجة التطبيقات الخاصة بك؟ استخدم Nginx Log Analyzer الخاص بنا لفحص أنماط الطلبات ورصد محاولات مشبوهة عبر المصادر.