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

هجمات سلسلة التوريد: حين تأتي الثغرة من حزمة ثقة بها

كلاود|٢٠ أكتوبر ٢٠٢٦|6 دقائق قراءة|٩٨ مشاهدة
هجمات سلسلة التوريد: حين تأتي الثغرة من حزمة ثقة بها

الحزم تُخترق عبر حسابات مطوّرين مسروقة وأسماء مشابهة وسكربتات تثبيت. الدفاع: composer audit وnpm audit في كل نشر، وتثبيت الإصدارات من ملف القفل، وفحص ملفات autoload، وعند الاختراق دوّر كل الأسرار وأعد بناء السيرفر بدل تنظيفه.

هجوم سلسلة التوريد يعني أن كوداً خبيثاً وصل سيرفرك عبر حزمة ثبّتها بنفسك وعن قصد، لا عبر ثغرة في كودك أنت. المهاجمون يوصلون بثلاث طرق رئيسية: يسرقون حساب مطوّر الحزمة أو توكن النشر ويرفعون إصداراً مسموماً من حزمة مشهورة، أو ينشرون حزماً بأسماء مشابهة تصطاد خطأ الكتابة، أو يخبّون الحمولة في سكربت تثبيت أو ملف يُحمَّل تلقائياً فيشتغل لحظة التثبيت. الدفاع اللي ينفع فعلاً ممل وقابل للتكرار: شغّل composer audit وnpm audit مع كل نشر وأوقف البناء عند الثغرات عالية الخطورة، وارفع ملفات القفل إلى Git وثبّت منها فقط، واقرأ تغييرات ملف القفل مع كل تحديث للاعتماديات، وأوقف سكربتات التثبيت في npm افتراضياً، وافحص ملفات autoload قبل أن تثق بأي حزمة جديدة. أما إذا تبيّن أن حزمة عندك مخترقة، فالاستجابة ليست تنظيف السيرفر، بل تدوير كل سر يقدر السيرفر يقرأه وإعادة بنائه من صورة نظيفة. مشروع Laravel معتاد يسحب من 100 إلى 150 حزمة Composer، وغالباً أكثر من 1,000 حزمة npm مع الاعتماديات غير المباشرة، فأي واحد من هؤلاء المطوّرين ممكن يصير أضعف حلقة عندك. بقية المقال تشرح كيف يشتغل كل هجوم، والأوامر الدقيقة لكل دفاع، وخطة استجابة تنفذها في أقل من 4 ساعات.

كيف تُخترق الحزم

حسابات وتوكنات مطوّرين مسروقة

هذا أخطر نمط لأن اسم الحزمة أصلي وموثوق. في 2021 رفع حساب مخطوف إصدارات من ua-parser-js، وكانت تُنزَّل وقتها نحو 7 ملايين مرة أسبوعياً، تحمل معدّن عملات رقمية وسارق كلمات مرور. في 2024 كشف باب xz-utils الخلفي النسخة البطيئة من نفس الفكرة، حيث قضى المهاجم قرابة سنتين يكسب ثقة المشرفين قبل أن يدسّ الكود الخبيث في ملفات الإصدار. أما في مايو 2026 فانتشر خبر اختراق حزم ترجمة شهيرة في منظومة Laravel، حيث وصلت بملف helpers.php يشتغل مع كل طلب ويرسل ملفات البيئة ومفاتيح SSH إلى نطاق خارجي.

أسماء مشابهة

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

كود يشتغل لحظة التثبيت

حزم npm تقدر تعرّف سكربتات preinstall وpostinstall تنفَّذ بصلاحيات مستخدمك أثناء npm install، قبل أن تشغّل اختباراً واحداً. حزم Composer تقدر تضع ملفات تحت autoload.files يحمّلها PHP مع كل طلب سواء استدعاها كودك أو لا، والميزتان مشروعتان تماماً، لكنهما بالضبط المكان اللي تختبئ فيه الحمولات.

افحص مع كل نشر واجعل الفحص يوقف

فحص يدوي كل ثلاثة أشهر ما يلحق على شيء. ضعه في خط النشر وخلّه يوقف العملية:

# CI step before build
composer audit --locked --no-dev
npm audit --omit=dev --audit-level=high

composer audit يقارن ملف القفل بقاعدة تحذيرات أمان PHP، ويخرج برمز فشل إذا لقي إصداراً معروفاً بثغرة. أمر npm audit --audit-level=high يتجاهل الملاحظات المنخفضة والمتوسطة حتى لا يفشل البناء إلا على شيء يستاهل التوقف. في مشروع معتاد ينتهي الأمران من 3 إلى 10 ثوانٍ، وهذا لا شيء مقارنة بكلفة نشر ثغرة معروفة. انتبه أن الفحص يعرف فقط المشاكل المبلَّغ عنها، فالإصدار المسموم الجديد يبقى مخفياً عنه أول ساعات أو أيام، ولهذا تحديداً تهمك العادات الثلاث التالية.

ثبّت الإصدارات واقرأ ملف القفل

ارفع composer.lock وpackage-lock.json إلى المستودع، وعلى الإنتاج ثبّت منهما فقط بأمر composer install --no-dev --prefer-dist وأمر npm ci. لا تشغّل composer update أو npm update على سيرفر أبداً، فالتحديث مكانه جهاز المطوّر وفي فرع مستقل حيث يمكن مراجعة التغيير.

لما يلمس طلب الدمج ملف القفل، اقرأ الفروقات بأسئلة محددة:

  • هل تغيّر إصدار حزمة ما طلبت تحديثها؟
  • هل ظهرت حزمة جديدة ما أضافها أحد عن قصد؟
  • هل تغيّر رابط dist أو مشرف إحدى الحزم؟
  • هل عمر الإصدار الجديد أقل من 72 ساعة؟ الانتظار بضعة أيام قبل اعتماد الإصدارات الطازجة يعطي المجتمع فرصة يكشف أغلب النسخ المسمومة قبلك.

الحزم اللي تلمس الدخول أو الدفع أو التشفير ثبّت إصدارها بالضبط في composer.json بدون علامة ^، حتى لا يحرّكها تحديث ملف القفل بصمت.

افحص ما يشتغل تلقائياً

قبل ما تثق بحزمة Composer جديدة، اعرض كل ملف ستحمّله تلقائياً مع كل طلب:

jq -r '.packages[] | select(.autoload.files != null)
  | .name + " : " + (.autoload.files | join(", "))' composer.lock

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

في npm أوقف سكربتات التثبيت افتراضياً، واسمح بها فقط حيث تعرف سبب وجودها:

# .npmrc in the project
ignore-scripts=true

# list packages that declare install scripts
npm query ":attr(scripts, [postinstall])" | jq -r '.[].name'

أغلب عمليات بناء الواجهات تشتغل عادي والسكربتات موقفة، والحزم القليلة اللي تحتاجها فعلاً، مثل مكتبات الصور الأصلية، تعيد بناءها صراحة بأمر npm rebuild package-name. قبل إضافة أي اعتمادية جديدة راجع الأساسيات أيضاً: التنزيلات الأسبوعية، وعمر المستودع، وتاريخ آخر تعديل، وعدد المشرفين، وهل الفجوة اللي تسدها صغيرة لدرجة تكتبها بنفسك في 30 سطراً.

قلّل ما تقدر الحزمة المخترقة توصله

افترض أن حزمة ما ستنقلب يوماً، وصمّم بحيث يكون نطاق الضرر صغيراً. شغّل التطبيق بمستخدم مخصص ما يقدر يقرأ /root ولا المشاريع الأخرى، وخلِّ ملف .env مقروءاً لهذا المستخدم فقط بصلاحيات 600. قيّد الاتصالات الصادرة من سيرفرات الإنتاج حتى يوصل التطبيق لقاعدة البيانات وبوابة الدفع وخادم البريد ولا شيء غيرها، لأن أغلب برامج السرقة تحتاج ترسل البيانات لنطاق مجهول. ابنِ ملفات الواجهة في CI وانشر الناتج المجمّع فقط، فلا يوجد node_modules على سيرفر الإنتاج أصلاً.

الضابطالجهدما يمنعه
فحص في CI بعتبة إيقاف15 دقيقة مرة واحدةالإصدارات المعروفة بثغرات
npm ci وcomposer install من ملفات القفلدقائقالترقيات الصامتة أثناء النشر
مراجعة فروقات ملف القفلمن 2 إلى 5 دقائق لكل تغييرالحزم والإصدارات غير المتوقعة
ignore-scripts=trueدقائقحمولات وقت التثبيت
قائمة سماح للاتصالات الصادرةمن ساعة إلى ساعتينتهريب البيانات بعد الاختراق

إذا وقع الاختراق: دوّر كل شيء وأعد البناء ولا تنظّف

إذا عرفت أن إصدار حزمة ثبّته كان خبيثاً، فاعتبر كل سيرفر شغّله مخترقاً، لأن حمولة قرأت ملف .env ممكن تكون زرعت مهمة cron أو مفتاح SSH أو عدّلت ملفاً تنفيذياً، وأنت ما تقدر تثبت أنك لقيتها كلها. الخطة:

  1. حدد نطاق التعرّض: ابحث في ملفات القفل عبر المشاريع عن الحزمة والإصدارات السيئة، وسجّل أي سيرفرات نشرتها ومتى.
  2. احفظ الأدلة: انسخ سجلات الويب والدخول والجدار الناري خارج السيرفر قبل تغيير أي شيء، وابحث فيها عن المؤشرات المنشورة في التحذير.
  3. دوّر كل سر يقدر السيرفر يقرأه: كلمات مرور قاعدة البيانات، ومفاتيح API، وبيانات بوابة الدفع، وكلمات مرور البريد، وتوكنات السحابة، ومفاتيح SSH، ومفتاح التطبيق، وابدأ بالأسرار اللي تحرك المال.
  4. أعد البناء من صورة نظيفة: جهّز سيرفراً جديداً، وانشر من Git بملف القفل المصحح، واسترجع البيانات من نسخة احتياطية أُخذت قبل الاختراق، ثم حوّل الزيارات.
  5. أخرج السيرفر القديم من الخدمة بعد حفظ سجلاته والتحقق من الجديد فقط.

إعادة البناء تبدو مكلفة، لكن الخادم السحابي من كلاود يتفعّل خلال ثوانٍ بعد الدفع، فالجزء البطيء هو عملية النشر عندك أنت. الفرق اللي تقدر تعيد النشر من الصفر في أقل من ساعة تتعافى خلال ظهيرة واحدة، وسيرفر صغير من باقة أساس بـ3,450 ريالاً سنوياً يصلح أيضاً منفّذ CI معزولاً، فلا يجري البناء والفحص أبداً على الجهاز اللي يحمل أسرار الإنتاج.

ابدأ بهذه التغييرات الأربعة

  1. أضف composer audit --locked وnpm audit --audit-level=high إلى خط النشر اليوم.
  2. ارفع ملفات القفل، وحوّل الإنتاج إلى npm ci وcomposer install --no-dev، وامنع التحديث على السيرفرات.
  3. فعّل ignore-scripts=true واعرض كل ملف autoload في ملف القفل الحالي.
  4. اكتب قائمة بكل سر يقدر كل سيرفر يقرأه، حتى يأخذ التدوير ساعات لا أياماً.

قارن أحجام السيرفرات لمنفّذ بناء معزول أو لإعادة بناء نظيفة في صفحة الأسعار.

مشاركة