فحص الثغرات الأمنية قبل Pull Request امنع الثغرات الأمنية قبل Pull Request باستخدام فحص pre-commit

مقدمة: لا تنتظر Pull Request لاكتشاف الخطأ

اكتشفتَ مفتاح API داخل ملف إعدادات بعد فتح Pull Request؟ أو ظهر استدعاء MD5 ضعيف في مراجعة الكود بينما أصبح التغيير متشابكاً مع عدة ملفات؟ في هذه المرحلة يكون الخطأ ما زال قابلاً للإصلاح، لكن تكلفة فهمه وإعادة العمل عليه ارتفعت بلا داعٍ.

الحل هو نقل أول طبقة من الفحص إلى جهاز المطور. يتيح لك فحص الثغرات الأمنية قبل Pull Request تشغيل اختبارات سريعة عند محاولة إنشاء commit، قبل أن يصل الكود إلى المراجعة أو CI/CD. سنبني هنا سير عمل عملياً باستخدام pre-commit وDevSkim لفحص الأنماط البرمجية الخطرة، ثم Gitleaks لاكتشاف الأسرار المضمّنة في الملفات.

تم إعداد الخطوات لبيئة Git مع Python 3 و.NET SDK، واختُبرت منهجيتها على أدوات DevSkim CLI وGitleaks وpre-commit. عدّل الإصدارات وفق سياسة مشروعك، ولا تستخدم أي بيانات اعتماد حقيقية أثناء الاختبار.

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

ما هو فحص الثغرات الأمنية قبل Pull Request؟

المقصود هو تشغيل أدوات تحليل تلقائي على الملفات المعدلة قبل أن ينشئ Git commit. هذه الخطوة جزء من مفهوم Shift Left Security (نقل الأمن إلى مراحل التطوير المبكرة)؛ أي أن تكتشف المشكلة عندما يكون الكود ما زال في ذهنك وضمن نطاق تغيير صغير.

يمكن أن تبحث هذه الطبقة عن كلمات مرور ومفاتيح API، استخدامات تشفير ضعيفة، تحقق غير آمن من شهادات TLS، فك تسلسل بيانات غير موثوق، أو استدعاءات قد تفتح باباً لـ Command Injection (حقن الأوامر).

هذه الآلية ليست بديلاً عن فحص CI أو مراجعة Pull Request أو اختبار الاختراق. هي حاجز أول سريع يمنع انتقال الأخطاء الواضحة إلى مراحل أكثر تكلفة.

الفرق بين DevSkim وGitleaks

DevSkim هو Security Linter (مدقق أمني للكود) من Microsoft. يحلل أنماط استخدام API والكود، ويعطي تنبيهات عن التشفير الضعيف، والتحقق غير الآمن من TLS، وعمليات الإدخال أو الملفات التي قد تسبب مخاطر.

أما Gitleaks فهو Secret Scanner (كاشف أسرار) متخصص في العثور على مفاتيح وتوكنات وبيانات اعتماد تشبه القيم الحقيقية. يعتمد على أنماط وقواعد وفحص Entropy (عشوائية القيمة)، لذلك لا ينبغي اعتبار DevSkim بديلاً عنه.

⚠️ تحذير / فخ برمجي (Gotcha): العثور على تنبيه لا يعني تلقائياً وجود ثغرة قابلة للاستغلال. راجع السياق، لكن لا تعالج الضوضاء بإيقاف الأداة بالكامل. استخدم استثناءً ضيقاً مع توثيق السبب.

المتطلبات قبل البدء

ستحتاج إلى:

  1. مستودع Git فعلي يحتوي على ملفات تريد فحصها.
  2. Python 3 لتثبيت وتشغيل pre-commit.
  3. .NET SDK لتثبيت DevSkim CLI، أو نسخة ثنائية مناسبة لنظام التشغيل.
  4. صلاحية تثبيت Git hooks داخل المستودع.

ثبّت الأدوات ثم تحقق من أن PATH محدث في جلسة طرفية جديدة:

# تثبيت pre-commit عبر Python
python3 -m pip install pre-commit

# تثبيت DevSkim كأداة .NET عامة
dotnet tool install --global Microsoft.CST.DevSkim.CLI

# التحقق من الإصدارات
pre-commit --version
devskim --version

إذا لم يتعرف الطرفي على devskim بعد التثبيت، أعد فتح الطرفية أو أضف مجلد أدوات .NET العامة إلى PATH. ويمكنك تثبيت إضافة DevSkim في VS Code للحصول على تنبيه أثناء الكتابة، لكن الـ CLI هو الجزء الذي سيعمل داخل Git hook.

إنشاء فحص pre-commit عملي

هناك تفصيل مهم في دمج DevSkim مع pre-commit: يمرر pre-commit أسماء كل الملفات المعدلة إلى الأمر، بينما يتوقع DevSkim مساراً واحداً بعد الخيار -I. لذلك نستخدم Wrapper (غلافاً صغيراً) يشغّل DevSkim مرة لكل ملف.

أنشئ الملف scripts/run-devskim.py:

import subprocess
import sys

# نحتفظ بأول رمز فشل حتى يمنع pre-commit إنشاء commit
exit_code = 0

for filename in sys.argv[1:]:
    result = subprocess.run([
        "devskim",
        "analyze",
        "-I",
        filename,
    ])
    exit_code = exit_code or result.returncode

sys.exit(exit_code)

يقرأ السكربت أسماء الملفات التي يمررها pre-commit، ثم يشغّل التحليل على كل ملف. إذا فشل DevSkim في ملف واحد، يعيد السكربت رمز خروج غير صفري، وبذلك يمنع Git الـ commit.

في جذر المستودع، أنشئ .pre-commit-config.yaml:

repos:
  - repo: local
    hooks:
      - id: devskim
        name: DevSkim security lint
        entry: python3 scripts/run-devskim.py
        language: system
        types_or: [python, javascript, typescript, json, yaml]
        pass_filenames: true

  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.30.1
    hooks:
      - id: gitleaks

يقصر types_or الفحص على أنواع الملفات المفيدة لمشروعك. أضف امتدادات أخرى عند الحاجة، مثل dockerfile أو shell، ولا توسع القائمة عشوائياً إذا كان ذلك سيبطئ كل commit.

ثبّت الـ hook ثم شغّله على المستودع كاملاً للمرة الأولى:

# تثبيت hook داخل .git/hooks
pre-commit install

# فحص كل الملفات الموجودة، وليس الملفات المعدلة فقط
pre-commit run --all-files

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

اختبار الحماية بفشل مقصود

لا تفترض أن الـ hook يعمل لأن ملف الإعدادات يبدو صحيحاً. اختبره بحالة غير آمنة، ثم احذف ملف الاختبار فوراً.

أنشئ insecure-example.js:

const crypto = require("crypto" );

// مثال مقصود لاختبار اكتشاف خوارزمية ضعيفة
const hash = crypto.createHash("md5")
  .update("password")
  .digest("hex");

أضف الملف وحاول إنشاء commit:

git add insecure-example.js
git commit -m "Test security hooks"

يفترض أن يرفض pre-commit العملية ويعرض اسم الـ hook ورمز الخروج وتفاصيل DevSkim، مثل رقم القاعدة ودرجة الخطورة ورقم السطر. تختلف صياغة الرسالة حسب إصدار الأداة ومجموعة القواعد، لكن العلامة المهمة هي رمز الخروج غير الصفري.

إذا مرّ commit رغم توقعك لفشله، اعزل المشكلة بتشغيل DevSkim مباشرة:

devskim analyze -I insecure-example.js

إذا ظهر التنبيه في التشغيل المباشر ولم يظهر مع pre-commit، فراجع entry وtypes_or واسم الملف في .pre-commit-config.yaml.

اختبار كشف الأسرار باستخدام Gitleaks

أنشئ ملفاً تجريبياً يحتوي على قيمة تشبه مفتاحاً حقيقياً، لا كلمة مثل my-secret؛ فالقيم البسيطة قد لا تطابق قواعد كشف الأسرار:

// قيمة وهمية للاختبار فقط، وليست بيانات اعتماد حقيقية
const apiKey = "4f2a9c1e7b6d3a8f0c5e9b2d7a41c6";

شغّل الفحص على الملف المعدل:

git add config.js
pre-commit run

المتوقع أن يمنع Gitleaks العملية. الإصلاح الصحيح ليس إضافة المفتاح إلى قائمة استثناءات، بل إخراجه من الكود:

// تُحقن القيمة من بيئة التشغيل بدلاً من حفظها في Git
const apiKey = process.env.PAYMENT_API_KEY;

ضع القيمة الفعلية في مدير أسرار معتمد مثل GitHub Actions Secrets أو Azure Key Vault أو المنصة التي تستخدمها. إزالة السر بعد commit أصعب؛ فقد يكون قد وصل إلى تاريخ Git أو نسخة محلية أو سجل CI أو نظام نشر.

📌 ملاحظة: بعد الاختبار احذف ملفات الأسرار التجريبية، ونظّف تاريخ Git إذا تسربت قيمة حقيقية. لا تختبر الأدوات أبداً بمفتاح إنتاجي أو بيانات اعتماد قابلة للاستخدام.

فحص الملفات المعدلة أم المستودع كاملاً؟

فحص الملفات المرحّلة هو الاختيار الأفضل على جهاز المطور لأن زمنه ثابت تقريباً مع حجم التغيير. أما فحص المستودع كاملاً في كل commit فقد يصبح بطيئاً عندما يكبر تاريخ المشروع وعدد ملفاته.

يمكنك استخدام إعداد أبسط لفحص المجلد كله، لكنه مناسب أكثر للتجارب أو للمستودعات الصغيرة:

repos:
  - repo: local
    hooks:
      - id: devskim-all
        name: DevSkim full repository scan
        entry: devskim analyze -I .
        language: system
        pass_filenames: false

التقسيم العملي هو فحص سريع للملفات المرحّلة محلياً، ثم فحص أوسع داخل CI يشمل SAST وفحص Dependencies (التبعيات) وربما المستودع كاملاً.

التعامل مع النتائج الكاذبة

Static Analysis (التحليل الساكن) لا يفهم دائماً نية الكود أو حدود الثقة في البيانات. قد يرى تنبيهاً في اختبار أو في كود محاكاة لا يصل إلى الإنتاج. ابدأ بالتحقق: هل المسار قابل للوصول؟ هل القيمة تحت سيطرة المستخدم؟ هل توجد طبقة حماية أخرى؟

إذا كان التنبيه يمثل خطراً فعلياً، أصلح السبب. وإذا كان الاستثناء مبرراً، اجعله ضيق النطاق، واكتب سبباً واضحاً، واربطه بملف أو سطر محدد، وحدد موعداً لمراجعته. تجنب استثناء مجلد كامل؛ فهو يحول المنطقة إلى Blind Spot (منطقة عمياء) يصعب اكتشافها لاحقاً.

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

مسار الحماية الكامل من جهاز المطور إلى الإنتاج

ضع الفحص المحلي ضمن مسار أكبر، لا كحل منفرد:

جهاز المطور
    -> pre-commit: DevSkim + Gitleaks
    -> Pull Request: مراجعة بشرية وفحوص إضافية
    -> CI/CD: SAST + فحص التبعيات + اختبارات
    -> الإنتاج: مراقبة واكتشاف وإدارة ثغرات

ميزة هذا التصميم أن كل طبقة تعالج نوعاً مختلفاً من الأخطاء. pre-commit يمنحك سرعة ورداً فورياً، Pull Request يضيف حكماً بشرياً، وCI يضمن أن القواعد لا تعتمد على إعداد جهاز مطور واحد.

أخطاء شائعة وكيفية تصحيحها (Common Pitfalls)

تشغيل DevSkim على كل الملفات بطريقة تكسر الفحص

تمرير عدة أسماء ملفات مباشرة إلى أمر يتوقع مساراً واحداً قد يفشل عند تعديل أكثر من ملف. استخدم Wrapper لكل ملف، أو استخدم مساراً ثابتاً مع pass_filenames: false إذا قبلت تكلفة الفحص الكامل.

الاعتماد على DevSkim لاكتشاف كل الأسرار

DevSkim ليس Secret Scanner متخصصاً. وجود بعض قواعد بيانات الاعتماد فيه لا يغطي حالات المفاتيح والتوكنات المختلفة. أبقِ Gitleaks أو أداة متخصصة أخرى ضمن المسار.

تعطيل الأداة بسبب تنبيه مزعج

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

جعل الفحص المحلي بطيئاً جداً

ابدأ بالملفات المرحّلة والنتائج عالية الخطورة. انقل الفحص الكامل إلى CI، وراقب زمن الـ hook. إذا تجاوزت المدة ما يقبله الفريق عملياً، فالحماية ستُتجاوز عاجلاً أو آجلاً.

نسيان أن السر قد بقي في تاريخ Git

تغيير الكود إلى process.env لا يلغي السر الذي سُجل سابقاً. دوّر المفتاح فوراً، افحص السجل والنسخ، واتبع إجراء الاستجابة للحوادث في مؤسستك.

رأي عملي: هل يستحق الاستخدام في الإنتاج؟

نعم، يستحق pre-commit الاستخدام في الإنتاج كطبقة أولى، بشرط ألا تقدمه على أنه نظام أمن كامل. الجمع بين DevSkim وGitleaks عملي لأن كل أداة تغطي مساحة مختلفة: الأولى تراجع أنماط الكود، والثانية تبحث عن أسرار تشبه القيم الحقيقية.

استخدمه عندما يعمل فريقك على مستودع مشترك أو يتعامل مع مفاتيح API أو تطبيقات تتلقى مدخلات خارجية. لا تجعله الحاجز الوحيد في مشروع حساس؛ أضف CI مستقل، وفحص تبعيات، ومراجعة Pull Request، ومراقبة بعد النشر.

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

خطوتك التالية

طبّق الإعداد في مستودع تجريبي خلال عشر دقائق: ثبّت pre-commit وDevSkim، أضف Gitleaks، اختبر مثال MD5 وقيمة سر وهمية، ثم احذف ملفات الاختبار. بعد نجاح التجربة، انقل الإعداد إلى مشروعك الحقيقي وأضف فحصاً مماثلاً داخل CI حتى لا تعتمد الحماية على جهاز واحد.

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

الأسئلة الشائعة ومخطط البيانات (FAQ Schema JSON-LD)

ما الفرق بين DevSkim وGitleaks؟

DevSkim يحلل أنماط الكود غير الآمنة مثل التشفير الضعيف وبعض استخدامات API الخطرة، بينما Gitleaks متخصص في اكتشاف الأسرار ومفاتيح API والتوكنات داخل الملفات وتاريخ Git.

هل يغني فحص pre-commit عن فحص CI؟

لا. الفحص المحلي يعطي ملاحظات مبكرة وسريعة، لكنه يجب أن يعمل بجانب فحوص CI ومراجعة Pull Request وفحص التبعيات واختبارات الأمن المناسبة.

ماذا أفعل إذا ظهر تنبيه كاذب؟

تحقق من قابلية استغلال الحالة أولاً. إذا كان الاستثناء صحيحاً، استخدم استثناءً ضيقاً مع توثيق السبب ومراجعته لاحقاً، ولا تستبعد مجلداً كاملاً دون مبرر تقني.

هل يمكن استخدام فحص المستودع كاملاً في كل commit؟

نعم، لكنه يصبح بطيئاً مع نمو المستودع. الأفضل عادةً فحص الملفات المرحّلة محلياً، ثم تشغيل الفحص الشامل وفحوص SAST والتبعيات داخل CI.

    اعجبك المقال : شاركه الآن
    احمد علي
    احمد علي

    مطور تطبيقات هواتف ذكية باستخدام Flutter، وصانع محتوى تقني يكتب عن الذكاء الاصطناعي والبرمجة وتطورات التكنولوجيا الحديثة. أسعى لتبسيط الأفكار المعقدة ومشاركة خبرتي مع المهتمين بالمجال.

    المقالات: 235

    اترك ردّاً

    لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *