CodeAuditAgent
كل المقالات
  • الأمان
  • Git
  • الأسرار

الأسرار المسرّبة في سجل Git: اكتشاف وتدوير ووقاية

حذف مفتاح API مرفوع لا يزيله من سجل git. كيف تجد الأسرار المسرّبة، وتدوّرها أولًا، وتعيد كتابة السجل بأمان، وتمنع التسريب التالي.

· قراءة في 7 دقائق · Lina Source LLC

يرفع أحدهم ملف .env، أو يلصق مفتاح API فعّالًا في وحدة إعدادات ليختبر شيئًا على عجل. يلاحظ المراجع ذلك، فيُحذف المفتاح في الإيداع التالي، ويمضي الجميع في عملهم. لكن المفتاح ما يزال هناك. فـ Git يحتفظ بكل نسخة من كل ملف، وأي شخص يستطيع استنساخ المستودع يمكنه قراءة الإيداع الذي أضافه.

تُصنَّف بيانات الاعتماد المضمّنة في الكود تحت CWE-798. يتناول هذا الدليل ما يجب فعله حين يكون أحدها قد وصل بالفعل إلى السجل: اعثر على كل سر، ودوّرها جميعًا قبل أي شيء آخر، وقرّر ما إذا كانت إعادة كتابة السجل تستحق العناء، وأقم الضوابط التي توقف التسريب التالي.

لماذا لا يكفي حذف السطر

الإيداع الذي يزيل سرًّا يضيف لقطة جديدة خالية منه. أما اللقطة السابقة، التي تحتوي على السر، فما يزال سجل الفرع يشير إليها. يعرضها git log -p، ويستعيدها git checkout للإيداع القديم، وكل نسخة مستنسخة أو fork موجودة لديها نسخة منه بالفعل. ولا يفيد دمج الفرع بـ squash قبل الدمج إذا كانت الإيداعات الأصلية قد دُفعت يومًا: فقد يظل الخادم البعيد محتفظًا بها، ومن جلبها لديه نسخة محلية منها.

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

الخطوة 1: التدوير أولًا

التدوير هو الخطوة الوحيدة التي تزيل الخطر فعلًا. فإعادة كتابة السجل تخفي السر عن النسخ المستنسخة مستقبلًا، لكنها لا تفعل شيئًا حيال النسخ الموجودة أصلًا. لذا ألغِ بيانات الاعتماد واستبدلها قبل أن تلمس المستودع.

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

  • أنشئ مفتاحًا جديدًا في لوحة تحكم المزوّد وانشره عبر مسار الإعدادات المعتاد لديك.
  • ألغِ المفتاح القديم. لا تكتفِ بالتوقف عن استخدامه؛ فالمفتاح الصالح غير المستخدم يظل مفتاحًا صالحًا.
  • راجع سجلات التدقيق لدى المزوّد بحثًا عن أي نشاط بالمفتاح القديم منذ تاريخ الإيداع: استدعاءات API، ومستخدمون جدد، وصلاحيات مُعدّلة، وفواتير غير متوقعة.
  • إذا كان السر كلمة مرور لقاعدة بيانات أو مفتاح توقيع، ففكّر فيما كان يمكن أن يفتحه. فتسريب سر توقيع JWT يعني أن أي رمز كان يمكن تزويره، لذا أبطل الجلسات القائمة.
  • دوّن ما الذي كُشف، ولأي مدة، وما الذي غيّرته. ستحتاج إليه إذا سأل عميل أو مدقق.

الخطوة 2: اعثر على كل ما تسرّب

حيث يوجد سر واحد مرفوع، غالبًا ما توجد أسرار أخرى. ابحث في السجل كاملًا، لا في الشجرة الحالية فقط، وشمل كل الفروع والوسوم.

@@CODE@@

الأداتان gitleaks وtrufflehog ماسحان مفتوحا المصدر صُمّما لهذه المهمة. فهما يعرفان صيغ مفاتيح المزوّدين الشائعة، ويستطيع trufflehog التحقق مما إذا كانت بيانات الاعتماد المكتشفة ما تزال فعّالة. تستخدم إصدارات gitleaks الأقدم الأمر gitleaks detect --source . بدلًا من الأمر الفرعي git. شغّل الماسح مرة على السجل كاملًا، ثم أبقه يعمل على الإيداعات الجديدة. توقّع بعض النتائج الإيجابية الكاذبة، مثل بيانات الاختبار الثابتة والمفاتيح التوضيحية في الوثائق. راجع كلًّا منها، ثم سجّل النتائج الكاذبة المؤكدة في قائمة السماح أو ملف الأساس الخاص بالماسح، حتى لا يعرض التشغيل التالي إلا الاكتشافات الجديدة.

لا تنسَ الأماكن المحيطة بالمستودع: سجلات CI التي طبعت متغيرات البيئة، وتعليقات المشكلات وطلبات الدمج، وصفحات الويكي، وطبقات صور Docker المبنية من المستودع، وأي gists أو مقتطفات لُصقت أثناء تصحيح الأخطاء.

الخطوة 3: قرّر ما إذا كنت ستعيد كتابة السجل

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

الأداة git filter-repo هي ما يوصي به مشروع Git لهذا الغرض، بديلًا عن git filter-branch الأقدم. تعمل على نسخة مستنسخة حديثًا وتزيل الخادم البعيد origin كإجراء احترازي، لذا عليك إضافته مجددًا قبل الدفع.

@@CODE@@

ما لا تستطيع إعادة الكتابة فعله

  • لا تستطيع الوصول إلى النسخ المستنسخة الموجودة أو الـ forks أو ذاكرات CI المؤقتة أو النسخ الاحتياطية. فكل من جلب قبل إعادة الكتابة يحتفظ بالإيداعات القديمة.
  • على GitHub، المراجع المُنشأة لطلبات الدمج للقراءة فقط وقد تُبقي الإيداعات القديمة قابلة للوصول. وإزالة العروض المخزّنة مؤقتًا وتلك المراجع تتطلب التواصل مع دعم GitHub.
  • المتعاونون الذين يسحبون أو يدمجون من نسخة قديمة قد يدفعون السجل القديم مباشرة من جديد. اطلب من الجميع إعادة الاستنساخ، واحمِ الفرع ريثما يفعلون.
  • لا تزيل السر من أي مكان آخر نُسخ إليه: السجلات أو التذاكر أو رسائل الدردشة أو المخرجات المبنية.

لهذا السبب يهم الترتيب. دوّر أولًا، ثم نظّف. فالسجل المُعاد كتابته مع مفتاح ما يزال فعّالًا يمنح إحساسًا زائفًا بالأمان. وبعد الدفع، شغّل الماسح على نسخة مستنسخة حديثًا لتتأكد من أن السر قد اختفى فعلًا من كل فرع ووسم.

الخطوة 4: امنع التسريب التالي

الهدف هو جعل رفع الأسرار صعبًا واكتشافها سريعًا. لا يوجد ضابط واحد يحقق الأمرين، لذا اجمع بين عدة طبقات.

أبعد الأسرار عن مسار الكود

اقرأ بيانات الاعتماد من متغيرات البيئة أو من مدير أسرار وقت التشغيل، وتحقق عند بدء التشغيل من وجود ما تحتاجه منها. ارفع ملف .env.example بقيم نائبة، وضع .env في .gitignore منذ الإيداع الأول. وفي بيئة الإنتاج، يمنحك مدير أسرار مثل AWS Secrets Manager أو Google Secret Manager أو HashiCorp Vault أو إعدادات البيئة المشفّرة في منصتك تحكمًا في الوصول وسجلات تدقيق وتدويرًا أسهل.

احظر الأسرار قبل رفعها

خطّاف pre-commit يلتقط الخطأ على جهاز المطوّر، قبل أن يصل إلى الخادم البعيد. ويجعل إطار pre-commit ذلك مجرد أسطر قليلة من الإعدادات يستطيع كل مساهم تثبيتها.

@@CODE@@

الخطافات محلية ويمكن تجاوزها، لذا شغّل الماسح نفسه في CI على كل عملية دفع كخط دفاع احتياطي. وعلى GitHub، فعّل فحص الأسرار (secret scanning) وحماية الدفع (push protection) حيث تدعمهما خطتك؛ إذ ترفض حماية الدفع من جهة الخادم عمليات الدفع التي تحتوي على رموز مزوّدين معروفة.

قلّل ضرر التسريبات التي تفوتك

  • قيّد كل مفتاح بأدنى الصلاحيات، وحيثما يسمح المزوّد، بعناوين IP أو مُحيلين (referrers) محددين.
  • فضّل بيانات الاعتماد قصيرة العمر، مثل اتحاد OIDC من CI إلى مزوّد السحابة، على المفاتيح الثابتة طويلة العمر.
  • استخدم مفاتيح منفصلة لكل بيئة، حتى لا يستطيع مفتاح اختبار مسرّب المساس بالإنتاج.
  • احتفظ بدليل تشغيل للتدوير لكل سر حرج، حتى يكون التدوير تحت الضغط إجراءً روتينيًا لا ارتجالًا.

أين تندرج مراجعة الكود

تطابق الماسحات الصيغ المعروفة جيدًا، لكنها أضعف في فهم السياق، مثل كلمة مرور مُركّبة من ثابتين أو بيانات اعتماد افتراضية تُشحن ضمن قيمة احتياطية في الإعدادات. ومراجعة الكود تلتقط ذلك. يُبلّغ CodeAuditAgent عن بيانات الاعتماد المضمّنة في الكود بوصفها CWE-798 مع الدليل المقتبس حين يدقق الفرع الافتراضي لمستودع عام أو مقتطفًا ملصوقًا. وهو يقرأ الكود الحالي لا سجل الإيداعات، لذا أبقِ ماسحًا للسجل قائمًا للإيداعات السابقة.

الخلاصة: السر المرفوع سرٌّ مسرّب. دوّره اليوم، ونظّف السجل إذا كان يستحق الإرباك، واجعل التسريب التالي يفشل عند خطّاف pre-commit بدلًا من أن يظهر على صفحة عامة.