تخزين الباسورد
إنت مش محتاج تعرف باسورد المستخدم أبداً. الدرس ده بيطلع بيك سلّم من 6 درجات، كل درجة جت عشان تحل مشكلة اللي قبلها، لحد ما توصل للطريقة اللي تخلي كسر الباسوردات ياخد سنين حتى لو الداتابيز اتسرقت.
- تشرح ليه مينفعش نص عادي، ولا تشفير، ولا SHA-256 لوحده
- تفهم الـ salt بيعمل إيه، وليه مش لازم يبقى سر
- تفهم ليه bcrypt و Argon2id بطيئين عن قصد، وتقرا هاش bcrypt جزء جزء
- تعرف الـ Timing Attack، والـ Rehash، وسياسة الباسورد الحديثة، و k-anonymity
قبل أي تفصيلة، ثبّت القاعدة دي في دماغك: إنت مش محتاج تعرف باسورد المستخدم أبداً. كل اللي محتاجه إنك تتأكد إن اللي كتبه دلوقتي هو هو اللي كتبه يوم ما سجّل. كل الدرجات اللي جاية مبنية على الفكرة دي.
السلّم: 6 درجات
كل درجة جت عشان تحل مشكلة اللي قبلها. ابدأ من الأولى ودوس “ابدأ الهجوم”، وبعدين “الدرجة الجاية”، واتفرج على الهاكر وهو بيكسر كل طريقة.
| password |
|---|
الدرجة 1: Plain Text (نص عادي)
- الفكرة: تخزّن الباسورد زي ما المستخدم كتبه بالظبط.
- المشكلة: أي حد يوصل للداتابيز يقرا كل الباسوردات. ولأن الناس بتكرر نفس الباسورد في كل حتة، اختراقك إنت بيفتح إيميل العميل وحسابه في البنك.
- حصلت فين: RockYou سنة 2009.
الدرجة 2: Encryption (تشفير)
- الفكرة: تشفّر الباسورد بمفتاح، ولما تحتاجه تفك التشفير.
- المشكلة: التشفير معمول عشان يترجع. والمفتاح لازم يبقى على السيرفر عشان تعرف تتشيك، يعني اللي يسرق الداتابيز غالباً هيسرق المفتاح معاها.
- حصلت فين: Adobe سنة 2013.
الدرجة 3: Hash
- الفكرة: الـ hash زي الخلاط: تحط برتقان يطلع عصير، ومستحيل ترجّع العصير برتقان. نفس الباسورد دايماً بيدي نفس الهاش، وأي تغيير في حرف واحد بيغيّر الهاش كله.
- المشكلة: لو 5000 يوزر باسوردهم
123456، هتلاقي نفس الهاش 5000 مرة. والهاكر عنده Rainbow Tables: جداول محسوب فيها مسبقاً هاش ملايين الباسوردات المشهورة. يبص فيها يلاقي الباسورد في ثانية. - حصلت فين: LinkedIn سنة 2012.
الدرجة 4: Salt
- الفكرة: قبل الهاش، تضيف نص عشوائي مختلف لكل يوزر وتخزّنه جنب الهاش. كده نفس الباسورد بيطلع ليه هاش مختلف عند كل يوزر، والـ Rainbow Tables مبقاش ليها لازمة.
- المشكلة: SHA-256 سريع جداً. كارت شاشة واحد بيجرّب مليارات في الثانية، فالهاكر ياخد قايمة RockYou ويجرّبها على كل يوزر لوحده ويخلص برضه بسرعة.
الدرجة 5: Slow Hash (bcrypt و Argon2id)
- الفكرة: خلّي الهاش بطيء عن قصد. إنت بتعمل login مرة واحدة، فـ 0.1 ثانية محدش هيحس بيها. لكن الهاكر اللي عايز يجرّب مليار باسورد هيحتاج حوالي 3 سنين للمستخدم الواحد.
- ميزة إضافية: البطء ده إنت اللي بتتحكم فيه بحاجة اسمها cost، وكل ما تزوّدها بواحد الوقت بيتضاعف. ولما الأجهزة تبقى أسرع بعد كام سنة، بتزوّد الـ cost. أما Argon2id فبياكل memory كمان، وده بيصعّب الهجوم بكروت الشاشة.
- الحالة: ده الحل المعتمد النهارده.
الدرجة 6: Pepper (اختياري)
- الفكرة: سر واحد لكل التطبيق بيتضاف للباسورد قبل الهاش، ومتخزن برا الداتابيز (في
.envأو جهاز أمان مخصوص). لو الداتابيز بس اتسربت، الهاكر مش هيعرف حتى يبدأ. - العيب: لو الـ pepper اتسرب أو احتجت تغيّره، العملية صعبة جداً.
جرّب بنفسك: الـ Salt والبطء
اكتب باسورد واحد لمستخدمين اتنين، وبعدين شغّل الـ salt وشوف إيه اللي يحصل للهاش. وبعدها قيس البطء على جهازك. كل الحسابات بتتعمل جوه متصفحك، ومفيش حاجة بتتبعت لأي حتة.
……البطء بالأرقام
نفس الباسورد مرة بـ SHA-256 عادي، ومرة بـ PBKDF2 بـ 600,000 دورة (من عيلة الـ slow hashes زي bcrypt). القياس على جهازك إنت دلوقتي.
شكل هاش bcrypt اللي هتلاقيه في الداتابيز
لاحظ إن الـ salt جوه نفس السطر. عشان كده مش هتلاقي عمود اسمه salt في جدول users في لارافيل.
4 تفاصيل صغيرة بتفرق
1. المقارنة لازم تكون Constant-time
المقارنة العادية بتقف عند أول حرف مختلف. يعني لو أول حرف صح، الرد بيتأخر نانو ثواني زيادة، ومع ملايين المحاولات الهاكر يقدر يستنتج القيمة حرف حرف. ده اسمه Timing Attack، والحل إنك تقارن كل الحروف دايماً: hash_equals() في PHP، و password_verify() بتعمل كده من جوه.
السيرفر عنده token سري. إنت هاكر وبتخمّن. اكتب تخمين، وشوف المقارنتين بيمشوا حرف حرف.
k7Qx9mZ22. Rehash on Login
لو غيّرت الـ cost من 10 لـ 12، الباسوردات القديمة هتفضل متهششة بـ 10، وإنت مش عارف الباسوردات عشان تعيد الهاش. الحل إنك تستنى المستخدم يعمل login، لأن ساعتها الباسورد الأصلي بيبقى معاك في الـ request. لارافيل 11 وأحدث بيعمل ده لوحده.
3. سياسة الباسورد الحديثة
- الطول أهم حاجة: 8 على الأقل، والأحسن 12 أو أكتر.
- اسمح بأي حروف حتى المسافات، عشان الناس تكتب جمل كاملة.
- ارفض أي باسورد اتسرب قبل كده.
- متجبرش حد يغيّر الباسورد كل فترة، لأن ده بيخلي الناس تكتب
Password1وبعدهPassword2.
4. تعرف إن الباسورد اتسرب من غير ما تبعته لحد
الـ rule اللي اسمه Password::uncompromised() في لارافيل بيسأل موقع Have I Been Pwned بطريقة اسمها k-anonymity. اتفرج على الرحلة:
دوس ▶ شغّل، أو امشي خطوة خطوة بالأسهم.
استخدم bcrypt أو Argon2id بـ salt لكل يوزر و cost متظبط، وعمرك ما تستخدم SHA لوحده أو التشفير.
أسئلة الإنترفيو
فكّر في إجابتك الأول، وبعدين افتح السؤال.
01إزاي تخزن الباسورد؟
بخوارزمية password hashing بطيئة ومعمولة للغرض ده: bcrypt أو Argon2id، بـ salt عشوائي لكل يوزر، و cost متظبط إن الهاش ياخد حوالي 100 ملي ثانية على السيرفر. المقارنة تبقى constant-time، وأعمل rehash لما أغيّر الـ cost. ولو عايز طبقة زيادة أضيف pepper متخزن برا الداتابيز.
02ليه مش بنشفّر الباسورد؟
لأن التشفير معمول عشان يترجع، والمفتاح موجود على نفس السيرفر، فاللي يسرق الداتابيز غالباً هيوصل للمفتاح. وإحنا أصلاً مش محتاجين نعرف الباسورد، محتاجين بس نتأكد إنه هو هو.
03الـ salt مش سر، يبقى فايدته إيه؟
بيقتل الـ Rainbow Tables لأن الحساب المسبق بقى مستحيل، وبيجبر الهاكر يهاجم كل يوزر لوحده، وبيخفي إن اتنين عندهم نفس الباسورد.
04ليه bcrypt بدل SHA-256؟
SHA-256 معمول عشان يبقى سريع، وكارت الشاشة بيجرّب مليارات في الثانية. bcrypt بطيء عن قصد وبطؤه بيتظبط بالـ cost. و Argon2id بياكل memory كمان، فبيصعّب هجوم الـ GPU أكتر.
05غيّرت الـ cost من 10 لـ 12. الباسوردات القديمة هتتحدّث إزاي؟
مقدرش أعيد الهاش لأني معرفش الباسوردات. بستنى كل مستخدم يعمل login، لأن ساعتها الباسورد الأصلي معايا في الـ request، فأتأكد منه بالهاش القديم وأخزّن هاش جديد بالـ cost الجديد. لارافيل 11 وأحدث بيعمل ده أوتوماتيك.
06يعني إيه Timing Attack، وإزاي تمنعه؟
إن الهاكر يستنتج سر من الفرق في وقت الرد. المقارنة العادية بتقف عند أول حرف مختلف، فكل حرف صح بيأخّر الرد شوية. الحل مقارنة constant-time بتعدّي على كل الحروف دايماً، زي hash_equals و password_verify.
07إزاي تعرف إن باسورد اتسرب من غير ما تبعته لحد؟
بـ k-anonymity: أعمل SHA-1 للباسورد وأبعت أول 5 حروف بس لـ Have I Been Pwned. يرجّعلي كل الهاشات المسرّبة اللي بتبدأ بيهم، وأدوّر على الباقي عندي. الموقع عمره ما بيعرف الباسورد ولا الهاش كامل. وده اللي Password::uncompromised بيعمله في لارافيل.