الرؤوس كأكياس
تتعامل أطر تسجيل HTTP مع رؤوس الطلب كمجموعة من أزواج المفتاح والقيمة. تكشف واجهة برمجة التسجيل عن المجموعة كاملة. يُفعّل المشغّلون تسجيل الرؤوس لأغراض التصحيح: عند فشل الطلب، تروي الرؤوس القصة. لا توجد قائمة حظر مدمجة. لا يوجد تصفية للاعتمادات في التوثيق. الرؤوس الكاملة تُكتب إلى القرص.
رؤوس الاعتمادات في طلب نموذجي:
- Authorization: Bearer eyJhbGciOiJIUzI1NiJ9... (رمز JWT أو OAuth)
- Cookie: session=abc123; auth=xyz789
- X-API-Key: sk-live-abc123...
- X-Auth-Token: ghp_abc123... (نمط رمز الوصول الشخصي لـ GitHub)
تُصادق هذه القيم على الطلب. وعند كتابتها في ملف السجل، فإنها تُصادق على أي طلب.
مسار بيانات الاعتماد
لا تبقى بيانات الاعتماد المكتوبة في ملف السجل في مكان واحد. بل تنتقل:
1. يكتب خادم الويب إلى /var/log/nginx/access.log
2. يقوم وكيل تدوير السجلات (logrotate) بنسخها إلى /var/log/nginx/access.log.1
3. يقرأ شاحن السجلات (Fluentd, Filebeat, Logstash) ويرسلها إلى المُجمّع
4. مُجمِّع السجلات (Elasticsearch، Splunk، Datadog) يقوم بالفهرسة والتخزين
5. يتم الاحتفاظ بها لمدة 30-90 يومًا وفقًا للسياسة الافتراضية
توجد بيانات الاعتماد في جميع المواقع الخمسة في وقت واحد. إبطال رمز الجلسة لا يزيل بيانات الاعتماد من مُجمِّع السجلات. تبقى قابلة للبحث والتصدير والوصول لأي شخص لديه صلاحية الوصول إلى السجلات طوال فترة الاحتفاظ الكاملة.
نافذة التعرض
نافذة التعرض لبيانات الاعتماد في الذاكرة: max(مدة الجلسة، عمر العملية). الجلسة: ساعات إلى أيام. العملية: ساعات إلى أسابيع.
نافذة التعرض لبيانات الاعتماد في السجل: max(مدة الجلسة، فترة الاحتفاظ بالسجل). الجلسة: ساعات إلى أيام. فترة الاحتفاظ: 30-90 يومًا.
بيانات الاعتماد المسروقة من الذاكرة تتطلب وجود المهاجم أثناء نافذة الجلسة. أما بيانات الاعتماد المسروقة من السجل فتتطلب فقط الوصول إلى مُجمِّع السجلات، وهو متاح بأثر رجعي طوال فترة الاحتفاظ الكاملة.
MOAD-0003 مقابل MOAD-0004
MOAD-0003 (تسريب سياق): بيانات اعتماد في الذاكرة تتسرب إلى معالج الطلب الخطأ. يمكن الوصول إليها فقط أثناء نافذة العملية، عبر مجموعة الخيوط. مؤقتة.
MOAD-0004 (سر مسجّل): بيانات اعتماد على القرص تستمر عبر تدوير السجلات، وشحنها، وتجميعها. يمكن الوصول إليها بأثر رجعي، لأي شخص لديه وصول إلى السجلات، لمدة 30-90 يومًا. مستمرة.
الفرق الهيكلي: مؤقت مقابل مستمر. يعمل الإصلاح على طبقة مختلفة.
مؤقت مقابل مستمر
يحدد التمييز بين المؤقت والمستمر سطح المخاطر، وطبقة الإصلاح، ومتطلبات الاستجابة للحوادث.
قائمة حظر بيانات الاعتماد في طبقة التسلسل
الحل: قائمة حظر بيانات الاعتماد في طبقة التسلسل. قبل أن تصل أي قيمة رأس إلى مخرجات السجل، تحقق من اسم الرأس مقابل القائمة السوداء. استبدل القيمة بـ [REDACTED].
CREDENTIAL_HEADERS = {
'authorization',
'cookie',
'x-api-key',
'x-auth-token',
'x-csrf-token',
'proxy-authorization',
}
def sanitize_headers(headers: dict) -> dict:
return {
k: '[REDACTED]' if k.lower() in CREDENTIAL_HEADERS else v
for k, v in headers.items()
}
تنتمي القائمة السوداء إلى طبقة التسلسل (serialization layer)، وليس إلى طبقة استعلام السجلات (log query layer). تعني عملية التنقيح في طبقة استعلام السجلات: تُطبَّق بعد وصول بيانات الاعتماد إلى القرص؛ حيث لا تزال القيمة الأصلية موجودة، لكنها مخفية فقط عن العرض. أما عملية التنقيح في طبقة التسلسل: فلا تصل بيانات الاعتماد أبدًا إلى القرص. ولا تدخل القيمة الأصلية مطلقًا إلى ملف السجل أو شاحن السجلات أو مجمّع السجلات.
اختبار القائمة السوداء
ثلاثة أنماط اختبار:
- إيجابي: طلب يحتوي على Authorization: Bearer token123 ينتج عنه سجل يحتوي على Authorization: [REDACTED]
- سلبي: طلب يحتوي على Content-Type: application/json ينتج إدخال سجل مع الحفاظ على القيمة كما هي
- غير حساس لحالة الأحرف: AUTHORIZATION: Bearer token123 ينتج أيضًا [REDACTED] (أسماء رؤوس HTTP غير حساسة لحالة الأحرف)
تتطلب القائمة المحظورة صيانة: أنماط رؤوس بيانات الاعتماد الجديدة (مثل رؤوس X-Service-Auth المخصصة) تحتاج إلى إضافتها صراحة. الإصلاح هيكلي لكنه ليس ذاتي الصيانة.
تطبيق القائمة المحظورة
يقوم فريق بتكوين تنسيق سجل وصول Nginx ليشمل جميع رؤوس الطلبات لتصحيح حادث إنتاجي. التكوين:
log_format debug_format '$remote_addr - $request - $http_authorization - $http_cookie';
access_log /var/log/nginx/debug.log debug_format;
يقومون بحل الحادث ويعتزمون إزالة إعدادات التصحيح، لكن التغيير لا يصل إلى الإنتاج قبل دورة النشر التالية (بعد 7 أيام).