المقدمة
حماية كلمات مرور المواقع هي مهارة أساسية يجب أن يمتلكها أي مطور. يقدم JavaScript
خيارًا لضمان تخزين ومعالجة آمنة لكلمات المرور أو البيانات الحساسة الأخرى باستخدام خوارزميات التجزئة المقدمة من وحدة BcryptJS
في JavaScript
.
في هذا البرنامج التعليمي، ستتعلم حول BcryptJS
وعملية التجزئة لإعداد خادم express أساسي سيقوم بتخزين كلمات المرور كتجزئة في قاعدة بيانات بدلاً من سلاسل نصية خامة واسترجاعها للتحقق من كلمة المرور.
المتطلبات المسبقة
لمتابعة هذا البرنامج التعليمي، يجب أن يكون لديك الإعداد التالي.
-
إصدار ثابت من Node.js مثبت على جهاز الكمبيوتر الخاص بك بالإصدار 12.x أو أعلى. يمكنك استخدام هذا البرنامج التعليمي من DigitalOcean لتثبيت أحدث إصدار من Node Js على جهاز الكمبيوتر الخاص بك.
-
يجب أن تعرف كيفية كتابة الشيفرة بلغة JavaScript.
-
_يجب أن يكون لديك Express JS مثبتًا على جهاز الكمبيوتر الخاص بك. يمكنك استخدام هذا الدليل لتعلم كيفية إعداد خادم Express.
-
أخيرًا ، ستحتاج إلى قاعدة بيانات MongoDB المجتمعية أو أطلس لإكمال هذا البرنامج التعليمي. يمكنك تثبيته باستخدام أحد هذه الدلائل من DigitalOcean على_ كيفية تثبيت MongoDB.
لماذا استخدام BcryptJS؟
Bcrypt هو خوارزمية تجزئة لإنشاء تجزئات لكلمات المرور لتخزينها في حالة حدوث اختراق للبيانات. تستخدم هذه الخوارزمية المتقدمة تجزئة الملح ، مما يجعل من الصعب كسرها بواسطة هجمات مثل القوة الجبرية.
BcryptJS هو تنفيذ JavaScript لخوارزمية تجزئة Bcrypt، مما يتيح لك استخدام تشفير التجزئة دون الحاجة إلى التورط في وظائف تجزئة معقدة. بعض الأسباب التي تجعل BcryptJS خيارًا رائعًا لأمان كلمات المرور هي الآتية:
-
الأمان – ينفذ BcryptJS خوارزمية Bcrypt، وهي خوارزمية بطيئة (وهو أمر جيد في التجزئة) وتتطلب قوة حاسوبية كبيرة. يجعل ذلك من المهمة صعوبة بالغة بالنسبة للمهاجمين كسر تجزئة كلمة المرور، مما يضمن سلامة كلمات المرور حتى في حالة انتهاك البيانات._
-
تمليح – يدير BcryptJS إنشاء تمليح عشوائي لكلمات المرور لضمان أمان التخزين (سنتعلم المزيد عن التجزئة والتمليح في القسم التالي بمزيد من التفصيل). يجعل التمليح تجزئة كلمة المرور الضعيفة نسبياً أكثر تعقيدًا، مما يجعل من الصعب فك تشفيرها.
-
سهولة الاستخدام – يوفر BcryptJS لمطوري JavaScript أداة لتشفير كلمات المرور دون الحاجة إلى فهم عميق لعمليات التجزئة._
في الخطوة التالية، سنتعرف بإيجاز على التجزئة و الملح.
كيف يعمل الهاش؟
قبل استخدام هذه المفاهيم في مشاريعك، يجب أن تفهم كيفية عمل التجزئة والملح.
التجزئة
التجزئة هي تحويل سلسلة بسيطة أو نص واضح إلى سلسلة من الأحرف العشوائية (تشفير). يتيح ذلك لتخزين آمن و/أو نقل البيانات الحساسة. تشمل التجزئة الخطوات الرئيسية التالية:
إدخال البيانات – أولاً، يتم تخزين البيانات التي قد تكون من أي نوع (ثنائية، حرف، عشري، إلخ.) كنص عادي أو سلسلة.
وظيفة التجزئة – وظيفة التجزئة هي خوارزمية رياضية تأخذ إدخال البيانات وتحولها إلى مجموعة من الأحرف أو رموز التجزئة. تكون وظائف التجزئة حاسمة (تنتج نفس الإخراج لنفس الإدخال) وتعتبر وظائفًا لاعودة (وهذا يعني أنه من المستحيل تقريبًا عكس هندسة الإخراج من وظائف التجزئة، أي تحويل التجزئة إلى بيانات الإدخال).
مقاومة التصادم – يعني ذلك أن تم إنشاء وظيفة تجزئة بالأخذ في الاعتبار فكرة مقاومة التصادم، أي أنه لا يمكن أن تحصل مخرجات متماثلة (شفرة تجزئة) لمدخلين مختلفين.
المصادقة – الوظائف التجزئية تكون حاسمة، حيث تنتج نفس الشفرة التجزئية لنفس المدخل. وبالتالي، عند المصادقة على كلمة مرور مخزنة كشفرة تجزئة، الفكرة العامة هي أنه إذا تطابقت كلمة المرور المراد التحقق منها مع الكشفة التجزئية المخزنة في قاعدة البيانات، فإن كلمة المرور صحيحة.
التمليح
نظرًا لأن عملية التجزئة موجودة منذ عقود، فقد حدثت تطورات مثل جداول الألوان، التي تحتوي على مليارات الإدخالات التي تحتوي على سلاسل بيانات والكشفات التجزئية الخاصة بها استنادًا إلى خوارزميات تجزئة مختلفة.
الآن، لنفترض حالة حدوث حيث يقوم مستخدم بإنشاء حساب على موقع الويب الخاص بك بكلمة مرور ضعيفة. بالتالي، في حالة وقوع اختراق للبيانات، يمكن للمهاجم البحث عن الكشفات التجزئية للمستخدمين الخاصين بك والعثور على تطابق الكشفة التجزئية لحساب المستخدم ذي كلمة مرور ضعيفة. وهذا قد يكون كارثيًا في التطبيقات التي تتطلب أمانًا عاليًا. لمنع حدوث مثل هذا الأمر، يُستخدم التمليح.
التمليح هو طبقة إضافية من الأمان تُضاف إلى الكشفات بإضافة سلسلة عشوائية من الأحرف إلى كشفة كلمة مرور قبل تخزينها في قاعدة البيانات. وبالتالي، حتى لو تم تسريب البيانات في حالة اختراق، فإنه سيكون من الصعب على المهاجم فك تشفير كشفة تحتوي على التمليح. دعونا ننظر في المثال التالي:
كما يمكننا أن نرى بوضوح، فإن كلمة المرور المخزنة مع الملح أقل احتمالاً للكسر بسبب الطبيعة التحديدية للهاش. لذلك، إذا كان المهاجم، على سبيل المثال، يبحث عن هذا الهاش + سلسلة كلمة المرور في جدول قوس قزح، فإنه لن يحصل على سلسلة كلمة المرور الفعلية بل شيئًا مختلفًا تمامًا.
الآن، أنت جاهز لاستخدام BcryptJS وتأمين كلمات المرور بطريقة معتمدة في الصناعة.
تثبيت BcryptJS والوحدات الأخرى المطلوبة
الآن بعد أن تعرفت على الهاش والملح، كل ما تبقى لك هو الحصول على جهاز الكمبيوتر الخاص بك والبدء في البرمجة. سيكون هيكل المشروع كما يلي:

أولاً، سنبدأ بإنشاء مشروع npm بالخطوات التالية:
-
افتح مجلدًا وأنشئ ملفًا،
app.js.
-
افتح نافذة الطرفية في هذا المجلد واكتب الأمر
بعد ذلك، سيُطلب منك إدخال البيانات لكن يمكنك الضغط على Enter دون تقديم أي بيانات.
- ثم، قم بإنشاء 3 ملفات أخرى، وهي
auth.js
db.js
User.js
- في نافذة الطرفية نفسها، اكتب الأمر التالي لتثبيت الحزم اللازمة.
لديك الآن بيئة مشروع كاملة لمتابعة هذا البرنامج التعليمي. في الخطوة التالية، ستتعلم كيفية إنشاء خادم لاستخدام BcryptJS لتخزين ومصادقة كلمات المرور بأمان باستخدام MongoDB.
إعداد خادم مع Express JS
الآن بعد أن قمت بإعداد بنية المشروع، يمكنك إنشاء خادم يستخدم bcrytjs
لتأمين كلمات المرور عن طريق تخزينها كقيم تجزئة ومصادقتها. سنقوم بإنشاء الخادم باستخدام الخطوات الصحيحة التالية.
الخطوة 1 – إنشاء اتصال بقاعدة بيانات MongoDB
للاتصال بـ mongoDB
، نستخدم النسخة المجتمعية. للحفاظ على تنظيم المشروع، ستحفظ الكود الخاص بإعداد الاتصال في ملف db.js
.
هنا، تقوم ب استيراد حزمة mongoose
، التي توفر واجهة برمجة تطبيقات للاتصال بين جافا سكريبت و MongoDB.
أيضًا، في هذه الحالة، عنوان URI للاتصال يكون للتثبيت المحلي لـ mongoDB، إذا كنت تستخدم قاعدة بيانات سحابية (مثل Atlas)، فقط قم بتغيير عنوان URI إلى عنوان قاعدة بياناتك الخاصة.
معلومات
المُعرّف العالمي الموحّد (URI) مشابه لعنوان URL للخادم مع الفرق أن المُعرّف العالمي الموحّد يمكن أن يحدد اسم وهوية الموارد وموقعها على الإنترنت، بينما يُعتبر عنوان URL جزءًا فرعيًا من المُعرّف العالمي الموحّد قادرًا على القيام بالعمليات الأخيرة فقط.
الدالة connectToMongo
هي دالة async لأن mongoose.connect
تُرجع وعدًا من جافا سكريبت. هذه الدالة ستُعيد اتصالًا بنجاح عند تنفيذها بنجاح. في حال عدم ذلك، ستُعيد خطأً.
أخيرًا، نستخدم module.exports
لتصدير هذه الدالة كلما تم استيراد وحدة db.js
.
الخطوة ٢ – إنشاء بنية للمستخدم
ستحتاج إلى بنية أساسية لإنشاء أو مصادقة المستخدمين باستخدام قاعدة بيانات MongoDB. إذا لم تكن تعرف ما هي البنية، يمكنك استخدام دليل DO الممتاز هذا لـ فهم وإنشاء البنية في MongoDB. سنستخدم فقط حقلين لبنيتنا، email
و password
.
استخدم الكود التالي في وحدة User.js
الخاصة بك.
نقوم بإنشاء حقلين في هذا النموذج، email
و password
. كلاهما حقول مطلوبة ومن نوع البيانات النصية. أيضًا، email
هو حقل فريد، مما يعني أنه يمكن استخدام بريد إلكتروني واحد فقط لإنشاء حساب على هذا الخادم.
وأخيرًا، نقوم بتصدير نموذج يسمى users
. يُمثِّل النموذج نموذجًا في نهاية قاعدة البيانات. يمكنك أن تفكر في النموذج كقاعدة لتعريف نموذج، بينما يتم تخزين النموذج كمجموعة في قاعدة بيانات MongoDB
.
يمكنك تحويل نموذج إلى نموذج باستخدام وظيفة model() من مكتبة mongoose
.
الخطوة 3 – إعداد الخادم في ملف app.js
بعد اتباع الخطوات السابقة، لقد قمت بإنشاء نموذج بنجاح ووحدة لإنشاء اتصال بقاعدة بيانات MongoDB
. الآن، ستتعلم كيفية إعداد الخادم. استخدم الكود التالي في ملف app.js
الخاص بك.
هنا، نقوم باستيراد الوحدات express
و db.js
للاتصال بـ MongoDB. ثم، نستخدم وسيط express.json()
لمعالجة الردود JSON. يتم إنشاء المسارات في وحدة مختلفة (auth.js
) للحفاظ على تنظيم ونظافة الكود. ثم، في النهاية، ننشئ نقطة انتهاء للخادم للاستماع على المنفذ 3300
على localhost. (يمكنك استخدام أي منفذ تفضله)
تشفير كلمات المرور وتخزينها في قاعدة بيانات MongoDB
حتى هذه النقطة، الخادم جاهز تقريبًا، والآن ستقوم بإنشاء نقاط نهاية للخادم. سنقوم بإنشاء نقطتين نهاية – signup
و login
. في نقطة النهاية للتسجيل، سنأخذ البريد الإلكتروني وكلمة المرور من مستخدم جديد ونقوم بتخزينها مع التشفير لكلمة المرور باستخدام BcryptJS.
في ملف auth.js
، اكتب الكود التالي:
نقوم بإجراء الواردات الضرورية ثم نقوم بإعداد موجّه express لإنشاء نقطة نهاية /signup
. نستخدم الطريقة POST
بحيث لا تتم الكشف عن بيانات الاعتماد في عنوان URL في التطبيق. بعد ذلك، نقوم بإنشاء ملح باستخدام وظيفة genSalt
في حزمة scripts
؛ يحتوي المعامل الذي يتم تمريره إلى دوال genSalt() على طول حرف الملح. ثم نستخدم وظيفة hash() في BcryptJS، التي تأخذ معلمة مطلوبة، سلسلة كلمة المرور التي سيتم تحويلها إلى رمز التجزئة، ومعامل اختياري، سلسلة الملح. ثم يعيد هذا الأمر تجزئة تحتوي على password
و salt
.
بعد ذلك، نستخدم وظيفة create() من وحدة التحكم mongoose
لإنشاء وثيقة في قاعدة البيانات الخاصة بنا المحددة بقواعد نموذج users. تأخذ هذه الوظيفة كائنًا Javascript
يحتوي على البريد الإلكتروني وكلمة المرور، ولكن بدلاً من تقديمها كسلسلة نصية نقدم secPass (كلمة المرور المشفرة
+ الملح
) ليتم تخزينها في قاعدة البيانات. بهذه الطريقة، لقد قمنا بتخزين كلمة مرور بشكل آمن في قاعدة البيانات باستخدام تشفيرها مع ملح بدلاً من سلسلة نصية عادية. في النهاية، نقوم بإرجاع استجابة JSON
تحتوي على نموذج المستخدم. (هذه الطريقة لإرسال الاستجابات هي فقط لمرحلة development
؛ في الإنتاج، ستقوم بتبديل هذا برمز مصادقة أو شيء آخر).
لاختبار نقطة النهاية هذه، يجب عليك تشغيل الخادم أولاً، والذي يمكن القيام به عن طريق كتابة الأمر التالي في الطرفية.
سيرفر على 3300
(أو أي منفذ تحدده). بعد ذلك، يمكنك إرسال طلب HTTP
إلى عنوان URL http://localhost:3300/auth/signup
بالجسم التالي:
سينتج عن ذلك الإخراج/الاستجابة التالية:
ملاحظة: لن يكون تشفير كلمة المرور والمعرف متطابقين، حيث أنهما دائمًا فريدين.
في القسم التالي، ستتعلم كيفية الوصول إلى التشفير المخزن لكلمة المرور والتحقق منه مع كلمة مرور تقدم عند تسجيل الدخول/المصادقة.
الوصول إلى كلمة المرور المشفرة واستخدامها للمصادقة
حتى الآن، لقد تعلمت عن BcryptJS،
التجزئة،
التمليح،
وتطوير خادم Express
الذي يقوم بإنشاء مستخدمين جدد مع كلمات مرور مخزنة كتجزئة. الآن، ستتعلم كيفية استخدام كلمة المرور المخزنة والمصادقة على المستخدم عند محاولة تسجيل الدخول إلى التطبيق.
لإضافة طريقة المصادقة، قم بإلحاق المسار التالي في ملف auth.js
بعد مسار /signup
:
هنا، نستخدم الطريق الفرعي /auth/login
لأداء مصادقة تسجيل الدخول لمستخدم موجود بالفعل. على غرار نقطة النهاية /auth/signup
، سيكون هذا وظيفة async-await حيث يعيد BcryptJS الوعود.
أولاً، نستخدم وظيفة findOne
من مكتبة Mongoose، التي تُستخدم للبحث عن وثيقة في مجموعة بناءً على استعلام بحث معين. في هذا السياق، نبحث عن المستخدم بناءً على البريد الإلكتروني. إذا لم يكن هناك مستخدم بالبريد الإلكتروني المقدم، فسيتم إرسال استجابة برمز الحالة 400 لعدم صحة البيانات الاعتماد. (ليس من الممارسات الجيدة تقديم معلومات حول أي معلمة غير صحيحة أثناء تسجيل الدخول، حيث يمكن للمهاجمين استخدام تلك المعلومات للعثور على حسابات قائمة).
إذا كان المستخدم الذي يمتلك البريد الإلكتروني المُقدم موجودًا، يتم نقل البرنامج إلى مقارنة كلمة المرور. لهذا الغرض، يوفر BcryptJS
الطريقة compare()
التي تأخذ سلسلة نصية غير مشفرة كمُعامل أول و hash
(مع أو بدون salt
) كمُعامل ثانٍ. ثم، يُرجع وعدًا من نوع Boolean
؛ true
إذا كانت كلمة المرور تُطابق الهاش و false
إذا لم تكن تُطابق. بعد ذلك، يمكنك إضافة فحص بسيط باستخدام جملة if وإرجاع النجاح أو الخطأ استنادًا إلى المقارنة.
وأخيرًا، ستقوم بتصدير express router
باستخدام module.exports لنقطة بداية app.js
لاستخدامه في المسارات.
للاختبار لهذا المسار، يمكنك إرسال استجابة أخرى من نوع HTTP
إلى هذا الرابط http://localhost:3300/auth/login
مع الجسم على النحو التالي:
سيعطي هذا الطلب الاستجابة التالية:
وأخيرًا، سيبدو auth.js
كالتالي:
الاستنتاج
تم إنشاء هذا البرنامج التعليمي لإنشاء خادم لشرح استخدام BcryptJS لتخزين كلمات مرور قاعدة البيانات بشكل آمن والوصول إليها. يمكنك المضي قدمًا في ذلك بواسطة:
-
تنفيذ مسارات إضافية لمهام أخرى مثل استرجاع بيانات اعتماد المستخدم، تحديث بيانات اعتماد المستخدم، إلخ.
-
تنفيذ رموز المصادقة لإرسالها كاستجابات ، الخ.
يبدأ هذا رحلتك للتعامل مع كلمات المرور بأمان. يمكنك دائمًا إضافة المزيد من الأمان باستخدام تقنيات وتقنيات مختلفة ، مما يتيح لك إنشاء تطبيقات أكثر أمانًا ومرونة.