ملفات تعريف الارتباط والجلسات في HTTP

بروتوكول HTTP عديم الحالة (stateless): كل طلب قائم بذاته. وملف تعريف الارتباط (cookie) هو طريقة الخادم ليطلب من المتصفح أن يحفظ له قيمة: تحمل الاستجابة Set-Cookie: sid=k3Vq9XbT2mR7wLp4; Path=/; Secure; HttpOnly، ومن بعدها يضيف المتصفح Cookie: sid=k3Vq9XbT2mR7wLp4 إلى كل طلب مطابق. أما الجلسة (session) فهي الجزء الخاص بالخادم: سجلّ بمن سجّل الدخول، يحفظه الخادم ويعثر عليه عبر ذلك المعرّف.

عندما تسجّل الدخول إلى متجر وتفتح سجل طلباتك، لا يعرف المتجر أنه أنت إلا لأن المتصفح أرسل ملف تعريف ارتباط الجلسة ووجد الخادم جلسة سارية له. ومن دون جلسة سارية يتلقى الطلب إعادة التوجيه إلى صفحة الدخول أو الاستجابة ⁦401⁩ اللتين تعرّفت إليهما في رموز حالة HTTP.

لماذا يهم

تعتمد كل ميزة تقريباً خلف تسجيل الدخول على هذه الآلية، وكثير من عيوبها عيوب أمنية: فمعرّف الجلسة الذي تقرؤه السكربتات، أو ينتقل عبر HTTP غير المشفّر، أو يظل صالحاً بعد تسجيل الخروج، أو لا ينتهي أبداً، يتيح لشخص آخر أن يتصرف باسم المستخدم. ولا يظهر شيء من ذلك في تشغيل المسار السعيد (happy path).

والفحوص رخيصة وملموسة: بأدوات المطوّر وحساب اختبار ترى هل السمة موجودة وهل يُرفض الطلب المعاد إرساله. والتقرير الذي يقتبس سطر Set-Cookie بعينه يتيح للمطوّر إصلاح الإعدادات بسرعة.

النطاق ومدة البقاء: Domain وPath وExpires وMax-Age

يضع الخادم ملف تعريف ارتباط واحداً في كل ترويسة Set-Cookie: الزوج name=value أولاً، ثم السمات (attributes). ويحدد RFC 6265 كيف يخزّنه المتصفح وأيّ الطلبات اللاحقة تستلمه. ولا يعيد المتصفح إلا أزواج name=value في ترويسة Cookie واحدة، لذا افحص السمات في الاستجابة لا في الطلب.

  • Domain: من دونها يكون ملف تعريف الارتباط خاصاً بالمضيف (host-only)، فلا يعود إلا إلى المضيف الذي وضعه؛ أما Domain=portal.example فترسله أيضاً إلى كل نطاق فرعي، مثل docs.portal.example.
  • Path: يذهب ملف تعريف الارتباط إلى العناوين التي يبدأ مسارها بمساره عند حدّ /، فـPath=/help يطابق /help/start ولا يطابق /helpdesk. ويحذّر RFC 6265 من أن Path ليس حداً أمنياً.
  • Expires (تاريخ) أو Max-Age (ثوانٍ) تجعل ملف تعريف الارتباط دائماً (persistent)، وتتقدم Max-Age إذا وُجدتا معاً. ومن دونهما يكون ملف تعريف ارتباط جلسة (session cookie) يُحذف عند انتهاء جلسة المتصفح. وMax-Age=0 تحذفه.
  • يُعرَّف ملف تعريف الارتباط بالاسم والنطاق والمسار معاً. فالحذف أو الاستبدال يجب أن يكرر الثلاثة؛ وإلا بقي القديم في مكانه، ولا يضيف الاستبدال إلا ملفاً ثانياً بالاسم نفسه.
Responses from https://portal.example
Set-Cookie: sid=k3Vq9XbT2mR7wLp4; Path=/; Secure; HttpOnly; SameSite=Lax
Set-Cookie: lang=ar; Domain=portal.example; Path=/; Max-Age=31536000; Secure
Set-Cookie: tour=done; Path=/help; Expires=Fri, 01 Jan 2027 00:00:00 GMT; Secure

Request to                               Cookies the browser sends
https://portal.example/help/start        sid, lang, tour
https://portal.example/dashboard         sid, lang
https://docs.portal.example/             lang

جرّبها: محلّل ملفات تعريف الارتباط (Cookies) جرّبها: محلّل عناوين URL

سمات الأمان: Secure وHttpOnly وSameSite

تحدّ هذه السمات من طرق تسرّب ملف تعريف الارتباط أو إساءة استخدامه. وكل واحدة منها تسدّ طريقاً واحداً، فاعرف ما لا تسدّه.

  • Secure: لا يُرسل ملف تعريف الارتباط إلا عبر HTTPS، فلا يمكن قراءته من حركة HTTP غير المشفّرة.
  • HttpOnly: ملف تعريف الارتباط مخفي عن document.cookie، فلا يستطيع سكربت محقون نسخه، لكن المتصفح يظل يرفقه بالطلبات، فيبقى بوسع هذا السكربت أن يتصرف باسم المستخدم داخل الصفحة.
  • SameSite تتحكم في الطلبات التي تبدأ من موقع آخر. Strict: لا يُرسل أبداً، فالمستخدم القادم من رابط في موقع آخر يبدو غير مسجّل الدخول. Lax: يُرسل فقط في التنقل على المستوى الأعلى (top-level navigation)، أي حين تنتقل علامة التبويب كلها إلى الموقع (مثلاً باتباع رابط)، وبطريقة آمنة مثل GET؛ لا في إرسال النماذج من موقع آخر ولا الصور ولا الإطارات ولا استدعاءات fetch. None: يُرسل في الطلبات القادمة من مواقع أخرى أيضاً، ما لم تحجب إعدادات المتصفح ملفات تعريف الارتباط التابعة لجهات خارجية (third-party cookies)، ولا يُقبل إلا مع Secure.
  • «الموقع» هو النطاق القابل للتسجيل (registrable domain)، فـdocs.portal.example وportal.example موقع واحد. وتأتي SameSite من مسودات RFC 6265bis التي تطبقها المتصفحات لا من RFC 6265، وتختلف القيمة الافتراضية بين المتصفحات، لذا توقّع أن تُضبط صراحةً.
  • الحد الأدنى لملف تعريف ارتباط الجلسة: Secure وHttpOnly وSameSite=Lax أو Strict صراحةً، ولا Domain ما لم تحتجه النطاقات الفرعية، ولا Expires ولا Max-Age، لأن ورقة OWASP المرجعية لإدارة الجلسات (Session Management Cheat Sheet) توصي بملفات جلسة غير دائمة.

جرّبها: محلّل ملفات تعريف الارتباط (Cookies) جرّبها: محلّل ترويسات HTTP

الجلسات على الخادم: المعرّف والانتهاء وتسجيل الخروج

عند تسجيل الدخول يحفظ الخادم سجلّ جلسة (المستخدم والأدوار والأوقات) في مخزن جلسات مثل الذاكرة أو قاعدة بيانات أو ذاكرة تخزين مؤقت، ولا يرسل في Set-Cookie إلا معرّفاً عشوائياً. وفي كل طلب لاحق يبحث عن المعرّف: إن وجد جلسة سارية نُفّذ الطلب باسم ذلك المستخدم، وإلا أُعيد توجيه الصفحة إلى صفحة الدخول وأعادت الواجهة البرمجية (API) الاستجابة 401 Unauthorized.

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

  • معرّفاً يولّده مولّد أرقام عشوائية آمن تشفيرياً، بإنتروبيا (entropy، أي مقياس صعوبة تخمينه) لا تقل عن ⁦64⁩ بت، ولا يحمل معنى كرقم مستخدم أو طابع زمني.
  • معرّفاً جديداً عند تسجيل الدخول وعند كل تغيير في الصلاحيات مع إبطال القديم؛ وإلا فإن معرّفاً زُرع قبل الدخول، وهو ما يُعرف بتثبيت الجلسة (session fixation)، يظل يعمل بعده.
  • مهلة خمول (idle timeout) تُحسب من آخر طلب، ومهلة مطلقة (absolute timeout) تُحسب من تسجيل الدخول، تُفرضان كلتاهما على الخادم.
  • تسجيل خروج يُنهي السجلّ على الخادم؛ أما حذف ملف تعريف الارتباط بـMax-Age=0 فيرتّب المتصفح فقط.
  • المعرّف في ملف تعريف الارتباط وحده، لا في العنوان (URL) أبداً، حيث يتسرّب إلى سجل المتصفح والسجلات وترويسات Referer.
يحفظ تسجيل الدخول الجلسة على الخادم ولا يرسل إلا معرّفها العشوائي في Set-Cookie؛ ويجب أن يُنهي تسجيل الخروج ذلك السجلّ، فحين يعيد المختبِر إرسال المعرّف القديم يُعاد توجيهه إلى صفحة الدخول.
  • المتصفح حساب اختبار
  • خادم الويب portal.example
  • مخزن الجلسات ذاكرة أو قاعدة بيانات أو تخزين مؤقت
  1. 1 من المتصفح إلى خادم الويب: تسجيل الدخول POST /login
  2. 2 من خادم الويب إلى مخزن الجلسات: إنشاء جلسة بمعرّف عشوائي جديد يتوقف معرّف ما قبل الدخول عن العمل
  3. 3 من خادم الويب إلى المتصفح: لا يذهب إلى المتصفح إلا المعرّف ردّ Set-Cookie: sid=k3Vq…; Secure; HttpOnly
  4. 4 من المتصفح إلى خادم الويب: كل طلب مطابق يحمله Cookie: sid=k3Vq…
  5. 5 من خادم الويب إلى مخزن الجلسات: البحث عن المعرّف: جلسة سارية يبدأ عدّاد الخمول من جديد
  6. 6 من خادم الويب إلى المتصفح: لوحة تحكم هذا المستخدم ردّ 200 OK
  7. 7 من المتصفح إلى خادم الويب: تسجيل الخروج POST /logout
  8. 8 من خادم الويب إلى مخزن الجلسات: إنهاء سجلّ الجلسة الخطوة التي تُخرج المستخدم فعلاً
  9. 9 من خادم الويب إلى المتصفح: حذف ملف تعريف الارتباط ردّ Set-Cookie: sid=; Path=/; Max-Age=0
  10. 10 من المتصفح إلى خادم الويب: المختبِر يعيد إرسال المعرّف القديم Cookie: sid=k3Vq…
  11. 11 من خادم الويب إلى مخزن الجلسات: البحث عن المعرّف: لا جلسة
  12. 12 من خادم الويب إلى المتصفح: صفحة الدخول، ولا بيانات من اللوحة أبداً ردّ 302 Location: /login نجاح

النتيجة: ملف تعريف الارتباط مجرد مفتاح: لا يحمي تسجيل الخروج والمهلات المستخدم إلا حين يُنهي الخادم السجلّ.

مثال تطبيقي: تتبّع جلسة تسجيل دخول واختبارها

بوابة موظفين في بيئة اختبار، https://portal.example، متطلبها: «تنتهي الجلسة بعد ⁦15⁩ دقيقة بلا نشاط، وبعد ⁦8⁩ ساعات من تسجيل الدخول. وتسجيل الخروج يُنهي الجلسة». بحساب اختبار ولوحة Network مفتوحة، يسجّل المختبِر الدخول ويفتح لوحة التحكم ثم يسجّل الخروج، ويحفظ التبادل أدناه.

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

  • السمات: لـsid السمات Secure وHttpOnly وSameSite=Lax، وليس له Domain ولا Max-Age.
  • التجديد: أعطى الموقع الزائرَ المجهول جلسة قبل الدخول (Ae5f…)؛ وهذه القيمة تختلف عن القيمة الجديدة، والطلب المرسل بها ينتهي إلى صفحة الدخول.
  • الخروج: الحذف يكرر Path=/، وإعادة إرسال القيمة القديمة بـcurl (يطبع الخيار -i ترويسات الاستجابة، ويضيف -H ترويسة إلى الطلب)، مثلاً curl -i -H "Cookie: sid=k3Vq9XbT2mR7wLp4" https://portal.example/dashboard، تُرجع إعادة توجيه إلى /login، ولا بيانات من لوحة التحكم أبداً.
  • مهلة الخمول عند حدّها: تأخير الشبكة ومؤقّت الخادم يجعلان القياس بالثانية بالضبط غير موثوق، فاتفق على هامش صغير واختبر جانبَي الحد، مثلاً طلباً بعد ⁦14⁩ دقيقة و⁦50⁩ ثانية من الخمول (ما زال يعمل) وطلباً بعد ⁦15⁩ دقيقة و⁦10⁩ ثوانٍ (صفحة الدخول). واسأل هل يمكن استخدام مهلات أقصر في بيئة الاختبار.
  • المهلة المطلقة: رغم النشاط المستمر، تنتهي الجلسة بعد ⁦8⁩ ساعات من الدخول.
  • النطاق: لا يستلم docs.portal.example المعرّف sid أبداً.
POST /login HTTP/1.1
Host: portal.example
Cookie: sid=Ae5fUq0Zr8Ty2Nc6

HTTP/1.1 303 See Other
Location: /dashboard
Set-Cookie: sid=k3Vq9XbT2mR7wLp4; Path=/; Secure; HttpOnly; SameSite=Lax

GET /dashboard HTTP/1.1
Host: portal.example
Cookie: sid=k3Vq9XbT2mR7wLp4

POST /logout HTTP/1.1
Host: portal.example
Cookie: sid=k3Vq9XbT2mR7wLp4

HTTP/1.1 303 See Other
Location: /login
Set-Cookie: sid=; Path=/; Max-Age=0; Secure; HttpOnly; SameSite=Lax

جرّبها: محلّل ملفات تعريف الارتباط (Cookies) جرّبها: مولّد أوامر cURL

أخطاء شائعة

  • اعتماد تسجيل الخروج ناجحاً لأن ملف تعريف الارتباط اختفى من المتصفح، دون إعادة إرسال المعرّف القديم إلى الخادم.
  • البحث عن Secure أو HttpOnly في ترويسة Cookie في الطلب؛ فالسمات لا تظهر إلا في Set-Cookie.
  • معاملة Max-Age على أنها مهلة الجلسة بدلاً من اختبار المهلة التي يفرضها الخادم.
  • افتراض أن HttpOnly يمنع البرمجة النصية عبر المواقع (XSS) أو أن SameSite يمنع كل طلب مزوّر.
  • إهمال Domain وPath: ملف تعريف ارتباط جلسة يمتد إلى النطاق الأعلى، أو تسجيل خروج يحذف بقيمة Path مختلفة.
  • لصق معرّفات جلسات سارية في تقارير الأخطاء أو المحادثات أو لقطات الشاشة بدلاً من إخفائها.

من منظور ضمان الجودة

سلوك الجلسة يأتي في الغالب من إعدادات إطار العمل، وكثيراً ما تُترك على قيمها الافتراضية، لذا اطلب سياسة الجلسات مبكراً: اسم ملف تعريف الارتباط وسماته، والمهلتان، والجلسات المتزامنة، وماذا يفعل تسجيل الخروج وتغيير كلمة المرور. فإذا كُتبت في جدول قصير صارت أساس اختبار يستطيع المطوّرون ومراجعو الأمان تأكيده؛ وأي خانة فارغة فيه سؤال عن المتطلبات.

احتفظ بهذه الفحوص في حزمة الانحدار، وأعد تشغيلها بعد ترقيات إطار العمل وتغييرات الوكيل (proxy) أو شبكة توصيل المحتوى (CDN) والانتقال إلى نطاق جديد، لأنها تغيّر ملفات تعريف الارتباط بصمت. وفي التقرير قدّم الطلب والاستجابة مع إخفاء القيم، وإصدار المتصفح، والطوابع الزمنية، واترك الهجمات الأعمق على إدارة الجلسات لمختصي الأمان ولدليل OWASP لاختبار أمان الويب (Web Security Testing Guide).

تمرين عملي

راجع ملف تعريف ارتباط الجلسة في بوابة عيادة

المطلوب

بوابة حجز مواعيد لعيادة في بيئة اختبار ترسل الترويسات أدناه. ويلاحظ زميل أن المتصفح ما زال يرسل قيمة SESSION القديمة بعد تسجيل الخروج، وأن إعادة إرسالها بـcurl تُرجع 200 OK مع مواعيد المستخدم. اعثر على كل عيب أو خطر، وسمِّ القاعدة التي يخالفها، واكتب اختبار تأكيد لكل إصلاح.

المادة
Response to POST /login on https://clinic.example
Set-Cookie: SESSION=u1042-20261002-0915; Domain=clinic.example; Path=/; Max-Age=2592000

Response to POST /logout
Set-Cookie: SESSION=; Path=/app; Max-Age=0

Login of a second test user at 11:30
Set-Cookie: SESSION=u1043-20261002-1130; Domain=clinic.example; Path=/; Max-Age=2592000
الخطوات
  1. اقرأ ترويسة Set-Cookie الخاصة بالدخول سمةً سمةً، أو الصقها في محلّل ملفات تعريف الارتباط (Cookie Analyzer).
  2. قارن بها ترويسة Set-Cookie الخاصة بالخروج: الاسم وDomain وPath.
  3. حدّد ما يقوله الطلب المعاد إرساله عن الجلسة على الخادم.
إظهار الإجابة النموذجية
الإجابة النموذجية

معرّف قابل للتنبؤ: رقم المستخدم مع تاريخ الدخول ووقته، كما تؤكد القيمة الثانية، فيمكن تخمين معرّفات المستخدمين الآخرين. ويجب أن يكون عشوائياً بإنتروبيا لا تقل عن ⁦64⁩ بت. الاختبار: قيم عمليات الدخول المتكررة لا تحوي رقم المستخدم ولا الوقت ولا نمطاً ظاهراً، وتؤكد مراجعة الشيفرة استخدام مولّد آمن تشفيرياً.

غياب Secure وHttpOnly وSameSite، وDomain=clinic.example ترسل ملف تعريف الارتباط إلى كل نطاق فرعي، وMax-Age=2592000 تُبقيه ⁦30⁩ يوماً عبر إعادة تشغيل المتصفح، خلافاً لتوصية OWASP بملفات جلسة غير دائمة؛ فاسأل ماذا يقول المتطلب عن «تذكرني». الاختبار: يعرض محلّل ملفات تعريف الارتباط السمات الثلاث، ولا Domain ولا Max-Age.

الحذف يستخدم Path=/app ومن دون Domain، فلا يصيب ملف تعريف الارتباط الأصلي، فيحتفظ به المتصفح؛ لأن ملف تعريف الارتباط يُعرَّف بالاسم والنطاق والمسار معاً. ويجب أن يكرر الاسم وDomain وPath كما يستخدمها ملف الدخول فعلاً (بعد الإصلاح السابق: بلا Domain ومع Path=/). الاختبار: بعد تسجيل الخروج لا تضم قائمة ملفات تعريف الارتباط في المتصفح SESSION، ولا يحمل الطلب التالي ملف SESSION.

الأخطر: لم يُنهِ الخادم الجلسة عند الخروج، مع أن تسجيل الخروج يجب أن يُنهي السجلّ على الخادم، فكل من يملك القيمة القديمة يرى مواعيد المستخدم. الخطورة: حرج (Critical). الاختبار: إعادة الإرسال بعد الخروج تتلقى إعادة توجيه إلى صفحة الدخول أو 401. وأضف اختبارات للتجديد عند الدخول وللمهلتين.

أسئلة شائعة

ما الفرق بين ملف تعريف ارتباط الجلسة والجلسة نفسها؟

ملف تعريف ارتباط الجلسة هو أي ملف تعريف ارتباط بلا Expires أو Max-Age، ويحذفه المتصفح عند انتهاء جلسته هو، وإن كان المتصفح الذي يستعيد الجلسة السابقة عند إعادة تشغيله قد يُبقيه. أما الجلسة فهي السجلّ على الخادم الذي يشير إليه المعرّف. وقد يكون المعرّف في ملف جلسة أو في ملف دائم، وحذف ملف تعريف الارتباط لا يُنهي جلسة الخادم، ولهذا يُختبر تسجيل الخروج والمهلات من جهة الخادم.

كيف أختبر مهلة خمول من ⁦30⁩ دقيقة دون أن أنتظر ⁦30⁩ دقيقة في كل مرة؟

اسأل المطوّرين هل المهلة قابلة للضبط، واستخدم قيمة قصيرة مثل دقيقتين في بيئة الاختبار لتختبر الآلية بالقيم الحدّية. ثم أكّد القيمة الحقيقية مرة واحدة، في الإعدادات أو باختبار طويل واحد، في بيئة مضبوطة مثل بيئة الإنتاج. وتعديل انتهاء ملف تعريف الارتباط في المتصفح لا يثبت شيئاً، لأن ساعة الخادم هي التي تقرر.

هل تتلقى الجلسة المنتهية ⁦401⁩ أم إعادة توجيه؟

يعتمد ذلك على العميل. فصفحة المتصفح تتلقى عادةً إعادة توجيه مثل 302 أو 303 إلى صفحة الدخول، وتُرجع الواجهة البرمجية 401 Unauthorized. وما لا يجوز أبداً هو 200 مع بيانات المستخدم، أو صفحة خطأ فيها تتبّع المكدس (stack trace). وتحقق من أن السلوك المتفق عليه واحد في كل مسار محمي.

هل تحمي SameSite وحدها من تزوير الطلبات عبر المواقع (CSRF)؟

تزوير الطلبات عبر المواقع يعني أن يجعل موقعٌ آخر متصفحَ مستخدم مسجّل الدخول يرسل إلى تطبيقك طلباً لم يقصده، مرفقاً به ملفات تعريف الارتباط الخاصة بالمستخدم. وSameSite تقلل هذا الخطر، لكن ورقة OWASP المرجعية لمنع تزوير الطلبات عبر المواقع تعدّها طبقة دفاع إضافية لا بديلاً عن دفاع حقيقي ضد CSRF مثل رموز مكافحة CSRF. فقيمة Lax ما زالت ترسل ملف تعريف الارتباط في التنقل على المستوى الأعلى بطريقة GET من مواقع أخرى، فيبقى كل إجراء يغيّر الحالة ويمكن الوصول إليه بـGET مكشوفاً. اختبر السمة والرمز كليهما.

المراجع

تدرّب بأدوات متقن

تحليل ترويسات طلبات واستجابات HTTP الخام إلى جدول منظّم مع الشروحات.

الويب

إنشاء أوامر cURL من الطريقة وعنوان URL والترويسات والمتن وخيارات المصادقة.

الويب

تفكيك عنوان URL إلى البروتوكول والمضيف والمنفذ والمسار ومعاملات الاستعلام والجزء (fragment) وبيانات الاعتماد.

الويب

للتعمّق أكثر

تقدّمك في هذا الموضوع

جزء من مسار تعلم ضمان الجودة