إذا كان تطبيقك يخزّن كلمات المرور، فإن هذا القرار أهم من أي شيء آخر تقريبًا في قاعدة شيفرتك البرمجية. إن أصبْتَ فيه، فاختراق قاعدة البيانات سيكون مجرد إزعاج. وإن أخطأْتَ، فستكون كارثة على الصفحة الأولى للصحف.
تحليل خوارزميات تجزئة كلمات المرور الأكثر شيوعًا - bcrypt و Argon2 بلغة واضحة، ثم شرح تفصيلي لكيفية استخدام كل منهما في Node.js
أولاً، مراجعة سريعة: ما هي تجزئة كلمات المرور؟
لا تريد أبدًا تخزين كلمة المرور الفعلية للمستخدم في قاعدة بياناتك. بدلاً من ذلك، تمررها عبر دالة تجزئة (hashing) - وهي عملية تشويش أحادية الاتجاه تحوّل "MyPassword123" إلى شيء مثل $2b$12$KIXQ.... لا يوجد زر "فك التشفير". عندما يسجّل شخص ما الدخول، تقوم بتجزئة ما كتبه وتتحقق مما إذا كان مطابقًا للتجزئة المخزّنة.
هذا يختلف عن التشفير (encryption) الذي يمكن عكسه باستخدام مفتاح. التجزئة هي طريق مسدود - حتى بالنسبة لك، أيها المطور.
لكن هنا تكمن المشكلة: التجزئة السريعة هي تجزئة سيئة لكلمات المرور. إذا سرق مهاجم قاعدة البيانات الخاصة بك، فالخوارزمية السريعة تسمح له بتجربة مليارات التخمينات في الثانية. ولهذا السبب وُجدت bcrypt و Argon2 - فهي بطيئة بشكل متعمد وقابل للضبط.
Bcrypt: المخضرم
موجودة منذ عام 1999، مبنية على تشفير Blowfish من قبل Niels Provos و David Mazières. هي الخوارزمية التي يلجأ إليها معظم المطورين افتراضيًا، ولسبب وجيه - فقد خضعت لأكثر من عقدين من التدقيق ولم يتم اكتشاف أي اختراقات عملية فيها.
كيف تعمل: تستخدم bcrypt "عامل تكلفة" (يُسمى أيضًا جولات الملح) - رقم مثل 10 أو 12 يحدد عدد مرات تكرار الخوارزمية داخليًا. كل زيادة تضاعف الجهد، لذا فإن التكلفة 12 تستغرق ضعف الوقت تقريبًا مقارنة بالتكلفة 11.
أوجه القصور:
تحد كلمات المرور إلى 72 بايت - أي شيء أطول يتم اقتطاعه بصمت، مما قد يكون علة خفية إذا لم تتعامل معها.
هي "مكثفة لوحدة المعالجة المركزية (CPU-hard)" لكنها ليست "مكثفة للذاكرة (memory-hard)". تحتاج فقط إلى مقدار صغير وثابت من الذاكرة بغض النظر عن قيمة عامل التكلفة. وهذا يعني أن المهاجمين الذين يستخدمون وحدات معالجة رسوميات (GPU) أو دوائر متكاملة خاصة بالتطبيق (ASIC) الحديثة يمكنهم تشغيل العديد من التخمينات المتوازية بكفاءة - وهو أمر لم يكن تهديدًا حقيقيًا في عام 1999 ولكنه حقيقي جدًا اليوم.
هل لا تزال آمنة؟ نعم، إلى حد كبير. مع عامل تكلفة 12 أو أعلى، لا تزال bcrypt تعتبر مقبولة للاستخدام في الإنتاج في عام 2026. لكنها لم تعد الخيار الأقوى المتاح.
Argon2: المعيار الحديث
فازت Argon2 في مسابقة تجزئة كلمات المرور (Password Hashing Competition) في عام 2015 - وهي مسابقة مفتوحة صُممت خصيصًا لإيجاد خليفة bcrypt - وتم توحيدها رسميًا كـ RFC 9106 في عام 2021. وهي الآن التوصية الأولى في ورقة OWASP الخاصة بتخزين كلمات المرور.
تأتي Argon2 بثلاثة أنماط:
Argon2d - الأسرع، لكنه أكثر عرضة لهجمات التوقيت الجانبية.
Argon2i - مصمم لمقاومة هجمات القنوات الجانبية، أبطأ قليلاً.
Argon2id - هجين من الاثنين، وهو الذي يجب استخدامه دائمًا تقريبًا.
ما الذي يميزها: Argon2 هي مكثفة للذاكرة (memory-hard). بدلاً من ضبط "عدد الجولات" فقط، تضبط ثلاثة مقاييس منفصلة:
تكلفة الذاكرة - مقدار ذاكرة الوصول العشوائي (RAM) التي يتطلبها كل تجزئة (مثل 19-64 MiB)
تكلفة الوقت - عدد التكرارات التي سيتم تشغيلها
التوازي - عدد الخيوط التي تعمل بالتوازي
إجبار المهاجم على تخصيص ذاكرة حقيقية لكل تخمين هو ما يجعل Argon2 أصعب بكثير في القوة العمياء على نطاق واسع مقارنة بـ bcrypt - فـ GPUs و ASICs مصممة لتكون سريعة ورخيصة في الأحمال الخفيفة على الذاكرة، وليس الثقيلة عليها.
Argon2 مقابل bcrypt: مقارنة مباشرة
Bcrypt | Argon2id | |
|---|---|---|
تاريخ الإصدار | 1999 | 2015 (RFC 9106 في 2021) |
مقاومة هجمات GPU/ASIC | أضعف - استخدام منخفض وثابت للذاكرة | قوية - مصممة لتكون مكثفة للذاكرة |
المعلمات القابلة للضبط | 1 (عامل التكلفة) | 3 (الذاكرة، الوقت، التوازي) |
حد طول كلمة المرور | 72 بايت (اقتطاع صامت) | لا حد عملي |
توصية OWASP | مقبولة للأنظمة القائمة | مفضلة للأنظمة الجديدة |
نضج النظام البيئي | واسع جدًا - كل لغة، كل بيئة | قوي ومتنامٍ، روابط أحدث قليلاً |
الأفضل لـ | الأنظمة القديمة، البيئات التي تحتاج توافقًا واسعًا | المشاريع الجديدة، أي شيء حساس أمنيًا |
إذًا أي واحدة تختار؟
استخدم bcrypt إذا:
لديك بالفعل قاعدة مستخدمين مشفّرة بـ bcrypt وعامل التكلفة لديك هو 12 أو أعلى - لا توجد ضرورة ملحة للترحيل.
تعمل في بيئة ذات دعم محدود أو غير متسق لمكتبات Argon2.
لست هدفًا عالي القيمة (مثل منصة مالية أو مدير كلمات مرور).
استخدم Argon2id إذا:
تبني شيئًا جديدًا. هذا هو الجواب الافتراضي السهل في 2026.
أنت في فئة عالية القيمة أو عالية المخاطر - التكنولوجيا المالية، الرعاية الصحية، أي شيء يحتوي على بيانات حساسة.
تريد إعدادًا مقاومًا للمستقبل يمكنك ببساطة "رفع مستواه" (ذاكرة أكثر، وقت أكثر) مع تحسّن الأجهزة.
تحذير مهم إذا كنت تنشر في بيئات بدون خوادم (serverless) مثل AWS Lambda أو Cloudflare Workers: متطلبات الذاكرة في Argon2 هي ذاكرة حقيقية يجب أن تحجزها وظيفتك. في دالة بسعة 128 ميغابايت افتراضية، فإن ملف OWASP القياسي 64 MiB يستهلك نصف ذاكرتك المتاحة. في هذه الحالة، قلّل تكلفة الذاكرة (أو زد تخصيص ذاكرة الدالة) بدلاً من التخلي عن Argon2 تمامًا.
الترحيل من bcrypt إلى Argon2 لاحقًا؟ لا تحتاج إلى فرض إعادة تعيين كلمة المرور. النمط القياسي هو إعادة التجزئة عند تسجيل الدخول: تحقق من كلمة المرور باستخدام bcrypt كالمعتاد، وإذا نجحت، أعد تجزئة كلمة المرور النصية الواضحة باستخدام Argon2id واحفظ التجزئة الجديدة. على مدار بضعة أشهر، يهاجر مستخدمونك النشطون بأنفسهم.
كيفية استخدام كل منهما في Node.js
الخيار 1: Bcrypt
ثبّت الحزمة الأصلية:
npm install bcrypt
تجزئة كلمة المرور (عند التسجيل):
const bcrypt = require('bcrypt');
const SALT_ROUNDS = 12; // 12 هو افتراضي جيد لعام 2026
async function hashPassword(plainPassword) {
return await bcrypt.hash(plainPassword, SALT_ROUNDS);
}
التحقق من كلمة المرور (عند تسجيل الدخول):
async function verifyPassword(plainPassword, storedHash) {
return await bcrypt.compare(plainPassword, storedHash);
}
دمجها في تدفق التسجيل وتسجيل الدخول:
// التسجيل
app.post('/signup', async (req, res) => {
const { email, password } = req.body;
const hash = await hashPassword(password);
await db.users.create({ email, passwordHash: hash });
res.status(201).send('Account created');
});
// تسجيل الدخول
app.post('/login', async (req, res) => {
const { email, password } = req.body;
const user = await db.users.findByEmail(email);
if (!user || !(await verifyPassword(password, user.passwordHash))) {
return res.status(401).send('Invalid credentials');
}
res.send('Logged in');
});
بعض الأمور الجديرة بالمعرفة:
يتم إنشاء الملح (salt) تلقائيًا وتخزينه داخل سلسلة التجزئة المُعادة - لا تحتاج إلى عمود منفصل للملح في قاعدة البيانات.
إذا كانت سلسلة أدوات المترجم/البناء تمثل مشكلة في نشرك (مثل بعض حاويات serverless أو Alpine)، فإن حزمة
bcryptjsالمكتوبة بـ JavaScript الخالصة هي بديل قابل للتبديل - أبطأ بحوالي 30%، ولكن بدون خطوة بناء أصلية مطلوبة.تقوم bcrypt باقتطاع أي شيء يتجاوز 72 بايت بصمت. إذا سمحت بكلمات مرور طويلة، قم بالتجزئة المسبقة باستخدام SHA-256 قبل تمريرها إلى bcrypt حتى لا يتم اقتطاع أي شيء بشكل غير متوقع.
الخيار 2: Argon2
ثبّت الحزمة:
npm install argon2
تجزئة كلمة المرور (عند التسجيل):
const argon2 = require('argon2');
// إعدادات خط الأساس الموصى بها من OWASP
const hashOptions = {
type: argon2.argon2id,
memoryCost: 19456, // 19 MiB - الحد الأدنى من OWASP
timeCost: 2, // التكرارات
parallelism: 1,
};
async function hashPassword(plainPassword) {
return await argon2.hash(plainPassword, hashOptions);
}
التحقق من كلمة المرور (عند تسجيل الدخول):
async function verifyPassword(plainPassword, storedHash) {
try {
return await argon2.verify(storedHash, plainPassword);
} catch {
return false;
}
}
التحقق مما إذا كانت التجزئة القديمة بحاجة إلى ترقية (مفيد أثناء الترحيل أو بعد رفع المعلمات):
async function needsRehash(storedHash) {
return argon2.needsRehash(storedHash, hashOptions);
}
// أثناء تسجيل الدخول، بعد التحقق الناجح:
if (await needsRehash(user.passwordHash)) {
const newHash = await hashPassword(plainPassword);
await db.users.updatePasswordHash(user.id, newHash);
}
مثل bcrypt، يتم تضمين الملح وجميع المعلمات (الذاكرة، الوقت، التوازي) مباشرة في سلسلة التجزئة المُعادة، لذا يستخدم التحقق دائمًا الإعدادات الدقيقة التي أُنشئت بها التجزئة - حتى إذا غيّرت الإعدادات الافتراضية لاحقًا.
اختيار المعلمات: تنشر OWASP بعض الملفات المقبولة. نقطة بداية شائعة لخادم ويب نموذجي:
الملف | الذاكرة | الوقت | التوازي | الوقت التقريبي |
|---|---|---|---|---|
الحد الأدنى من OWASP | 19 MiB | 2 | 1 | ~40 مللي ثانية لكل تجزئة |
المستوى القياسي من OWASP | 64 MiB | 3 | 1 | ~90-100 مللي ثانية لكل تجزئة |
أمان عالٍ | 128 MiB | 4 | 2 | ~300+ مللي ثانية لكل تجزئة |
قم بإجراء اختبار الأداء على أجهزة الإنتاج الفعلية واختر أثقل إعداد يظل معه تسجيل الدخول سريعًا - بشكل عام أقل من 300-500 مللي ثانية. إذا كنت تتوقع الكثير من عمليات تسجيل الدخول المتزامنة، تذكر أن تضرب تكلفة الذاكرة بعدد تسجيلات الدخول المتزامنة القصوى لتتأكد من أنك لن تستهلك ذاكرة الخادم بالكامل.
الخلاصة
مشروع جديد؟ اختر Argon2id. إنها توصية OWASP الحالية، وهي مكثفة للذاكرة، وتتيح لك معلماتها مساحة للنمو مع زيادة سرعة الأجهزة.
نظام bcrypt قائم يعمل بتكلفة 12+؟ لست في خطر - ليست هناك حاجة للاستعجال في الترحيل. فقط تأكد من أن المستخدمين الجدد ينتقلون تدريجيًا، باستخدام نمط إعادة التجزئة عند تسجيل الدخول.
في كل الأحوال: لا تكتب أبدًا منطق التجزئة الخاص بك. استخدم مكتبة جيدة الصيانة، وحافظ على معلماتك متوافقة مع إرشادات OWASP الحالية، وراجع إعداداتك كل عام أو نحو ذلك مع تطور الأجهزة.
تجزئة كلمات المرور ليست قرار "اضبط وانسى" - لكنها واحدة من الخيارات الأمنية القليلة التي يوفّر فيها إصابتها من المرة الأولى الكثير من الألم لاحقًا.


