الاسمين قريبين من بعض لدرجة تلخبط: SSRF وCSRF، كلاهما "Request Forgery" (تزوير طلب). بس هاد التشابه بالاسم بيخلّي كتير مطورين يفترضون إنهم نفس الثغرة أو إن حماية وحدة كافية للتانية — وهاد افتراض خطير.
الفرق الجوهري: مين يرسل الطلب؟
السؤال الوحيد يلي لازم تسأله للتفريق بينهم: مين اللي فعليًا بيرسل الطلب الخبيث؟
CSRF → متصفح المستخدم هو يلي بيرسل الطلب (بدون علمه)
SSRF → خادمك أنت هو يلي بيرسل الطلب (بدون علمه)
CSRF: يستهدف المستخدم
بـ CSRF، المهاجم بيصمّم صفحة على موقعه (evil.com) بتخلّي متصفح الضحية يرسل طلب لموقع تاني (example.com) الضحية مسجّل دخول فيه أصلًا. المتصفح بيرسل الكوكيز تلقائيًا، فالطلب بيبان "شرعي" للخادم.
<!-- صفحة evil.com -->
<img src="https://example.com/api/transfer?to=attacker&amount=1000" style="display:none" />
1. الضحية مسجّل دخول بـ example.com
2. الضحية بيزور evil.com (رابط بإيميل مثلًا)
3. evil.com بترسل طلب مخفي لـ example.com
4. متصفح الضحية بيرسل الكوكيز تلقائيًا → الطلب ينفذ
الهدف هون: صلاحيات المستخدم نفسه. المهاجم ما شاف أي بيانات مباشرة — بس استغل ثقة الخادم بمتصفح مسجّل دخول.
SSRF: يستهدف الخادم
بـ SSRF، المهاجم بيرسل رابط (URL) كجزء من طلب API عادي — زي رابط صورة أو Webhook — والخادم نفسه هو يلي بيجلب هاد الرابط، مو المتصفح.
// endpoint يجلب صورة برابط يحدده المستخدم
app.post('/api/avatar', async (req, res) => {
const response = await fetch(req.body.imageUrl); // الخادم يطلب الرابط
res.send(await response.buffer());
});
المهاجم يرسل: { "imageUrl": "http://169.254.169.254/latest/meta-data/..." }
الخادم (مو المتصفح) هو يلي بيطلب هاد العنوان الداخلي — عنوان خدمة بيانات
اعتماد السحابة (Cloud Metadata) يلي المهاجم ما كان يقدر يوصله مباشرة من
برا الشبكة الداخلية أصلًا.
الهدف هون: شبكة الخادم الداخلية والبنية التحتية، مو حساب مستخدم واحد.
جدول المقارنة
| المعيار | CSRF | SSRF |
|---|---|---|
| مين بيرسل الطلب الخبيث؟ | متصفح الضحية | الخادم نفسه |
| مين الضحية؟ | مستخدم مسجّل دخول | البنية التحتية للشركة |
| أين يحدث؟ | جهة العميل (Client) | جهة الخادم (Server) |
| أقصى ضرر محتمل | إجراءات بصلاحية المستخدم (تحويل، حذف، تعديل) | سرقة بيانات اعتماد سحابية، اختراق شبكة داخلية |
| الحماية الأساسية | CSRF Tokens + SameSite Cookies | Allowlist للمضيفين + منع تحويلات تلقائية |
الحماية: كل وحدة لحالها
حماية CSRF
res.cookie('session', token, {
httpOnly: true,
secure: true,
sameSite: 'strict', // يمنع المتصفح من إرسال الكوكيز عبر مواقع تانية
});
حماية SSRF
const ALLOWED_HOSTS = ['images.trusted-cdn.com'];
async function safeFetch(userUrl) {
const url = new URL(userUrl);
if (!ALLOWED_HOSTS.includes(url.hostname)) {
throw new Error('مضيف غير مسموح');
}
return fetch(url, { redirect: 'manual' }); // بلا تتبع تحويلات
}
لاحظ: SameSite cookies ما بتأثر على SSRF إطلاقًا — الخادم مو متصفح، ما عنده كوكيز أساسًا بهاد السياق. وبالعكس، allowlist المضيفين ما بيحمي من CSRF لأنه المشكلة مو "أي رابط بيطلبه الخادم"، المشكلة "أي طلب بيوصل الخادم من متصفح مو متأكد من قصده".
ليش بيصير اللخبطة؟
كلاهما بالاسم فيهم "Request Forgery"، وكلاهما بالنهاية عن طلب HTTP "مزيّف" بمعنى إنه صار بدون قصد صريح من الطرف الحقيقي (المستخدم أو الخادم). بس السياق مختلف تمامًا — تخيلها هيك:
CSRF = حدا خدعك تدق على باب جارك بالنيابة عنه (أنت الأداة)
SSRF = حدا خدع حارس المبنى يفتحله باب مخزن داخلي (الحارس هو الأداة)
الخلاصة
SSRF وCSRF مختلفتين بالهدف، الآلية، والحماية — التشابه بالاسم بس. لو بتبني API فيه أي endpoint بيقبل روابط خارجية (رفع صور، Webhooks) لازم تفكر بالاثنين بشكل منفصل: هل في إجراء حساس ممكن ينفذ من متصفح بدون قصد المستخدم؟ (CSRF) وهل في رابط بيجلبه الخادم بدون تحقق من وجهته؟ (SSRF)
اقرأ أكتر بمسار أمن API: الحماية من XSS وCSRF والحماية من SSRF.