تأمين GitHub Actions: تحديد وتخفيف ورصد الثغرات في تدفقات عمل CI/CD

ما هي Github Actions؟
قبل الغوص في التفاصيل المهمة المتعلقة بسوء التهيئة، دعونا نوضح الأمر: ما هي GitHub Actions بالضبط؟
GitHub Actions هي أداة قوية للمطورين — أداة CI/CD تُؤتمت عمليات الاختبار والبناء ونشر التطبيقات. وهذا ليس كل شيء. إنها تشبه سكين الجيش السويسري المتكامل الخاص بك لأتمتة مهام مثل وسم القضايا في مستودعك. تُشغل هذه التدفقات على آلات افتراضية تابعة لـ GitHub (تدعم Linux و macOS و Windows)، أو يمكنك استضافتها على أجهزتك الخاصة (إذا كنت تحب التميز).
عندما تنحرف GitHub Actions عن مسارها: تأثير سوء التهيئة
اعتبر GitHub Actions كمساعدك الوفي. تخيل الآن إن علمته أن يحمل مفاتيحك... لكنك نسيت أن تغلق الخزنة. يمكن لسوء التهيئة أن يحول هذه الأداة القوية إلى بوابة للمهاجمين.
قد تؤدي الأخطاء إلى تنفيذ التعليمات البرمجية عن بُعد (RCE)، مما يعرض أسرارًا حساسة مثل مفاتيح API أو يسمح لرمز خبيث بالتسلل إلى مستودعاتك. على سبيل المثال:
- يمكن التلاعب بالمدخلات التي يتحكم بها المستخدم مثل github.event.issue.title لحقن الأوامر.
- حتى مع إخفاء أسرار GitHub، يستطيع المهاجمون الأذكياء تجاوز الحماية وسرقة المعلومات الحساسة.

الرهانات؟ كارثية — خاصة إذا قام المهاجمون برفع مواد خبيثة أو تعديل مستودعك بطرق قد تُعرض أنظمتك أو مستخدميك للخطر.
تشريح GitHub Actions المعرضة للخطر
هيا نفحص بعض الثغرات الشائعة، بدءًا بـ حقن الأوامر/الرموز. تنشأ هذه المشكلة الخفية غالبًا من الاستخدام غير الصحيح لسياقات GitHub أو المتغيرات البيئية أو حتى الإجراءات التابعة لأطراف ثالثة.
حقن الأوامر/الرموز
في GitHub Actions، يمكن استخدام البنية ${{ }} لاستبدال القيم مثل سياقات GitHub، والمتغيرات البيئية، ومدخلات التدفق وغير ذلك. لكن إذا استُخدمت بشكل غير صحيح، فقد تؤدي إلى حقن الأوامر/الرموز داخل التدفق. مثلًا عندما تُستخدم تحت العملية run، حيث تسمح بتنفيذ أوامر shell. لأن القيمة داخل البنية ${{ }} تُقيّم وتُستبدل قبل تنفيذ الأوامر/الرموز، فقد يؤدي ذلك إلى حقن أوامر.
إليكم بعض الأمثلة على تدفق عمل معرّض لحقن الأوامر/الرموز:
مثال 1: حقن الأوامر عبر سياقات Github
في هذا التدفق، هناك نقطتا حقن أوامر، وهما ${{github.event.issue.title}} و ${{github.event.issue.body}} حيث يُستدعى كلا السياقين تحت العملية run. ولأن مدخلات المستخدم تستخدم دون تنقية، يسمح ذلك للمهاجمين بحقن أوامر مثل ls -la (يمكن استبدالها بأوامر أكثر ضررًا بوضوح).


كما هو موضح في المثال التجريبي لحقن الأوامر أعلاه، تم تنفيذ الأمر ls -la على الرغم من أن القيمة جاءت من المستخدم/سياق GitHub.
مثال 2: حقن الأوامر عبر المتغيرات البيئية
فيما يلي تدفق عمل نموذجي معرض لحقن الأوامر عبر متغير بيئة GitHub Actions.
مثال 3: حقن الرموز عبر actions/GitHub script
فيما يلي تدفق عمل نموذجي معرض لحقن الرموز عبر actions/github-script.


هدف طلب السحب وتشغيل التدفق
المحفزات مثل pull_request_target و workflow_run تحمل معها مخاطر. تعطي امتيازات مرتفعة، مثل الوصول للأسرار ورموز القراءة/الكتابة، مما يجعلها عرضة للاستغلال إذا لم تُدار بشكل صحيح.
هدف طلب السحب
مع المحفز pull_request العادي، يكون لدى طلبات السحب من مستودعات مفرعة خارجية امتيازات أقل مثل عدم القدرة على الوصول لأسرار سير العمل وامتلاك رموز وصول للقراءة فقط للمستودع. علاوة على ذلك، في معظم الحالات، يحتاج المساهمون الجدد لموافقة مالك المستودع قبل تشغيل GitHub Actions. يتم ذلك لمنع المهاجمين من رفع وتنفيذ كود خبيث أو غير موثوق به في حال كان سير العمل يقوم بفحص كود طلب السحب.
لكن في حالة pull_request_target، يتم تشغيل أي سير عمل يتم تفعيله ضمن سياق الفرع الأساسي. وبما أن الفرع الأساسي يُعتبر موثوقًا، يمكن لسير العمل تجاوز موافقة مالك المستودع ويتم تشغيله أيضًا بامتيازات أعلى مثل الوصول للأسرار ورمز وصول قراءة/كتابة للمستودع.
في مثل هذه الحالات، يمكن تحقيق تنفيذ التعليمات البرمجية باستخدام ملفات البناء الموجودة مثل Makefile، سكربتات bash، سكربت PowerShell أو سكربتات البناء داخل package.json الخاص بـ npm (مثلاً preinstall أو postinstall)
إليكم مثالًا على استغلال سير عمل pull_request_target معرض للثغرة يستفيد من خاصية سكربت preinstall في npm:
هنا هي بنية ملفات المشروع، وهو مشروع node بسيط.

يقوم المهاجم بتفريع المستودع، وإجراء تغييرات على package.json، وإنشاء طلب سحب لتفعيل سير العمل:

يتم تنفيذ سير العمل وتُنفذ تغييرات المهاجم مما يؤدي إلى تسرب الأسرار في ناتج GitHub Actions. (كما ذُكر سابقًا، تقوم GitHub Actions بإخفاء الأسرار افتراضيًا، لكنه يمكن تجاوزه عن طريق عكس تسلسل السر)


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

محفز طلب السحب سيرفع القطعة الأثرية المعدلة،

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


التخفيف: جعل GitHub Actions أكثر أمانًا
الأخبار السارة؟ يمكن التخفيف من هذه الثغرات بواسطة استراتيجيات بسيطة وفعالة.
حقن الأوامر/الرموز
تعامل مع جميع البيانات المقدمة من المستخدم بشك، وصرّح القيمة القابلة للتحكم من قبل المستخدم كمتغير بيئة في GitHub Actions. أظهر المثال السابق أن استخدام متغير بيئة GitHub Actions قد يؤدي إلى حقن الأوامر/الرموز، ولكن ذلك يحدث فقط إذا استُخدم بناء ${{ }}. لتنقية مدخلات المستخدم ببساطة استخدم الطريقة الأصلية للغة للوصول إلى المتغير البيئي.
على سبيل المثال، في shell للوصول إلى المتغيرات البيئية، استدعِ المتغير كالتالي $SomeEnvVar، وللجافا سكريبت، يكون باستخدام process.env.SomeEnvVar. في هذه الحالة، ستُعامل مدخلات المستخدم كسلسلة نصية فقط بدلًا من أمر أو رمز.
إليك مثال على إصلاح حقن الأوامر لعملية run:
بما أن مدخلات المستخدم تم تنقيتها، لم يعد الأمر المحقون يُنفذ.


إليك مثال على إصلاح حقن الرموز لـ actions/github-script:
بما أن مدخلات المستخدم تم تنقيتها، لم يعد الكود المحقون يُنفذ ولم يعد السر المصرّح به يتسرب.


pull_request_target و workflow_run
فيما يخص pull_request_target و workflow_run، فإن التخفيف لهذين الأمرين أكثر تعقيدًا لأن لهما حالات استخدام صحيحة. ومع ذلك، إليك بعض الأمور التي يمكن أخذها بعين الاعتبار للتخفيف من سوء التهيئة:
- تقييد الامتيازات:
أ. تجنب استخدام pull_request_target إلا إذا كان ضروريًا للغاية وبدلًا من ذلك استخدم pull_request. سيضمن ذلك أن المستخدمين الخارجيين لا يمكنهم الوصول إلى أي أسرار سير العمل في حال وجود ثغرة حقن أوامر/رموز.
ب. قم بتكوين رمز التوكن الخاص بـ GitHub Action Workflow وفقًا لمبدأ أقل امتياز باستخدام الأذونات - للمزيد حول أذونات Github Action
- كن حذرًا فيما تقوم بتشغيله:
لا تقم أبدًا بـ checkout لكود غير موثوق بامتيازات مرتفعة (مثل: pull_request_target أو workflow_run)
أ. ${{ github.event.pull_request.head.sha }}
ب. ${{ github.event.workflow_run.head_sha }}
هذا يسمح للمهاجم بتشغيل كود عشوائي بامتيازات مرتفعة على ملف سير العمل كما تم توضيحه سابقًا.
الكشف: رصد تدفقات العمل المعرضة للخطر
يمكن للأدوات الآلية أن تكون أفضل صديق لك هنا. قم ببناء سكربت لفحص ملفات سير العمل بحثًا عن:
حقن الأوامر/الرموز
أي شيء تحت عملية run يمكن استخراجه بواسطة السكربت لمزيد من المعالجة.
بمجرد استخراج السكربت تحت عملية run، يمكن البحث فيه عبر regex لاكتشاف أي أنماط معرضة للخطر مثل، أي شيء يطابق ${{ some.github.contexts }}.
لتقليل الإيجابيات الكاذبة والضوضاء، إليكم قائمة بسياقات GitHub التي يجب مراقبتها عند البحث عن احتمالية حقن الأوامر داخل ملفات سير العمل - المرجع
لاكتشاف حقن الأوامر عبر المتغيرات البيئية، تكون منطق الكشف هو نفسه مع نمط الكشف ${{ env.* }}.
نفس الأمر ينطبق على حقن الرموز عبر actions/github-script، مع الفرق أنه بدلاً من عملية run، يجب استخراج سكربت.
عمليات run ضمن الإجراءات المركبة قد تكون عرضة للخطر أيضًا. نظرًا لعدم وجود موقع معياري للإجراءات المركبة، يجب على سكربت الكشف أن يقوم بفحص متكرر لاكتشاف كل الإجراءات المركبة التي تُستدعى ضمن ملف سير العمل الرئيسي.
pull_request_target و workflow_run
أما بالنسبة لرصد سوء تهيئة pull_request_target و workflow_run، فإذا كان الكشف يعتمد فقط على استخدام المحفز، فغالبًا ما ستنتج العديد من الإيجابيات الكاذبة نظرًا لوجود حالات استخدام جيدة لهذه المحفزات.
لتقليل الإيجابيات الكاذبة، يمكن أن يشمل نمط الكشف إجراءات أخرى غير محرّكات pull_request_target و workflow_run. أمثلة على هذه الإجراءات الإضافية يمكن أن تكون actions/checkout و actions/download-artifact، حيث يمكن للمهاجم عبر هذه الإجراءات العبث إذا لم تُهيأ بشكل صحيح.
تطبيق قائمة استثناءات/تجاهل لهذا الكشف سيكون مفيدًا، حيث إن قابلية استغلال سوء التهيئة تعتمد بشكل كبير على حالة استخدام سير العمل. على سبيل المثال، استخدام workflow_run مع actions/download-artifact لا يعني بالضرورة أنه معرض للخطر إذا كانت القطعة الأثرية التي تم تنزيلها لا يمكن العبث بها.
التنفيذ: البقاء في الصدارة
أحد الأساليب يشمل نشر سكربت للكشف يعمل كجزء من مهمة cron مجدولة. يقوم هذا السكربت بجلب ملفات سير العمل من مستودعات GitHub الخاصة بنا، ويفحصها لأي أنماط معرضة للخطر، وينبه إذا ما تم الكشف عن أي سوء تهيئة أو مخاطر. تساعد هذه المراقبة الاستباقية في الحفاظ على سلامة وأمان خطوط CI/CD الخاصة بنا.

علاوة على ذلك، قم بتنفيذ GitHub Actions مخصصة تكشف سوء التهيئة في الوقت الحقيقي وادمجها مع قواعد المستودع لضمان التزام كل طلب سحب بإرشادات الأمان.

الخاتمة
يمكن أن تكون GitHub Actions سلاحك السري للأتمتة، ولكن كما هو الحال مع أي أداة قوية، فهي تتطلب الاحترام والعناية. من خلال فهم المخاطر، وتنفيذ التخفيفات، والبقاء يقظين، يمكن ضمان بقاء خطوط CI/CD الخاصة بك آمنة.
لنجعل تدفقات عملك ليست فقط وظيفية بل محصنة.