الدرس 1 من 11 · الأساسيات
Shift-left وOWASP Top 10: الأمن يبدأ داخل المحرّر
الهدف
فهم لماذا يجب أن يدخل الأمن في عمل المطوّرين منذ السطر الأول من الشيفرة (ما يُسمّى « shift-left »، أي النقل نحو اليسار)، ومعرفة كيف تتعرّف، داخل ملف مصدري حقيقي، على العائلات الكبرى للمخاطر التي يصفها OWASP Top 10:2025.
أهم النقاط
- كلّما اكتُشفت الثغرة متأخّرة، ارتفعت تكلفتها: سطر يُصحَّح داخل المحرّر يكلّف بضع دقائق؛ أما الثغرة نفسها إذا استُغلّت في الإنتاج فتكلّف تسريبًا للبيانات، وتصريحًا لدى CNDP، وفقدان ثقة العملاء.
- يضيف DevSecOps الأمن إلى كل مرحلة من دورة DevOps (التخطيط، البرمجة، البناء، الاختبار، التسليم، التشغيل)، بشكل مؤتمت قدر الإمكان ومشترك بين الفريق كله.
- Shift-left = نقل عمليات المراقبة نحو يسار الدورة: نمذجة التهديدات، وتحليل الشيفرة والتبعيات والأسرار قبل الدمج، لا بعد الإطلاق.
- OWASP Top 10 هي القائمة المرجعية لأخطر عشرة مخاطر في تطبيقات الويب. تبدأ نسخة 2025 بالتحكّم في الوصول المعيب (A01) وتُدخل سلسلة التوريد البرمجية (A03).
- الأداة لا تعوّض التفكير: يجب أن تعرف كيف تقرأ العيب، وتصنّفه، وتصحّحه من جذوره.
1. لماذا « shift-left »؟
تخيّل دورة حياة تطبيق مرسومة من اليسار إلى اليمين: نحن نصمّم، ثم نبرمج، ثم نبني، ثم نختبر، ثم ننشر، ثم نشغّل. لمدة طويلة، كان الأمن يعيش في أقصى اليمين: بعد انتهاء التطبيق، يُطلق مدقّق اختبار اختراق قبل الإطلاق ببضعة أيام، ويسلّم تقريرًا من 60 صفحة… فيكتشف الفريق أن عليه مراجعة نظام المصادقة بأكمله.
لنأخذ شركة fintech (تكنولوجيا مالية) في الدار البيضاء تطوّر محفظة إلكترونية على الهاتف. إليك العيب نفسه — كلمة مرور مخزَّنة بـ MD5 — مكتشفًا في أربع لحظات مختلفة:
| لحظة الاكتشاف | ما يجب فعله | التكلفة التقريبية |
|---|---|---|
| داخل المحرّر (إضافة أو مراجعة شيفرة) | تغيير سطرين | بضع دقائق |
| داخل الـ CI، قبل الدمج | التصحيح، وإعادة تشغيل الـ pipeline | ساعة |
| أثناء اختبار الاختراق قبل الإطلاق | التصحيح، وترحيل حسابات الاختبار، وإعادة الاختبار، وتأجيل الموعد | عدة أيام |
| بعد تسريب في الإنتاج | فرض إعادة تعيين جميع كلمات المرور، والتحقيق، وإبلاغ CNDP والعملاء، والتواصل | أسابيع، ومال، وسمعة |
يتمثّل shift-left في دفع عمليات المراقبة نحو اليسار: لا نلغي التدقيق النهائي، بل نعمل على ألّا يجد شيئًا تقريبًا.
ما الذي يغيّره ذلك فعليًا
# قبل: يأتي الأمن في النهاية، مرة واحدة في السنة
# الشيفرة ← البناء ← النشر ← (بعد 6 أشهر) التدقيق ← الذعر
# بعد: كل مرحلة تحمل مراقبتها الصغيرة المؤتمتة
# المحرّر : إضافة Semgrep، تنبيه عند لصق سرّ داخل الشيفرة
# pre-commit : يرفض gitleaks أي commit يحتوي على مفتاح
# pull request : SAST (Semgrep)، تدقيق التبعيات (npm audit، pip-audit)
# البناء : فحص الصورة (Trivy)، SBOM (Syft)، التوقيع (cosign)
# النشر : رفض صورة غير موقّعة أو تحمل ثغرة حرجة
# الإنتاج : السجلات، التنبيهات، التصحيحات السريعة
سترى كل واحدة من هذه الأدوات في بقية التكوين.
2. DevSecOps: ثقافة قبل أن تكون أدوات
« DevSecOps » ليس منصبًا ولا برنامجًا نشتريه. إنه طريقة عمل تقوم على ثلاث أفكار.
- الأمن شأن الجميع. المطوّر الذي يكتب استعلام SQL هو الأقدر على حمايته. ويصبح فريق الأمن (حين يوجد) سندًا: يوفّر القواعد والنماذج والتكوينات، بدلًا من أن يلعب دور الدركي في نهاية المشروع.
- أتمتة كل ما يمكن أتمتته. الإنسان ينسى؛ أما الـ pipeline فلا. يجب أن تعمل كل مراقبة متكرّرة (الأسرار، التبعيات، صورة Docker) وحدها عند كل تعديل.
- ردود سريعة ومفيدة. يجب أن يصل التنبيه بينما لا تزال الشيفرة حاضرة في ذهن المطوّر، مع شرح ومسار للتصحيح. في المقابل، ألف تنبيه غير مفرز تُتجاهَل: قواعد قليلة موثوقة أفضل من ضجيج كثير.
الإطار القانوني المغربي
في المغرب، يحمي القانون 09-08 المعطيات ذات الطابع الشخصي. ويجب على المسؤول عن المعالجة (بنك، متجر إلكتروني، إدارة تقدّم خدمة عن بُعد) اتخاذ تدابير تقنية وتنظيمية ملائمة لحماية هذه المعطيات من الإتلاف أو الضياع أو التحريف أو الولوج غير المرخَّص. وتراقب CNDP (اللجنة الوطنية لمراقبة حماية المعطيات ذات الطابع الشخصي) هذه الالتزامات.
بعبارة أخرى: حقن SQL يكشف أرقام البطاقة الوطنية (CIN) وأرقام هواتف عملائك ليس مجرّد « bug ». إنه إخلال بالتزام قانوني. ويمنحك DevSecOps أدلّة ملموسة على أنك اتخذت هذه التدابير: قواعد التحليل، وتقارير الفحص، وسجلّ التصحيحات.
3. OWASP وقائمته Top 10
OWASP (Open Worldwide Application Security Project) مؤسسة غير ربحية تنشر مجانًا أدلّة وأدوات ومعايير لأمن التطبيقات. وأشهر وثائقها، Top 10، تصنّف أخطر المخاطر الملاحَظة في تطبيقات الويب، انطلاقًا من بيانات حقيقية تقدّمها الشركات ومن رأي المجتمع.
نسخة 2025 هي كالتالي:
| الرمز | الخطر | مثال مغربي |
|---|---|---|
| A01 | التحكّم في الوصول المعيب (Broken Access Control) | على بوابة للتجارة الإلكترونية، تغيير /commandes/1041 إلى /commandes/1042 يعرض طلبية عميل آخر. |
| A02 | سوء إعداد الأمن (Security Misconfiguration) | لوحة إدارة متروكة عمومية بالحساب admin/admin، أو حاوية تخزين مفتوحة للجميع. |
| A03 | إخفاقات سلسلة التوريد البرمجية (Software Supply Chain Failures) | مكتبة npm مهجورة، أو صورة Docker latest تتغيّر دون إنذار وتحمل مكوّنًا مفخّخًا. |
| A04 | الإخفاقات التشفيرية (Cryptographic Failures) | كلمات مرور مجزّأة بـ MD5، وأرقام بطاقات مخزّنة بوضوح، وموقع دون HTTPS. |
| A05 | الحقن (Injection) | حقل « رقم البطاقة الوطنية » في استمارة إدارية يُلصَق كما هو داخل استعلام SQL. |
| A06 | التصميم غير الآمن (Insecure Design) | رمز تحقّق من 4 أرقام يُرسَل عبر SMS، دون حدّ لعدد المحاولات: يُخمَّن في بضع دقائق. |
| A07 | إخفاقات المصادقة (Authentication Failures) | لا قفل بعد المحاولات الفاشلة، وجلسات لا تنتهي صلاحيتها أبدًا. |
| A08 | إخفاقات سلامة البرمجيات أو البيانات (Software or Data Integrity Failures) | تحديث يُنزَّل ويُثبَّت دون التحقق من توقيعه. |
| A09 | إخفاقات التسجيل والتنبيه (Security Logging and Alerting Failures) | هجوم بالقوة الغاشمة يدوم ثلاثة أيام دون أن ينطلق أي تنبيه. |
| A10 | سوء معالجة الحالات الاستثنائية (Mishandling of Exceptional Conditions) | خطأ يُرجع إلى العميل مكدّس الاستدعاءات كاملًا، أو استثناء يترك معاملة نصف مُصادَق عليها. |
احفظ المستجدّين في 2025: سلسلة التوريد (A03) — كل ما لا تكتبه بنفسك لكنك تسلّمه رغم ذلك — ومعالجة الحالات الاستثنائية (A10). وهما تحديدًا موضوعان يعالجهما DevSecOps بأدوات مؤتمتة (تدقيق التبعيات، SBOM، التوقيعات، اختبارات الأخطاء).
Top 10 أداة توعية، وليس قائمة شاملة. وللتحقق من تطبيق نقطة بنقطة، يقترح OWASP معيارًا أكمل: ASVS (Application Security Verification Standard).
4. قراءة الشيفرة بعيون المهاجم
لننظر في مقتطف نموذجي، قريب جدًا من مقتطف الـ lab. إنها الـ API الخاصة بشركة fintech: عميل متصل يطّلع على معاملة.
async function voirTransaction(req, res, db) {
const lignes = await db.query(`SELECT * FROM transactions WHERE id = ${req.params.id}`);
res.json(lignes[0]);
}
يختبئ عيبان في هذه الأسطر الثلاثة.
العيب 1 — A05 الحقن. القيمة req.params.id تأتي من الـ URL، أي من المهاجم. وهي تُلصَق داخل نص الـ SQL. فإذا طلبنا /transactions/0 OR 1=1، يصبح الاستعلام ... WHERE id = 0 OR 1=1 ويُرجع أول معاملة في القاعدة، أيًّا كانت. ومع قليل من الخيال (UNION SELECT ...)، نقرأ جداول أخرى.
التصحيح: استعلام مُعلَّم (requête paramétrée). يحتوي نص الـ SQL على علامات ? وتنتقل القيم على حدة؛ ولا يفسّرها مُشغِّل قاعدة البيانات أبدًا كـ SQL.
const lignes = await db.query(
"SELECT * FROM transactions WHERE id = ? AND client_id = ?",
[req.params.id, req.user.id] // قيم تُرسَل بشكل منفصل
);
العيب 2 — A01 التحكّم في الوصول المعيب. حتى دون حقن، تُرجع النسخة الأولى المعاملة المطلوبة دون التحقق من أنها تخصّ العميل المتصل. إنه العيب الأكثر تكرارًا في Top 10 (ويُسمّى أيضًا IDOR، Insecure Direct Object Reference). والتصحيح أعلاه يعالجه أيضًا: الشرط AND client_id = ? يحصر البحث في معاملات المستخدم الذي صادق على هويته.
تخزين كلمات المرور
function hacherMotDePasse(mdp) {
return crypto.createHash("md5").update(mdp).digest("hex");
}
A04 الإخفاقات التشفيرية. MD5 دالة تجزئة سريعة ومكسورة. والسرعة هنا عيب: تحسب بطاقة رسومية مليارات بصمات MD5 في الثانية، ودون ملح (sel)، يملك عميلان لهما كلمة المرور نفسها (Casa2026!) البصمة نفسها، والتي نجدها في جداول محسوبة مسبقًا.
نحتاج دالة بطيئة ومملّحة، مصمَّمة لكلمات المرور: scrypt أو Argon2id أو bcrypt. ويوفّر Node.js الدالة scrypt دون أي تبعية:
const crypto = require("node:crypto");
function hacherMotDePasse(mdp) {
const sel = crypto.randomBytes(16); // ملح عشوائي، فريد لكل حساب
const empreinte = crypto.scryptSync(mdp, sel, 64); // اشتقاق مكلف عن قصد
return sel.toString("hex") + ":" + empreinte.toString("hex"); // نخزّن الاثنين
}
وللتحقق من كلمة مرور عند الاتصال، نعيد قراءة الملح المخزَّن، ونعيد حساب البصمة ونقارن بـ crypto.timingSafeEqual (مقارنة في زمن ثابت).
الأخطاء الثرثارة
function gererErreur(err, req, res, next) {
res.status(500).json({ erreur: err.message, pile: err.stack });
}
A10 سوء معالجة الحالات الاستثنائية (كان يُصنَّف سابقًا ضمن سوء الإعداد، A02). يكشف مكدّس الاستدعاءات مسارات الملفات، ونسخ المكتبات، وأحيانًا استعلام SQL كاملًا: هدية للمهاجم. نسجّل التفاصيل من جهة الخادم ونُرجع رسالة محايدة:
function gererErreur(err, req, res, next) {
console.error(err); // تبقى التفاصيل في السجلات
res.status(500).json({ erreur: "Erreur interne, réessayez plus tard" });
}
5. أي أداة لأي خطر؟
لا توجد أداة تغطّي Top 10 كله. إليك خريطة ما ستتعلّمه وما تلتقطه كل أداة:
| الممارسة (الدرس) | ما تكشفه أساسًا | الفئات المستهدفة |
|---|---|---|
| نمذجة التهديدات STRIDE (1.2) | عيوب التصميم، وإغفالات التحكّم في الوصول | A01، A06 |
| كشف الأسرار — Gitleaks (1.3) | مفاتيح API، وكلمات مرور سُجّلت في commit | A04، A07 |
| التحليل الساكن — Semgrep (2.1) | الحقن، والتشفير الضعيف، والأخطاء | A05، A04، A10 |
| تدقيق التبعيات — npm audit، pip-audit (2.2) | المكتبات المعرَّضة للثغرات | A03 |
| SBOM — Syft (2.3) | جرد لكل ما تسلّمه | A03 |
| فحص الصور والـ IaC — Trivy (3.1) | حزم معرَّضة للثغرات، وإعدادات خطيرة | A02، A03 |
| Dockerfile مُحصَّن (3.2) | حاويات تعمل بـ root، وصور كبيرة جدًا | A02 |
| التوقيعات — cosign (3.3) | آثار (artefacts) مزوّرة | A08 |
| بوّابات داخل الـ CI (3.4) | كل ما سبق، عند كل تعديل | كلها |
ما تجده الأدوات بصعوبة: عيوب منطق الأعمال (استرداد يمكن طلبه مرتين، تحكّم في الوصول « شبه » صحيح). ولهذه، تبقى نمذجة التهديدات ومراجعة الشيفرة والاختبارات.
6. من أين نبدأ في فريق صغير؟
شركة ناشئة من ثلاثة مطوّرين في الرباط لا تملك ميزانية ولا فريق أمن. ترتيب واقعي:
# الأسبوع 1: إيقاف النزيف
# - gitleaks في pre-commit وفي الـ CI (الأسرار تتسرّب أولًا)
# - npm audit / pip-audit داخل الـ CI، بعتبة « critical »
# الأسبوع 2: الشيفرة
# - Semgrep مع مجموعة قواعد قياسية، في وضع « تحذير » أولًا
# الأسبوع 3: الحاويات
# - Dockerfile دون root، صورة أساس محدّدة، فحص Trivy للصورة
# بعد ذلك: نمذجة تهديدات كل وظيفة حسّاسة جديدة،
# SBOM وتوقيع الإصدارات، ثم تشديد العتبات
المهم هو البدء صغيرًا وعدم التراجع أبدًا: متى صارت بوّابة تحجب الثغرات الحرجة، لا نزيلها بعد ذلك.
أخطاء متكررة
- الاعتقاد بأن أداة واحدة تكفي. الماسح الأخضر لا يثبت أن التطبيق آمن؛ إنه يثبت فقط أنه لم يجد شيئًا مما يعرف البحث عنه.
- تفعيل كل القواعد في اليوم الأول. مئات التنبيهات غير المفرزة تُحبط الفريق، فينتهي به الأمر إلى تعطيل الأداة. ابدأ بدرجات الخطورة المرتفعة.
- تصحيح العَرَض لا السبب. تصفية الكلمة
ORفي حقل لا يصحّح الحقن؛ وحده الاستعلام المُعلَّم يفعل ذلك. - نسيان التحكّم في الوصول. استعلام مُعلَّم يُرجع معاملة عميل آخر يبقى ثغرة (A01).
التطبيق العملي (Lab)
تُنجز هذا الـ lab على آلتك الافتراضية الخاصة للعمل: شغّل sudo ml demarrer devsecops-1-1، ونفّذ المهام في الطرفية، ثم تحقّق بـ sudo ml verifier.
أنت مكلَّف بالمراجعة الأمنية لمقتطف من الـ API الخاصة بـ AtlasPay، شركة fintech بالدار البيضاء: /root/atlaspay/src/paiements.js. أربعة عيوب معلَّمة فيه من [1] إلى [4].
- صنّف كل عيب ضمن OWASP Top 10:2025 (الملف
constats.txt). - صحّح الحقن والتحكّم في الوصول باستعلام مُعلَّم مُصفّى على العميل المتصل.
- استبدل MD5 بـ scrypt مع ملح عشوائي.
- اجعل الأخطاء لا تكشف شيئًا للعميل بعد الآن.
بعد كل تعديل، تحقّق من البنية النحوية بـ node --check /root/atlaspay/src/paiements.js وأعد قراءة الملف بـ cat -n.
اختبار قصير
- ماذا يعني « shift-left »؟
- في أي فئة من OWASP Top 10:2025 تصنّف API تُرجع طلبية عميل آخر عندما نغيّر المعرّف في الـ URL؟
- لماذا يحمي الاستعلام المُعلَّم من حقن SQL، في حين لا تكفي تصفية علامات الاقتباس؟
- لماذا يُعدّ MD5 اختيارًا سيئًا لتخزين كلمات المرور، وماذا يجب أن نستعمل؟
- أي فئة ظهرت في Top 10:2025 لتغطية المكتبات والصور والأدوات التي نسلّمها دون أن نكون قد كتبناها؟
الأجوبة
- نقل عمليات المراقبة الأمنية نحو بداية دورة التطوير (التصميم، الشيفرة، الـ pull request) بدلًا من تركيزها في النهاية، حيث تكون التصحيحات الأكثر تكلفة.
- A01، التحكّم في الوصول المعيب (حالة نموذجية لـ IDOR).
- لأن القيم تُنقل بشكل منفصل عن نص الـ SQL: لا يفسّرها المحرّك أبدًا كشيفرة. أما التصفية فتغفل دائمًا حالة ما (ترميز آخر، حرف آخر، قيمة رقمية دون علامة اقتباس).
- MD5 سريع (مليارات المحاولات في الثانية)، ودون ملح، تعطي كلمتا مرور متطابقتان البصمة نفسها. يجب استعمال دالة بطيئة ومملّحة مصمَّمة لهذا الغرض: scrypt أو Argon2id أو bcrypt.
- A03، إخفاقات سلسلة التوريد البرمجية (Software Supply Chain Failures).
المراجع: OWASP (CC BY-SA 4.0)، وتوثيق Node.js، وCNDP. نص أصلي من MasterLinux.