تخزين كلمات المرور بأمان في Python باستخدام Hashing

تخزين كلمات المرور بأمان في Python باستخدام Hashing

كلمة المرور ليست قيمة ينبغي أن تحفظ كما كتبها المستخدم. إذا تسربت قاعدة البيانات، فإن التخزين النصي يجعل الضرر فورياً، بينما التجزئة الحديثة تجعل استعادة الكلمات أصعب بكثير. يخلط بعض المبتدئين بين hashing وencryption؛ التشفير يمكن عكسه بمفتاح، أما التجزئة فتنتج قيمة للتحقق من المطابقة من دون الحاجة إلى استعادة النص الأصلي. يشرح المقال استخدام Werkzeug داخل Python لإنشاء hash والتحقق منه، ثم يوضح ما الذي يبقى مسؤولية التطبيق مثل حماية الاتصال وتحديد محاولات الدخول وإدارة الأسرار.



الفكرة الأساسية

تضيف خوارزميات تخزين كلمات المرور salt مختلفة لكل كلمة حتى لا تنتج كلمتان متساويتان قيمة واحدة سهلة المقارنة. تستخدم المكتبة تكلفة حسابية تجعل التخمين المتكرر أبطأ. عند تسجيل الدخول، لا يفك الخادم التجزئة، بل يمرر القيمة المقدمة إلى دالة تحقق تقارنها بالنتيجة المحفوظة. لا تكتب خوارزمية خاصة بك، ولا تستخدم SHA-256 وحدها لكلمات المرور، لأنها مصممة لتكون سريعة لا بطيئة. اختر مكتبة موثوقة واتبع إعداداتها المحدثة.

مثال برمجي عملي

from werkzeug.security import generate_password_hash, check_password_hash

password = "مفتاح-تجريبي-قوي"
stored_hash = generate_password_hash(password)

print("القيمة المحفوظة:", stored_hash)

valid_login = check_password_hash(stored_hash, "مفتاح-تجريبي-قوي")
invalid_login = check_password_hash(stored_hash, "قيمة خاطئة")

print(valid_login)
print(invalid_login)

شرح المثال

تنشئ generate_password_hash قيمة تحتوي على معلومات الخوارزمية والإعدادات والملح، لذلك لا تحتاج إلى حفظ salt في عمود منفصل عند استخدام هذا الشكل. تحفظ القيمة الناتجة في قاعدة البيانات بدلاً من password. عند تسجيل الدخول، تمرر القيمة المحفوظة وكلمة المرور التي كتبها المستخدم إلى check_password_hash. لا تطبع هذه القيم في السجلات في تطبيق حقيقي. المثال يوضح الفكرة، لكن حساب المستخدم يحتاج أيضاً إلى بريد فريد ورسائل عامة لا تكشف إن كان البريد موجوداً.

عند إنشاء الحساب، تحقق من طول كلمة المرور واسم المستخدم ثم احسب التجزئة مرة واحدة. عند الدخول، ابدأ بتحديد الحساب ثم نفذ المقارنة في المكتبة. ضع مهلة أو حدّاً للمحاولات الفاشلة، وسجل الحدث من دون كلمة المرور. عندما تغير إعدادات الخوارزمية، استخدم وظيفة تدعم إعادة التجزئة عند تسجيل الدخول الناجح. اختبر التسجيل بكلمة فارغة وكلمة طويلة جداً وحساب غير موجود حتى لا تؤدي الأخطاء إلى رسائل أو سلوك غير متناسق.

طريقة العمل قبل كتابة الكود

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

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

اختبار المثال في حالات مختلفة

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

  • تحقق من المدخلات قبل استخدامها في الحساب أو التخزين.
  • أعد رسالة مفهومة ورمزاً مناسباً عند وقوع الخطأ.
  • اجعل الاختبارات قابلة للإعادة من دون اعتماد على شبكة أو وقت متغير.
  • راجع أثر التغيير على الأجزاء التي تستدعي الدالة أو المكون.

ملاحظات تتعلق بجودة الكود

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

احتفظ بالإعدادات التي تختلف بين جهاز وآخر خارج الكود، ولا تضع كلمات مرور أو مفاتيح خاصة في المستودع. استخدم سجلات مناسبة أثناء التطوير، ثم راجع ما ينبغي حجبه في بيئة التشغيل. إذا تعامل البرنامج مع بيانات المستخدم، فافصل بين ما يحتاجه التطبيق وما يمكن الاحتفاظ به. هذه الممارسات لا تخص لغة واحدة، بل تقلل المشكلات عندما يكبر المشروع أو يعمل عليه أكثر من شخص.

متى تعرف أن الحل يحتاج إلى تطوير؟

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

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

أخطاء ينبغي تجنبها

لا تحفظ كلمة المرور في سجل أو رسالة خطأ أو كائن session. لا تقارن النصين باستخدام == داخل كود خاص، ولا تشفر كلمة المرور لأنك لن تحتاج إلى فكها. من الأخطاء استخدام قيمة ثابتة كـ salt لكل المستخدمين، أو تخزين hash داخل ملف الإعدادات بدلاً من قاعدة البيانات. يجب أن يرسل التطبيق كلمة المرور عبر HTTPS، وأن يضع الأسرار المتعلقة بالخادم خارج المستودع ويغيرها عند الاشتباه بتسربها.

خطوة تالية مناسبة

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

اختيار إعدادات التجزئة بعناية

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

ما الذي يجب ألا يُخزّن؟

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

الخلاصة

أضف استعادة حساب تعتمد على رمز مؤقت محدود الصلاحية، ولا ترسل كلمة المرور القديمة بالبريد. اقرأ عن سياسات طول كلمات المرور ومديري كلمات المرور، واجعل رسالة الفشل عامة. الأمن لا يعتمد على التجزئة وحدها، لكنه يبدأ من رفض التخزين النصي ومعالجة المسار الكامل بوعي. يوضح هذا الموضوع كيف يتحول مفهوم نظري إلى خطوات يمكن تشغيلها وفحصها.

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

تعليقات