المستوى المطلوب: مبتدئ. المقال ده مناسب لأي حد بيبني أول تطبيق فيه تسجيل دخول، ومش لازم تكون خبير أمان علشان تطبّقه.
لو بتخزّن كلمة سر المستخدم كنص عادي في قاعدة البيانات، أي تسريب واحد بيسلّم حسابات كل مستخدمينك جاهزة للمهاجم. الحل مش التشفير زي ما ناس كتير فاكرة. الحل هو الهاش. في المقال ده هتعرف الفرق بالظبط، وهتطبّقه بأربع سطور بايثون شغّالة.
المشكلة باختصار
تخيّل قاعدة بيانات فيها عمود اسمه password مكتوب فيه P@ssw0rd! بالنص الصريح. طالما الكلمة مخزّنة كما هي، أي حد يوصل للجدول ده — موظف، أو مهاجم اخترق نسخة احتياطية — بياخد كل الحسابات في ثانية. والأسوأ: أغلب الناس بتعيد استخدام نفس الكلمة، فأنت مش بتسلّم حسابك بس، أنت بتسلّم إيميلهم وبنكهم كمان.
المفهوم بمثال بسيط: البصمة
خلّينا نفهمها بمثال قبل أي تعريف علمي. اعتبر الهاش زي بصمة الإصبع. الشخص الواحد بيدّي دايمًا نفس البصمة بالظبط. لكن مستحيل تاخد بصمة وترجّع منها الشخص نفسه. هي اتجاه واحد.
نظام تسجيل الدخول بيشتغل بنفس الفكرة. وقت ما تعمل حساب، السيرفر بياخد كلمة سرّك، يحسب "بصمتها" (الهاش)، ويخزّن البصمة بس — مش الكلمة. تاني يوم لما تسجّل دخول، بياخد اللي كتبته، يحسب بصمته، ويقارنها بالمخزّنة. لو اتطابقوا، يبقى انت هو. السيرفر عمره ما احتاج يعرف كلمتك الأصلية، وعمره ما خزّنها.
طيب لو اتنين اختاروا نفس الكلمة، مش هتطلع نفس البصمة وتفضح إنهم زي بعض؟ هنا بييجي المِلح (salt): نص عشوائي فريد بيتضاف لكل مستخدم قبل الهاش. فحتى لو الكلمة واحدة، البصمة المخزّنة بتطلع مختلفة تمامًا لكل شخص.
التعريف العلمي الدقيق
دالة الهاش المخصّصة لكلمات السر هي دالة رياضية حتمية (نفس المدخل يدّي نفس المخرج) وأحادية الاتجاه (مفيش خوارزمية عملية ترجّع المدخل من المخرج). خصائصها الأساسية: مقاومة الصورة العكسية (preimage resistance)، ومقاومة التصادم (يصعب توليد مدخلين بنفس الهاش).
وهنا الفرق الجوهري عن التشفير (Encryption): التشفير قابل للعكس بمفتاح. تشفّر Ahmed 2026 تطلع 9f3a-b1، وبنفس المفتاح ترجّعها زي ما كانت. ده مناسب لبيانات محتاج تقراها تاني (رسالة، رقم بطاقة). أما كلمة السر، انت مش محتاج ترجّعها أبدًا — انت محتاج تتأكد بس إن اللي كتبه المستخدم مطابق. عشان كده الهاش هو الصح، مش التشفير.
الكود: هش وتحقّق بأربع سطور
ده مثال شغّال بمكتبة bcrypt في بايثون. ثبّتها بـ pip install bcrypt.
import bcrypt
password = b"P@ssw0rd!"
# وقت التسجيل: هش الكلمة مع مِلح عشوائي (cost = 12)
hashed = bcrypt.hashpw(password, bcrypt.gensalt(rounds=12))
print(hashed)
# وقت تسجيل الدخول: قارن من غير ما تفك أي حاجة
print(bcrypt.checkpw(b"P@ssw0rd!", hashed)) # True
print(bcrypt.checkpw(b"wrong-pass", hashed)) # False
لاحظ إن الناتج بيبدأ بعلامة تدل على معامل الكلفة (cost factor) وهو 12 هنا، والمِلح متخزّن جوّه الهاش نفسه، فمش محتاج عمود منفصل ليه. وكل ما تشغّل الكود هيطلع هاش مختلف لنفس الكلمة، لأن المِلح عشوائي — وده المفروض.
ليه bcrypt بالذات ومش MD5 أو SHA-256؟
دوال زي MD5 و SHA-256 مصمّمة تكون سريعة جدًا، وده بالظبط اللي بيخليها كارثة لكلمات السر. كرت شاشة حديث زي RTX 4090 بيقدر يجرّب عشرات المليارات من تخمينات SHA-256 في الثانية الواحدة. يعني قاعدة كلمات سر متهشّرة بـ SHA-256 بلا مِلح بتتكسر أغلبها في دقايق.
bcrypt معمول بالعكس: بطيء عن قصد. عند معامل كلفة 12 الهاش الواحد بياخد حوالي 200 إلى 300 مللي ثانية على سيرفر عادي. الرقم ده مش محسوس للمستخدم وقت الدخول، لكنه بيخنق المهاجم: بدل مليارات في الثانية، بيقدر يجرّب بضعة آلاف بس في الثانية على نفس الكارت. وكل ما زوّدت الكلفة بواحد، الزمن بيتضاعف — فتقدر تصعّبها أكتر كل سنتين مع تطوّر العتاد.
الافتراض هنا إنك بتحمي كلمات سر بشرية. لو بتهش ملفات كبيرة أو بيانات مش سرّية، الكلام ده مش موجّه لك — استخدم SHA-256 عادي وهو أنسب وأسرع.
سيناريو واقعي: تسريبات حصلت فعلاً
في 2012 اتسرّبت قاعدة LinkedIn وفيها حوالي 6.5 مليون كلمة سر متهشّرة بـ SHA-1 من غير مِلح. النتيجة: أغلب الكلمات اتكسرت خلال أيام قليلة. وفي 2009 موقع RockYou كان بيخزّن حوالي 32 مليون كلمة سر كنص صريح، فلما اتسرّبت بقت لحد دلوقتي أشهر قائمة كلمات سر بيستخدمها المهاجمون في التخمين. الدرس واضح: الفرق بين نص صريح، وهاش سريع بلا مِلح، و bcrypt هو الفرق بين كارثة فورية، وكارثة مؤجّلة أيام، وحماية حقيقية.
الـ trade-offs وما يجب الانتباه له
- الكلفة مقابل الأمان: bcrypt بيستهلك CPU عن قصد. عند معامل كلفة 12 بتكسب مقاومة قوية للتخمين، بتخسر حوالي 250 مللي ثانية CPU لكل تسجيل دخول. لو عندك ملايين الدخول في الساعة، اضبط الكلفة على قد سيرفرك واقِس زمن الاستجابة الفعلي قبل ما تزوّده.
- حدّ الـ 72 بايت: bcrypt بيتجاهل أي شيء بعد أول 72 بايت من المدخل. لو بتدعم كلمات سر طويلة جدًا أو passphrases، ده فخّ حقيقي.
- البديل الأحدث: لمشروع جديد، Argon2id هو التوصية الحالية من OWASP، لأنه بيقاوم هجمات كروت الشاشة والـ ASIC أحسن. bcrypt لسه ممتاز وآمن، بس Argon2id أفضل افتراضيًا للأنظمة الجديدة.
متى لا تستخدم الهاش
الهاش أحادي الاتجاه، فمتستخدموش لأي بيانات محتاج ترجّعها. لو عندك رقم بطاقة أو توكن لازم تبعته لطرف تالت لاحقًا، ده شغل التشفير (أو الأفضل: ماتخزّنهوش أصلًا واستخدم خزنة أسرار زي Vault). كمان متستخدمش دوال سريعة (MD5/SHA) لكلمات السر أبدًا، ومتخترعش خوارزمية هاش بنفسك. القاعدة: كلمات السر تتخزّن بـ bcrypt أو Argon2id، وخلاص.
الخطوة التالية
افتح قاعدة بياناتك دلوقتي وبصّ على عمود كلمات السر. لو لقيت نص مقروء، أو هاش MD5/SHA بلا مِلح، ابدأ خطة ترحيل: عند أول تسجيل دخول ناجح لكل مستخدم، أعِد هش كلمته بـ bcrypt أو Argon2id واستبدل القيمة القديمة. كده بتنضّف القاعدة تدريجيًا من غير ما تطلب من حد يغيّر كلمته.
مصادر
- OWASP Password Storage Cheat Sheet — التوصيات الرسمية لتخزين كلمات السر و Argon2id/bcrypt: cheatsheetseries.owasp.org
- NIST SP 800-63B — إرشادات الهوية الرقمية وتخزين المُصادِقات: pages.nist.gov
- Provos and Mazieres، ورقة bcrypt الأصلية (USENIX 1999): usenix.org
- Argon2 — الفائز بمسابقة Password Hashing Competition 2015: github.com/P-H-C/phc-winner-argon2
- توثيق مكتبة bcrypt لبايثون: github.com/pyca/bcrypt
- تسريب LinkedIn 2012 عبر Have I Been Pwned: haveibeenpwned.com