bcrypt لضغط كلمات المرور لماذا لا يكفي التشفير وحده

نُشرت في
bcrypt لضغط كلمات المرور: لماذا لا يكفي التشفير وحده 1
إعلان · حذف؟

إذا كنت تُخزن كلمات المرور باستخدام AES أو RSA أو حتى SHA-256، فأنت تفعل ذلك بشكل خاطئ. ليس خاطئًا بشكل خفيف — بل خاطئًا جذريًا. هذا هو الخطأ الأمني الأكثر شيوعًا في تطوير الويب، ويوجد له حل بسيط: استخدم دالة تشفير كلمات المرور المناسبة مثل bcrypt.

إليك السبب في أهميتها، وكيف يعمل bcrypt، وما يشبه الكود المُعد للإنتاج.

لماذا تحتاج كلمات المرور إلى معالجة خاصة

العمليات التشفيرية المُصممة عادةً تكون قابلة للعكس أو سريعة. التشفير مُصمم ليكون قابلًا للعكس — وهذا هو هدفه كليًا. SHA-256 وMD5 سريعة جدًا، وتُعالج جيجابايت في الثانية. كل خاصية من هذه الخصائص تُعدّ كارثية بالنسبة لكلمات المرور.

عندما يحصل المهاجم على قاعدة البيانات، فإنه يحصل على تشفير كلمات المرور. مع التشفير، إذا وجد المهاجم المفتاح، فإنه يُفكّك كل شيء. مع التشفير السريع مثل MD5 أو SHA-256، فإنه يُجرّي هجومًا مُتسلسلًا باستخدام أجهزة GPU — يمكن للهياكل الحديثة أن تختبر ملايين الملايين من التشفيرات MD5 في الثانية. تُكسر كلمتك المُعقدة خلال دقائق.

يجب أن تكون كلمات المرور:

  1. غير قابلة للعكس — حتى مع المفتاح أو الخوارزمية، لا يمكن استرجاع النص الأصلي
  2. بطيئة في الحساب — البطء المقصود يجعل هجمات القوة المُباشرة غير ممكنة
  3. مميزة لكل مستخدم — يجب أن تُنتج تشفيرات مختلفة عند استخدام نفس كلمة مرور

يُحقق bcrypt كل هذه الميزات. لا تحقق الدوال التشفيرية العامة أو التشفير ذلك.

التشفير مقابل التشفير مقابل تشفير كلمات المرور

هذه ليست قابلة للتبادل:

النهجقابل للعكس؟سريع؟مُستقر للكلمات المرور؟
التشفير (AES، RSA)نعم — مع المفتاحنعملا
التشفير السريع (MD5، SHA-256)لانعم (بتصميمه)لا
تشفير كلمات المرور (bcrypt، Argon2id)لالا (بتصميمه)نعم

القابلية للعكس في التشفير هي عائق مُقاس: إذا اُستغل المفتاح، فإن كل كلمات المرور تصبح معرضة للخطر. السرعة في التشفير السريع هي عائق أيضًا: السرعة تُسهم في الهجمات بالقوة. تُصمم دوال تشفير كلمات المرور لتكون بطيئة — وهذا هو الهدف.

كيف يعمل bcrypt

تم تصميم bcrypt في عام 1999 من قبل نيلس بروفوس وديفيد مازيريس، ويقوم بثلاثة أشياء مهمة:

1. إضافة مفتاح عشوائي. قبل التشفير، يُولّد bcrypt مفتاحًا عشوائيًا (16 بايت) ويُدرج في الناتج النهائي للتشفير. حتى لو اشتُرِكَت كلمات المرور بين مستخدمين، فإن التشفيرات ستكون مختلفة. هذا يُوقف الهجمات المُسبقة باستخدام الجداول المُسبقة تمامًا.

2. عامل العمل (التكاليف). يقبل bcrypt معلمة التكلفة (عادةً بين 10 و14). كل زيادة تضاعف وقت الحساب. عند التكلفة 12، يستغرق التشفير تقريبًا 250-400 مللي ثانية على الأجهزة الحديثة. هذا البطء غير ملحوظ في طلب تسجيل دخول — لكنه يحوّل هجوم بليون محاولة إلى عملية تستمر لعشرات السنين.

3. الناتج مُدمج. يبدو التشفير بـ $2b$12$... وينسق بين نسخة الخوارزمية، عامل التكلفة، المفتاح، والتشفير. لا تحتاج إلى عمود مفتاح منفصل. احتفظ بالنص الكامل.

الكود المُعد للإنتاج: نودي جي وبيتوني

نودي جي (bcryptjs أو bcrypt)

const bcrypt = require('bcrypt');

const SALT_ROUNDS = 12;

// Hash a password
async function hashPassword(plaintext) {
  return bcrypt.hash(plaintext, SALT_ROUNDS);
}

// Verify a password against a stored hash
async function verifyPassword(plaintext, storedHash) {
  return bcrypt.compare(plaintext, storedHash);
}

// Usage
const hash = await hashPassword('hunter2');
// Store `hash` in your database

const isValid = await verifyPassword('hunter2', hash);
// true

بيتوني (bcrypt)

import bcrypt

COST = 12

def hash_password(plaintext: str) -> bytes:
    salt = bcrypt.gensalt(rounds=COST)
    return bcrypt.hashpw(plaintext.encode('utf-8'), salt)

def verify_password(plaintext: str, stored_hash: bytes) -> bool:
    return bcrypt.checkpw(plaintext.encode('utf-8'), stored_hash)

# Usage
hashed = hash_password('hunter2')
# Store hashed in your database

is_valid = verify_password('hunter2', hashed)
# True

احتفظ بالنص الكامل للتشفير. لا تُخزن النص الأصلي، ولا تُخزن المفتاح بشكل منفصل، ولا تُخزن القيم الوسيطة.

اختيار عامل التكلفة

يُعتمد العامل الصحيح على أجهزتك. الهدف: أن يُستغرق كل عملية تشفير 200-500 مللي ثانية على خادمك الإنتاجي. هذا سرعة كافية لتجربة مستخدم جيدة، وبطيئة بما يُثقل الهجمات.

الإرشاد الحالي: التكلفة 12 كحد أدنى، 14 لحسابات ذات قيمة عالية (مديرين، ماليين). قم بإجراء اختبار على أجهزتك الحقيقية:

// Node.js: benchmark different cost factors
const bcrypt = require('bcrypt');

for (let cost = 10; cost <= 14; cost++) {
  const start = Date.now();
  await bcrypt.hash('benchmark', cost);
  console.log(`Cost ${cost}: ${Date.now() - start}ms`);
}

إذا كانت التكلفة 12 تستغرق أقل من 100 مللي ثانية، فزد التكلفة. إذا كانت التكلفة 14 تتجاوز 1000 مللي ثانية، فقل إلى 13. عدّلها سنويًا — تصبح الأجهزة أسرع، ويجب أن تُتبع التكلفة.

يمكنك اختبار تشفير bcrypt بشكل تفاعلي باستخدام مولد تشفير bcrypt IO Tools.

bcrypt مقابل Argon2id مقابل scrypt

يُعدّ bcrypt مُختبرًا وشائعًا في الدعم. لكن له عيب: أنه ليس مُعتمدًا على الذاكرة. يمكن للمهاجم باستخدام أجهزة متخصصة (ASIC أو FPGAs) أن يُسرّع الهجمات أكثر من البدائل المُعتمدة على الذاكرة.

الخوارزميةمُعتمد على الذاكرةمُقاوم للإنتشارتوصية
bcryptلاجزئيمثالي كمُعيار؛ استخدم التكلفة ≥12
scryptنعمجزئيأفضل من bcrypt، أقل أدوات
Argon2idنعمنعممُفضل للمشاريع الجديدة

للمشاريع الجديدة: استخدم Argon2id. فاز في مسابقة تشفير كلمات المرور (2015)، ويُعتمد على الذاكرة، ويقاوم الهجمات باستخدام أجهزة GPU وASIC، ويُعدّ الآن من التوصيات الرسمية لـ OWASP. واجهة API تشبه بسيطًا بـ bcrypt.

للمشاريع القائمة: إذا كنت مُستخدمًا لـ bcrypt مع عامل تكلفة منطقي، فإن التحول ليس ضروريًا. أضفه إلى إعادة تطويرك القادم.

أخطاء شائعة في التنفيذ

تشفير التشفير. يُستخدم بعض المطورين تشفير كلمة المرور على مستوى العميل قبل إرسالها، ثم تُشفّر مرة أخرى على مستوى الخادم. يصبح التشفير على مستوى العميل "كلمة المرور". الآن تُشفّر سلسلة هكس ثابتة، وليس كلمة مرور مُختارة من قبل المستخدم — لا تُفقد شيئًا من التشفير المزدوج، لكنك لا تُكسب شيئًا أيضًا، وتُضيف تضاربًا.

مشكلة التقاط 72 بايت. يتجاهل bcrypt ما يتجاوز 72 بايت. إذا كانت كلمة مرور 100 حرف و كلمة مرور 72 حرف تُشارك أول 72 حرفًا، فإنها تُعتبر متماثلة في بريت. إذا كانت مستخدمون يضعون كلمات مرور طويلة جدًا، فإن هذا يُعدّ تدهورًا في الأمان. الحل: ابدأ بـ SHA-256 قبل إرسالها إلى بريت — لكن فقط إذا فهمت تمامًا التبعات، ووثّقت ذلك بوضوح.

عامل تكلفة ضعيف. كانت التكلفة 10 مناسبة في عام 2011. في عام 2026، استخدم على الأقل التكلفة 12. إذا كانت السجلات القديمة تستخدم التكلفة 10، يمكنك ترقية التكلفة بشكل مُباشر: بعد تسجيل دخول ناجح، أعد تشفير كلمة المرور المُوافقة باستخدام التكلفة الجديدة واحتفظ بالنسخة المُحدثة.

الوظيفة المُتوازية مهمة. يُعدّ بريت مُرهقًا للوحدة المعالجة. استخدم دائمًا واجهة التشفير غير المُتوازية (كما هو موضح أعلاه) في نودي جي لتجنب توقف دورة الأحداث. استخدام التشفير المُتوازي في خادم نودي سيجعل كل طلب ينتظر.

الانتقال من MD5/SHA إلى بريت

لا يمكنك إعادة التشفير بدون النص الأصلي. لكن يمكنك الانتقال بشكل مُتوازي:

  1. أضف عمودًا إلى جانب العمود القديم password_hash عند التسجيل الناجح (عندما يكون النص الأصلي متاحًا)، أعد تشفيره باستخدام بريت واحتفظ به في password_md5 العمود
  2. ، واحذف العمود القديم password_hashبعد فترة انتقال، يمكن إجبار المستخدمين الذين لم يسجلوا تسجيل دخول على إعادة تعيين كلماتهم
  3. مرة واحدة
  4. إذا كان password_md5 مُفرغًا لجميع المستخدمين، فاحذف العمود

هذا هو النهج القياسي، ولا يتطلب أي توقف.

الخلاصة

التشفير مخصص للبيانات التي تحتاج إلى استرجاع. التشفير مخصص للبيانات التي تحتاج إلى التحقق منها. يجب أن تُتحقق كلمات المرور، وليس أن تُسترجَع — وهذا يعني أن التشفير هو الأداة الخاطئة.

يُقدّم لك بريت التمثيل، البطء القابل للضبط، وصيغة تشفير مدمجة. وقد كان الحل الصحيح منذ 25 عامًا. استخدمه بعوامل تكلفة 12 أو أكثر، واستخدم Argon2id للمشاريع الجديدة، وانسَ MD5 وSHA-256 في أسرع وقت ممكن.

الخطأ في هذا ليس خطرًا فرضيًا. تُقرّب قواعد البيانات. عندما تُقرّب، يصبح تشفير كلمات المرور المُشفّرة بشكل صحيح غير قابل للتفكيك. أما التشفيرات MD5 فهي تُفكّك في الليل.

هل تريد حذف الإعلانات؟ تخلص من الإعلانات اليوم

تثبيت ملحقاتنا

أضف أدوات IO إلى متصفحك المفضل للوصول الفوري والبحث بشكل أسرع

أضف لـ إضافة كروم أضف لـ امتداد الحافة أضف لـ إضافة فايرفوكس أضف لـ ملحق الأوبرا

وصلت لوحة النتائج!

لوحة النتائج هي طريقة ممتعة لتتبع ألعابك، يتم تخزين جميع البيانات في متصفحك. المزيد من الميزات قريبا!

إعلان · حذف؟
إعلان · حذف؟
إعلان · حذف؟

ركن الأخبار مع أبرز التقنيات

شارك

ساعدنا على الاستمرار في تقديم أدوات مجانية قيمة

اشتري لي قهوة
إعلان · حذف؟