طَبِّقْهاتعلّم المبدأ، وطبّقه بيدكمقرر 243 · أمن الويب
الدرس 20 · الوحدة 9: أمان البنية التحتية والمعايير

الجدران النارية و TLS وحماية الشبكة

ما الذي يحمي تطبيقك خارج كوده، وكيف يُخدع خادمك ليطلب ما لا يجوز؟ ⏱ نحو 40 دقيقة.

بعد هذا الدرس ستستطيع أن:
  • تصف طبقات حماية البنية التحتية.
  • تشرح خدمات TLS الثلاث.
  • تدرك أن WAF يسند الكود لا يحلّ محلّه.
  • تكتشف SSRF وتصلحه بقائمة مسموح.

١طبقات حماية البنية التحتية

أمن الكود لا يكفي؛ يسنده أمن البنية التحتية حوله. تمرّ البيانات عبر طبقات، كل طبقة تصفّي ما قبلها:

جدار ناري شبكي
يفتح المنافذ اللازمة فقط

TLS/HTTPS
يشفّر النقل

جدار تطبيقات WAF
يصفّي الأنماط الخبيثة

تطبيقك
الدفاعات في الكود

طبقات الحماية من الشبكة إلى التطبيق؛ دفاع بالعمق على مستوى البنية.
الطبقةدورها
الجدار الناري الشبكييفتح المنافذ اللازمة فقط (مثلًا 443)، ويغلق الباقي
TLS/HTTPSيشفّر النقل ويوثّق هوية الخادم بشهادة
جدار تطبيقات الويب WAFيصفّي أنماط الهجوم المعروفة قبل وصولها للتطبيق
التطبيقالدفاعات في الكود (كل ما سبق في المقرر)

٢TLS: الثقة في النقل

TLS (الذي يجعل HTTP يصير HTTPS) يقدّم ثلاثة:

الخدمةالمعنى
التشفيرلا يُقرأ ما ينتقل في الطريق
السلامةيُكتشف العبث بالبيانات المنقولة
التوثيقشهادة الخادم تثبت أنه من يدّعي

الشهادة يصدرها طرف موثوق (CA)، ويتحقق المتصفح منها. انتهاء الشهادة أو ضعف إصدار TLS قديم ثغرة؛ استخدم TLS حديثًا وجدّد الشهادات.

٣SSRF: حين يُخدع خادمك ليطلب

فئة A10 في OWASP: تزوير الطلب من الخادم (SSRF). إن سمحت لخادمك بجلب رابط يحدده المستخدم، قد يوجّهه المهاجم إلى موارد داخلية لا يصلها هو مباشرة (خدمات داخل الشبكة، بيانات اعتماد السحابة). الخادم موثوق داخليًّا، فيصبح وكيلًا للمهاجم.

const express = require('express');const app = express();app.use(express.json());app.use(express.urlencoded({ extended: false })); const ALLOW = ['api.weather.sa', 'api.rafee.sa'];   // قائمة المضيفات المسموحة app.get('/fetch', (req, res) => {  const host = String(req.query.host || '');  if (!ALLOW.includes(host))                          // ✓ لا نطلب إلا المسموح    return res.status(400).json({ error: 'مضيف غير مسموح' });  res.json({ ok: true, fetchedFrom: host });          // (في الواقع: طلب فعلي للمضيف)}); app.listen(3000);

الطلب الأول لمضيف مسموح نجح. والثاني لعنوان بيانات اعتماد السحابة الداخلي (169.254.169.254) رُفض؛ لأنه ليس في قائمة المسموح. القائمة تمنع الخادم من أن يُوجَّه إلى الداخل.

توقّع وتحقّق

الجدار الناري الشبكي:

TLS يقدّم:

SSRF يخدع الخادم ليطلب:

الدفاع عن SSRF:

الخلاصة

تحدٍّ برمجي: سدّ ثغرة SSRF

متقدم

مسار الجلب يطلب أي مضيف يحدده المستخدم، فهو عرضة لـ SSRF نحو الموارد الداخلية. قيّده بقائمة مضيفات مسموحة.

المطلوب:
  • عرّف قائمة مسموحة تضم api.weather.sa و api.rafee.sa.
  • مضيف مسموح يُقبل.
  • مضيف غير مسموح (مثل عنوان داخلي) يُرفض 400.
👀 اعرض الاستجابات المطلوبة
✓ التحقق الآلي: يشغّل المختبر خادمك من جديد ويرسل إليه هذه الطلبات بالترتيب ثم يفحص الردود
  1. GET /fetch?host=api.weather.sa
  2. GET /fetch?host=169.254.169.254
  3. GET /fetch?host=localhost
  • الخادم يعمل ويرد على كل الطلبات بلا أخطاء غير معالَجة
  • مضيف مسموح يُقبل
  • عنوان داخلي يُرفض ← 400
  • localhost يُرفض ← 400
  • يستخدم قائمة مسموحة

💡 تلميح 1
عرّف const ALLOW = ['api.weather.sa', 'api.rafee.sa'];.
💡 تلميح 2
تحقق: if (!ALLOW.includes(host)) return res.status(400)….
💡 تلميح 3
قائمة المسموح ترفض كل ما عداها تلقائيًّا، ومنه العناوين الداخلية.

حاول بنفسك أولًا؛ للمسألة أكثر من حلّ صحيح.

const express = require('express');const app = express();app.use(express.json());app.use(express.urlencoded({ extended: false })); const ALLOW = ['api.weather.sa', 'api.rafee.sa'];app.get('/fetch', (req, res) => {  const host = String(req.query.host || '');  if (!ALLOW.includes(host))    return res.status(400).json({ error: 'مضيف غير مسموح' });  res.json({ ok: true, fetchedFrom: host });});app.listen(3000);
انتقل إلى تقييم الدرساختيار من متعدد، وصح وخطأ، وأكمل الفراغ، وتتبّع الناتج.ابدأ التقييم ←

📝 معلم؟ أرسل ملاحظة للمؤلف عن هذا الدرس