ملفات تعريف الارتباط (Cookies)
ملفات تعريف الارتباط (Cookies)
ملف تعريف الارتباط (cookie) هو قطعة صغيرة من البيانات يُرسلها الخادم إلى المتصفح، فيُرفقها المتصفح تلقائيًا بكل طلب لاحق إلى نفس المصدر. على الرغم من بساطتها، تُشكّل ملفات الارتباط حجر الأساس في هوية الويب: فهي تحمل رموز الجلسات، وتتذكر تفضيلات المستخدم، وتُشغّل التحليلات. يتناول هذا الدرس كيفية إنشاء ملفات الارتباط وقراءتها في Jakarta Servlet، وما يتحكم فيه كل خاصية، والقرارات الأمنية التي يجب أن يتخذها المطوّر بوعي كامل.
كيف تتدفق ملفات الارتباط
تتبع آلية عمل ملفات الارتباط بروتوكول HTTP بدقة. حين يريد الخادم تعيين ملف ارتباط يُضيف ترويسة استجابة Set-Cookie. يُخزّن المتصفح الملف ويُضيفه إلى ترويسة طلب Cookie في كل طلب مستقبلي مطابق. تُغلّف واجهة Servlet API هذه التبادل عبر الفئة Cookie حتى تتعامل مع كائنات بدلًا من سلاسل الترويسات الخام.
maxAge على 0.
إنشاء ملف ارتباط
أنشئ كائن jakarta.servlet.http.Cookie، اضبط خصائصه، ثم أضفه إلى الاستجابة قبل إرسال getWriter() أو getOutputStream():
قراءة ملفات الارتباط
يُعيد request.getCookies() جميع ملفات الارتباط التي أرسلها المتصفح، أو null إن لم يكن هناك أي منها. لا توجد طريقة "احصل على ملف بالاسم" — تكرّر على المصفوفة بنفسك. يستحق كتابة دالة مساعدة مرة واحدة وإعادة استخدامها عبر جميع الـ Servlets:
في موقع الاستدعاء:
خصائص ملفات الارتباط بالتفصيل
كل خاصية في Cookie تُعيَّن مباشرةً إلى توجيه في Set-Cookie. الخطأ فيها يكلفك إما وظيفةً أو أمانًا.
Max-Age وExpires — الاستمرارية مقابل الجلسة
إن لم تستدعِ setMaxAge() على الإطلاق، يكون الملف ملف ارتباط جلسة: يعيش في الذاكرة ويختفي حين يُغلق المتصفح. استدعاء setMaxAge(seconds) بعدد صحيح موجب يجعله ملف ارتباط دائم — يكتبه المتصفح على القرص ويُرسله مرة أخرى حتى بعد إعادة التشغيل.
setMaxAge(0)— يأمر المتصفح بحذف الملف فورًا (نمط الحذف).setMaxAge(-1)— مكافئ لعدم الاستدعاء أصلًا؛ الملف مرتبط بالجلسة.setMaxAge(n)حيث n > 0 — احتفظ به لمدة n ثانية من لحظة استلام الاستجابة.
Expires هي تاريخ مطلق يكون هشًا إذا كانت ساعة العميل خاطئة. أما Max-Age فهو نسبي وبالتالي موثوق. المتصفحات الحديثة تُكرّم الاثنين، لكن Max-Age له الأولوية حين يوجد الاثنان معًا.
Domain وPath — تحديد نطاق الطلبات التي تتضمن الملف
يتحكم setDomain() في أسماء المضيفين التي تستقبل الملف. تركه بدون ضبط هو الافتراضي الآمن: لا يُرسل الملف إلا إلى المضيف الذي أنشأه بالضبط. تعيين domain=example.com يجعل الملف يُرسل إلى api.example.com وapp.example.com وغيرها — مفيد لتسجيل الدخول الموحّد عبر النطاقات الفرعية، لكنه يوسّع سطح الهجوم.
يُقيّد setPath() إرسال الملف إلى عناوين URL تحت هذا المسار. ضبط /admin يعني أن الملف لا يُرسل إلا مع طلبات /admin/*. ضبط / يعني إرساله مع جميع الطلبات إلى المضيف — مناسب لملف هوية المستخدم، لكنه مُبذّر (ومحفوف بمخاطر طفيفة) لملف لا يحتاجه إلا قسم واحد من موقعك.
HttpOnly — حجب وصول JavaScript
ملف الارتباط المحمي بـ HttpOnly غير مرئي لـ document.cookie في JavaScript. هذه العلامة الواحدة تُلغي أكثر عواقب هجمات XSS شيوعًا: لا يستطيع السكريبت المُحقن في صفحتك سرقة ملف ارتباط الجلسة. ضع هذه العلامة دائمًا على ملفات المصادقة.
Secure — فرض HTTPS
لا يُرسَل ملف الارتباط المحمي بـ Secure إلا عبر TLS. بدون هذه العلامة يُرسل الملف مع طلبات HTTP بنص واضح — يمكن قراءته من قِبَل أي شخص على نفس شريحة الشبكة. في بيئة الإنتاج يجب أن تحمل جميع ملفات الارتباط الحساسة علامة Secure. قد تُهملها أثناء التطوير المحلي (إذ عادةً ما يكون localhost بروتوكول HTTP)، لكن يجب أن تكون موجودة قبل النشر.
SameSite — الحماية من تزوير الطلبات عبر المواقع
لم تُضف واجهة Servlet API دعمًا أصليًا لـ SameSite إلا مؤخرًا. في Jakarta EE 10 / Servlet 6.0، اكتسبت Cookie الطريقة setAttribute("SameSite", "Strict"). في الحاويات القديمة يجب ضبطها بكتابة الترويسة الخام:
- Strict — لا يُرسل الملف أبدًا مع الطلبات عبر المواقع. أقوى حماية من CSRF؛ لكنه يكسر التدفقات التي يجب أن يصل فيها رابط من موقع آخر إلى الجلسة الحالية للمستخدم.
- Lax — يُرسل الملف مع التنقل عبر الروابط من المستوى الأعلى (النقر على رابط) لكن ليس مع الطلبات الفرعية المدمجة (الصور، الإطارات، fetch). الإعداد الافتراضي في معظم المتصفحات الحديثة.
- None — يُرسل الملف دائمًا عبر المواقع. يستلزم وجود
Secure. استخدمه فقط لتكاملات الطرف الثالث (أدوات الدفع، الخرائط المدمجة).
حذف ملف ارتباط
لا توجد واجهة برمجية للحذف. أرسل ملف ارتباط بديلًا بنفس الاسم والمسار، لكن مع ضبط maxAge على 0:
theme مُعيَّن على مسار / يختلف عن ملف باسم theme مُعيَّن على مسار /app. إرسال ملف منتهي الصلاحية على المسار الخاطئ يُبقي الأصلي كما هو وينشئ ملفًا جديدًا منتهيًا يتجاهله المتصفح — وهو خطأ شائع يصعب تشخيصه.
قائمة التحقق الأمنية العملية
قبل إرسال أي ملف ارتباط إلى الإنتاج، تحقق من:
- تعيين
HttpOnlyعلى جميع ملفات المصادقة والجلسة. - تعيين
Secure— وتأكد من أن موزّع الحمل أو الوكيل العكسي يفرض HTTPS. - تعيين
SameSite=LaxأوStrictعلى ملفات الجلسة. - قيم ملفات الارتباط التي تحمل بيانات حساسة أمنيًا (معرّفات الجلسة، رموز CSRF) تُولَّد عشوائيًا ولا يتحكم فيها المستخدم — لا تخزّن اسم المستخدم نفسه كقيمة ملف ارتباط أبدًا.
Pathضيّق قدر الإمكان وظيفيًا.- ملفات الارتباط الدائمة تنتهي صلاحيتها في نافذة زمنية معقولة — وليس 10 سنوات.
الخلاصة
إنشاء ملف ارتباط يحتاج ثلاثة أسطر: أنشئ Cookie، اضبط خصائصه، استدعِ resp.addCookie(). قراءته تستلزم التكرار على req.getCookies() — دالة مساعدة تُوفّر التكرار. الحرفة الحقيقية تكمن في الخصائص: maxAge يُقرّر الاستمرارية، وpath وdomain يُحدّدان نطاق الإرسال، وhttpOnly وsecure وsameSite معًا يُحدّدان ما إذا كانت ملفاتك آمنة لحمل بيانات هوية حساسة. في الدرس القادم سترى كيف تستخدم الجلسات ملف ارتباط HttpOnly واحدًا كآلية نقل — ولماذا يهم هذا القرار التصميمي.