DevSecOps: تأمين الشيفرة والتبعيات والحاويات
خروج

الدرس 1 من 11 · الأساسيات

Shift-left وOWASP Top 10: الأمن يبدأ داخل المحرّر

45 د Node.js 22 (Debian, git, npm, python3)

الهدف

فهم لماذا يجب أن يدخل الأمن في عمل المطوّرين منذ السطر الأول من الشيفرة (ما يُسمّى « 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 » ليس منصبًا ولا برنامجًا نشتريه. إنه طريقة عمل تقوم على ثلاث أفكار.

  1. الأمن شأن الجميع. المطوّر الذي يكتب استعلام SQL هو الأقدر على حمايته. ويصبح فريق الأمن (حين يوجد) سندًا: يوفّر القواعد والنماذج والتكوينات، بدلًا من أن يلعب دور الدركي في نهاية المشروع.
  2. أتمتة كل ما يمكن أتمتته. الإنسان ينسى؛ أما الـ pipeline فلا. يجب أن تعمل كل مراقبة متكرّرة (الأسرار، التبعيات، صورة Docker) وحدها عند كل تعديل.
  3. ردود سريعة ومفيدة. يجب أن يصل التنبيه بينما لا تزال الشيفرة حاضرة في ذهن المطوّر، مع شرح ومسار للتصحيح. في المقابل، ألف تنبيه غير مفرز تُتجاهَل: قواعد قليلة موثوقة أفضل من ضجيج كثير.

الإطار القانوني المغربي

في المغرب، يحمي القانون 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].

  1. صنّف كل عيب ضمن OWASP Top 10:2025 (الملف constats.txt).
  2. صحّح الحقن والتحكّم في الوصول باستعلام مُعلَّم مُصفّى على العميل المتصل.
  3. استبدل MD5 بـ scrypt مع ملح عشوائي.
  4. اجعل الأخطاء لا تكشف شيئًا للعميل بعد الآن.

بعد كل تعديل، تحقّق من البنية النحوية بـ node --check /root/atlaspay/src/paiements.js وأعد قراءة الملف بـ cat -n.

اختبار قصير

  1. ماذا يعني « shift-left »؟
  2. في أي فئة من OWASP Top 10:2025 تصنّف API تُرجع طلبية عميل آخر عندما نغيّر المعرّف في الـ URL؟
  3. لماذا يحمي الاستعلام المُعلَّم من حقن SQL، في حين لا تكفي تصفية علامات الاقتباس؟
  4. لماذا يُعدّ MD5 اختيارًا سيئًا لتخزين كلمات المرور، وماذا يجب أن نستعمل؟
  5. أي فئة ظهرت في Top 10:2025 لتغطية المكتبات والصور والأدوات التي نسلّمها دون أن نكون قد كتبناها؟
الأجوبة
  1. نقل عمليات المراقبة الأمنية نحو بداية دورة التطوير (التصميم، الشيفرة، الـ pull request) بدلًا من تركيزها في النهاية، حيث تكون التصحيحات الأكثر تكلفة.
  2. A01، التحكّم في الوصول المعيب (حالة نموذجية لـ IDOR).
  3. لأن القيم تُنقل بشكل منفصل عن نص الـ SQL: لا يفسّرها المحرّك أبدًا كشيفرة. أما التصفية فتغفل دائمًا حالة ما (ترميز آخر، حرف آخر، قيمة رقمية دون علامة اقتباس).
  4. MD5 سريع (مليارات المحاولات في الثانية)، ودون ملح، تعطي كلمتا مرور متطابقتان البصمة نفسها. يجب استعمال دالة بطيئة ومملّحة مصمَّمة لهذا الغرض: scrypt أو Argon2id أو bcrypt.
  5. A03، إخفاقات سلسلة التوريد البرمجية (Software Supply Chain Failures).

المراجع: OWASP (CC BY-SA 4.0)، وتوثيق Node.js، وCNDP. نص أصلي من MasterLinux.

تمارين تطبيقية

تُنجَز على Node.js 22 (Debian, git, npm, python3)

أنجز هذا التطبيق العملي على جهازك

الطرفية طرفيتك: آلة افتراضية بنظام لينكس (VirtualBox أو VMware أو Hyper-V أو WSL…) أو Docker/Podman. أداة ml تحضّر التمرين وتصحّح عملك، ويُؤكَّد الدرس هنا تلقائيًا.

أنشئ حسابًا مجانيًا للحصول على أمرك الشخصي وتصحيح تطبيقاتك العملية تلقائيًا.

إنشاء حسابي

المهام المطلوبة

  1. اقرأ /root/atlaspay/src/paiements.js. وفي /root/atlaspay/constats.txt، اكتب فئة OWASP Top 10:2025 لكل عيب من العيوب الأربعة المعلَّمة من [1] إلى [4]، سطرًا لكل عيب بالصيغة numero=Axx (مثلًا 1=A07).
    عرض تلميح[1]: نقرأ ما لا يخصّنا. [2]: مُعطى من المستخدم يدخل في استعلام SQL. [3]: خوارزمية تجزئة (hachage) مكسورة. [4]: خطأ سيّئ المعالجة يكشف أكثر من اللازم. اكتب مثلًا: printf '%s\n' 1=A.. 2=A.. 3=A.. 4=A.. > /root/atlaspay/constats.txt
    عرض الحل
    printf '%s\n' 1=A01 2=A05 3=A04 4=A10 > /root/atlaspay/constats.txt

    التحقق : f=/root/atlaspay/constats.txt && grep -qx "1=A01" "$f" && grep -qx "2=A05" "$f" && grep -qx "3=A04" "$f" && grep -Eqx "4=A(10|02)" "$f"

  2. صحّح voirTransaction: يجب أن يكون الاستعلام مُعلَّمًا (paramétrée) (WHERE id = ? AND client_id = ?) مع تمرير القيم على حدة، داخل مصفوفة [req.params.id, req.user.id]. لا يبقى أي إدراج ${req…} داخل الـ SQL.
    عرض تلميحاستبدل السطر const lignes = … كاملًا بـ: const lignes = await db.query("SELECT * FROM transactions WHERE id = ? AND client_id = ?", [req.params.id, req.user.id]); (يعمل sed -i 's|^ const lignes = .*|…|' جيدًا).
    عرض الحل
    sed -i 's|^  const lignes = .*|  const lignes = await db.query("SELECT * FROM transactions WHERE id = ? AND client_id = ?", [req.params.id, req.user.id]);|' /root/atlaspay/src/paiements.js

    التحقق : f=/root/atlaspay/src/paiements.js && ! grep -qF '${req' "$f" && grep -qF 'WHERE id = ? AND client_id = ?' "$f" && grep -qF 'req.user.id' "$f" && node --check "$f"

  3. استبدل التجزئة MD5 بـ crypto.scryptSync مع ملح (sel) عشوائي من 16 بايت (crypto.randomBytes): يجب أن تُرجع الدالة الملح والبصمة بالنظام الست عشري، مفصولين بـ « : ». وبالتالي يجب أن يعطي استدعاءان بكلمة المرور نفسها نتيجتين مختلفتين.
    عرض تلميحداخل hacherMotDePasse: const sel = crypto.randomBytes(16); return sel.toString("hex") + ":" + crypto.scryptSync(mdp, sel, 64).toString("hex");
    عرض الحل
    sed -i 's|return crypto.createHash("md5").update(mdp).digest("hex");|const sel = crypto.randomBytes(16); return sel.toString("hex") + ":" + crypto.scryptSync(mdp, sel, 64).toString("hex");|' /root/atlaspay/src/paiements.js

    التحقق : f=/root/atlaspay/src/paiements.js && ! grep -qi 'createHash(.md5' "$f" && grep -q scryptSync "$f" && node -e 'const m=require("/root/atlaspay/src/paiements.js");const a=m.hacherMotDePasse("Rabat2026"),b=m.hacherMotDePasse("Rabat2026");process.exit(a!==b&&a.includes(":")&&a.length>100?0:1)'

  4. يرسل معالج الأخطاء الرسالة ومكدّس الاستدعاءات (pile d'appels) إلى العميل. سجّل الخطأ من جهة الخادم (console.error(err)) وأرجع فقط رسالة عامة مع الرمز 500: لا تبقى أي خاصية من err داخل json(...).
    عرض تلميحيكفي سطر واحد: console.error(err); res.status(500).json({ erreur: "Erreur interne, réessayez plus tard" }); (أي « خطأ داخلي، أعد المحاولة لاحقًا »).
    عرض الحل
    sed -i 's|res.status(500).json({ erreur: err.message, pile: err.stack });|console.error(err); res.status(500).json({ erreur: "Erreur interne, reessayez plus tard" });|' /root/atlaspay/src/paiements.js

    التحقق : f=/root/atlaspay/src/paiements.js && ! grep -Eq 'json\(.*err\.' "$f" && grep -q 'status(500)' "$f" && grep -q 'console.error(err)' "$f" && node --check "$f"

المراجع الرسمية المعتمدة: OWASP Top 10:2025 — https://owasp.org/Top10/2025/ ; OWASP DevSecOps Guideline — https://owasp.org/www-project-devsecops-guideline/ ; OWASP Cheat Sheet Series — Password Storage, SQL Injection Prevention, Error Handling — https://cheatsheetseries.owasp.org/ ; OWASP Application Security Verification Standard (ASVS) — https://owasp.org/www-project-application-security-verification-standard/ ; Node.js — documentation du module crypto (scrypt) — https://nodejs.org/api/crypto.html ; CNDP — Loi 09-08 relative à la protection des personnes physiques à l'égard du traitement des données à caractère personnel — https://www.cndp.ma/. نص أصلي من MasterLinux.