لا تخزّن كلمات المرور أبدًا
جزء من قسم المصادقة والأمان في رحلة Node.js على Coddy. الدرس 4 من 24.
يعيد الأشخاص استخدام كلمات المرور، لذلك قد تؤدي كلمة مرور مكشوفة بنص واضح إلى كشف حسابات في أماكن أخرى. خزّن تجزئة كلمة مرور مملّحة: قيمة مشتقة تتحقق منها بإعادة احتسابها، بدلًا من فك ترميزها.
const salt = randomBytes(16).toString('hex');
const key = await scryptAsync(inviteCode, salt, 32);
const saved = salt + '.' + key.toString('hex');يجمع هذا المثال بين قيمة ملح ومفتاح مشتق لرمز دعوة. يتيح الفاصل استعادة قيمة الملح أثناء التحقق واشتقاق مفتاح آخر باستخدام المعلمات نفسها. تستخدم مهمة كلمة المرور الخاصة بك فاصلًا وطول مفتاح خاصين بها. أنشئ قيمة الملح لكل كلمة مرور جديدة، واشتق المفتاح، ثم خزّن كليهما. تظل التجزئات المملّحة بحاجة إلى كلمات مرور قوية لأن المهاجم يستطيع تجربة التخمينات.
التحدي
سهلحاليًا، يحفظ التسجيل كل كلمة مرور تمامًا كما كُتبت. اجعله يحفظ تجزئة مملحة بدلًا من ذلك، حتى لا تكشف قاعدة البيانات المُسرَّبة كلمات المرور.
- في
passwords.js، غيّرhashPassword(password)بحيث تُرجع النص الذي يحفظه التسجيل، بالصيغة: الملح، ثم نقطتان، ثم التجزئة:- الملح هو 16 بايتًا عشوائيًا، يُنشأ من جديد مع كل استدعاء ويُكتب بصيغة سداسية عشرية: 32 محرفًا من 0 إلى 9 ومن a إلى f.
- التجزئة هي مفتاح بطول 64 بايتًا، تنشئه
scryptمن كلمة المرور وذلك الملح، ويُكتب أيضًا بصيغة سداسية عشرية: 128 محرفًا. الوسيط الثالث لـscryptAsyncهو طول المفتاح بالبايت. - صِل بينهما بنقطتين. تبدو القيمة المحفوظة هكذا:
f2bba0669d9fa2d203afc7e61bf8f065:c3f7cae352e023a8d4766da9a316b5a2c844100efff22c4079f89a8ab8512ac91c33227481c3afa88c3ba0e88347f9e3e0c22dad9d55f19688a350f71be8dbd2
- لا تحتاج إلى تغيير
server.js. فالمسارPOST /signupيستدعيhashPasswordبالفعل ويحفظ ما تُرجعه. كما يتضمنGET /debug/users/:username، الذي يعرض ما حُفظ لمستخدم واحد. هذا المسار موجود فقط كي تتمكن من الاطلاع؛ لا يتضمنه تطبيق حقيقي أبدًا.
جرّب ذلك: اضغط «العب». أرسل POST /signup مع {"username": "ada", "password": "correct horse"}. ستحصل على الحالة 201 و{"username": "ada"}. أرسل الجسم نفسه مع "username": "bob". ثم أرسل GET /debug/users/ada، وبعده GET /debug/users/bob. تتكون كل قيمة passwordHash من 32 محرفًا، ثم نقطتين، ثم 128 محرفًا آخر. تختلف القيمتان، رغم أن ada وbob اختارا كلمة المرور نفسها.
جرّب بنفسك
import { randomBytes, scrypt } from 'node:crypto';
import { promisify } from 'node:util';
const scryptAsync = promisify(scrypt);
// يحوّل كلمة المرور إلى النص الذي تخزّنه signup.
// في الوقت الحالي، يحتفظ بكلمة المرور كما كُتبت.
export async function hashPassword(password) {
return password;
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس المصادقة والأمان
1كلمات المرور
البايتات والنص الست عشرياشتقاق مفتاح كلمة المرورقيمة Salt جديدةلا تخزّن كلمات المرور أبدًامقارنة بايتات المفتاحالتحقق من كلمة المرورقواعد التسجيلتدرّب بنفسك: Playground لـ Express