فحص الأسرار والاستجابة للتسريبات
فحص الأسرار والاستجابة للتسريبات
مفتاح AWS مضمّن في الكود، أو سر Stripe، أو كلمة مرور قاعدة بيانات ملتزمة في مستودع عام — هذه هي أكثر أنواع حوادث الأمان شيوعاً وأكثرها قابلية للوقاية وأشدها ضرراً في التسليم البرمجي الحديث. حين تبيّن أن اختراق Uber عام 2022 يعود إلى بيانات اعتماد مخزّنة في مستودع GitHub خاص، وحين تقوم روبوتات آلية بفحص مستودعات GitHub خلال ثوانٍ من كل push، فإن السؤال ليس هل تفحص الأسرار — بل كم طبقة دفاع تشغّل.
يغطي هذا الدرس دورة الحياة الكاملة: حجب الأسرار قبل دخولها إلى نظام التحكم بالإصدارات، واصطياد ما يتسرب منها في CI، والتنبيه على التسريبات في التاريخ الموجود، وتنفيذ دليل الاستجابة للحوادث حين يخرج مفتاح ما إلى العالم الخارجي.
الطبقة الأولى: خطافات ما قبل الالتزام مع detect-secrets و Gitleaks
أرخص وقت لاكتشاف السر هو قبل إنشاء الالتزام. Gitleaks وdetect-secrets هما الأداتان الأكثر انتشاراً، وتعمل معظم الفرق الناضجة بالأداتين معاً — Gitleaks لسرعته وتغطيته الواسعة بالتعابير المنتظمة، وdetect-secrets لكشفه القائم على الإنتروبيا وسير عمل تدقيق الخط الأساسي.
الإعداد القياسي يستخدم pre-commit (إطار عمل Python) لتنسيق الخطافات من ملف .pre-commit-config.yaml واحد في جذر المستودع:
ثبّت وفعّل بـ pip install pre-commit && pre-commit install. على أجهزة Mac يمكن التوزيع عبر Homebrew. للمستودعات التي لا تستطيع ضمان تشغيل كل مساهم لـ pre-commit install، الخطاف عائق بسيط لا ضمان — لهذا فحص CI إلزامي.
يقرأ Gitleaks إعداد .gitleaks.toml لقوائم السماح والقواعد المخصصة. أهم ضبط دقيق هو قائمة سماح خاصة بالمشروع حتى لا تولّد تركيبات الاختبار ببيانات اعتماد مزيفة ضجيجاً:
detect-secrets أولاً (detect-secrets scan > .secrets.baseline) حتى لا تحجب المشكلات الموجودة في الخط الأساسي جميع الالتزامات — فقط الأسرار الجديدة الصافية تثير الفشل. جدوِل مهمة تدقيق منفصلة لمعالجة متأخرات الخط الأساسي.
الطبقة الثانية: الفحص في خط CI
CI هو بوابة التطبيق الإلزامية. حتى لو نفّذ كل مطوّر pre-commit بإخلاص، يصطاد فحص CI عمليات force-push، والالتزامات عبر محرر الويب، والتزامات روبوتات GitHub Actions التي تتجاوز الخطافات المحلية. شغّل Gitleaks على الفرق الكاملة لكل طلب سحب، وعلى كل push للفروع المحمية. العلامة --source تفحص فقط الالتزامات المدخلة في طلب السحب، مما يبقي وقت الفحص تحت خمس ثوانٍ لمعظم المستودعات.
ميزة Secret Scanning الخاصة بـ GitHub (متاحة في جميع المستودعات العامة وGitHub Advanced Security) تعمل باستمرار في الخلفية وترسل تنبيهات حماية push قبل وصول الالتزام إلى الفرع الافتراضي. فعّلها من Settings → Code security → Secret scanning → Push protection. تغطي أكثر من 200 نمط رمز شريك (AWS وGCP وStripe وTwilio وSlack وغيرها) بمعدلات إيجابيات كاذبة شبه معدومة لأن الأنماط تُتحقق منها في واجهة برمجة التطبيقات المباشرة للمزوّد.
الطبقة الثالثة: فحص التاريخ الموجود
حين تستقبل مستودعاً موجوداً، يجب فحص تاريخ الالتزامات الكامل — ليس فقط HEAD الحالي. الأسرار المحذوفة في التزام لاحق لا تزال في مخزن كائنات git، مرئية لأي شخص يستنسخ المستودع. استخدم gitleaks detect --source . --log-opts="--all" أو truffleHog لفحوصات التاريخ العميق. هذه مهمة تدقيق لمرة واحدة؛ نتائجها تُغذّي متأخرات المعالجة المتتبعة في نظام الأمان (Jira أو GitHub Issues أو لوحة إدارة أسرار مخصصة).
الاستجابة للحوادث: دليل الخطوات الخمس
حين يتسرب سر — يكتشفه ماسح، أو يبلّغ عنه باحث bug bounty، أو يُكتشف في إشعار اختراق — السرعة هي كل شيء. قِيست الروبوتات وهي تستهلك مفاتيح AWS المدفوعة حديثاً خلال أربع ثوانٍ من التعرض. كل دقيقة تأخر تتوسع فيها دائرة الأضرار.
- الإلغاء الفوري. لا تنتظر تأكيد الاستغلال. اذهب إلى وحدة تحكم مزوّد بيانات الاعتماد (AWS IAM، أو GCP IAM، أو لوحة تحكم Stripe، أو إعدادات GitHub) وعطّل المفتاح أو احذفه. إن كان المفتاح يتحكم في البنية التحتية، اقبل الانقطاع المؤقت — فهو أقل ضرراً من الاختراق. لمفاتيح AWS:
aws iam delete-access-key --access-key-id AKIA.... لرموز GitHub: ألغِها من Settings → Developer settings → Personal access tokens. - التدوير وإصدار بديل. أنشئ بيانات اعتماد جديدة فوراً وأدخلها في مدير الأسرار (HashiCorp Vault، أو AWS Secrets Manager، أو GCP Secret Manager). حدّث جميع الأنظمة المستخدمة للمفتاح القديم. لا تُعد استخدام مواد الاعتماد المخترقة أبداً.
- إعادة كتابة تاريخ git (أو قبول التعرض). إزالة سر من الالتزام الحالي لا تزيله من تاريخ git — كل من استنسخ المستودع أو خزّنه تخبئةً يملكه بالفعل. استخدم BFG Repo-Cleaner أو
git filter-repoلإعادة كتابة التاريخ، ثم force-push وأخطر جميع المتعاونين بإعادة الاستنساخ. هذا مُعطّل على المستودعات النشطة؛ وازنه مع ملف مخاطر بيانات الاعتماد المسرّبة. - تدقيق سجلات الوصول. اسحب سجلات CloudTrail (AWS)، أو سجلات تدقيق Stackdriver (GCP)، أو ما يعادلها. ابحث عن استدعاءات API بالمفتاح المخترق من IPs غير متوقعة، أو مناطق غير معتادة، أو في أوقات غير اعتيادية. هذا يحدد ما إذا كان الاستغلال قد وقع وما الموارد التي جرى الوصول إليها.
- السبب الجذري والإصلاح الشامل. اكتب تقرير ما بعد الحادث بلا لوم: كيف وصل السر إلى الالتزام؟ هل كان خطاف pre-commit مفقوداً؟ هل كان مطوّر يتجاوز الخطافات بـ
--no-verify؟ هل جرى تسريب سر CI عرضاً في السجلات؟ عالج الثغرة الشاملة — ليس هذه الحالة فحسب.
git commit --amend أو soft-reset أبداً لـ"إزالة" سر. يظل كائن الالتزام الأصلي في مخزن كائنات git ويمكن الوصول إليه من أي شخص لديه استنساخ أو ذاكرة تخزين مؤقت على GitHub حتى تُجرى إعادة كتابة تاريخ كاملة. افترض أن السر متاح للعموم تماماً لحظة دفعه.
منع الأسرار من المصدر: تكامل Vault
الفحص يصطاد الأسرار التي تتسرب. الإصلاح طويل الأمد هو جعل التشفير الصريح مستحيلاً لأن الأسرار لا توجد أصلاً كنص عادي في بيئة المطوّر. هذا يعني أن كل تطبيق يقرأ بيانات الاعتماد من مدير الأسرار في وقت التشغيل — لا من ملفات .env، ولا من متغيرات البيئة المضمّنة في صور الحاويات، وبالتأكيد ليس من كود المصدر.
في بيئة Kubernetes، النمط القياسي هو External Secrets Operator (ESO)، الذي يزامن الأسرار من Vault أو AWS Secrets Manager إلى كائنات Kubernetes Secret التي تستخدمها الحاوية كمتغيرات بيئة أو ملفات مُركّبة. مواد السر لا تمر أبداً عبر خط CI أو بناء صورة الحاوية.
فحص الأسرار ليس تدقيقاً لمرة واحدة — بل هو ضابط يعمل باستمرار. المنظمات التي تتعامل مع الأسرار بكفاءة تعامل كل بيانات اعتماد باعتبارها عابرة: قصيرة العمر، تُدار تلقائياً، ولا تُقرأ من قِبل البشر في الإنتاج. طبقة الفحص موجودة ليس لأن نمط vault أخفق، بل لأن البشر حتماً يأخذون اختصارات أثناء الحوادث وجلسات التصحيح والتطوير المحلي. مهمتك هي جعل تلك الاختصارات مرئية وقابلة للتصحيح قبل أن تتحول إلى اختراقات.