تصدير تجزئات كلمات المرور بتنسيق PHC

يمكن العثور على التفاصيل الحالية حول نظام تخزين كلمات مرور Discourse في discourse/docs/SECURITY.md at main · discourse/discourse · GitHub. وقت كتابة هذا النص، نستخدم PBKDF2-SHA256 مع 600,000 تكرار.

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

يتم تخزين بيانات كلمة المرور في جدول user_passwords، الذي يحتوي على أعمدة password_hash، password_salt، و password_algorithm. يخزن عمود password_algorithm بادئة خوارزمية PHC الكاملة (مثل $pbkdf2-sha256$i=600000,l=32$)، والتي قد تختلف من مستخدم لآخر إذا تم زيادة عدد التكرارات بمرور الوقت.

يمكنك استخدام مستكشف البيانات لتصدير المعلومات بتنسيق قابل للقراءة بواسطة الحاسوب:

SELECT users.id, users.username, up.password_salt, up.password_hash, up.password_algorithm
FROM users
INNER JOIN user_passwords up ON users.id = up.user_id
WHERE users.id > 0

سيؤدي هذا إلى تصدير البيانات بتنسيق Discourse الأصلي. يتم ترميز الملح (salt) بصيغة سداسية عشرية (hex)، ويُرمَّز تجزئة كلمة المرور (password hash) أيضًا بصيغة سداسية عشرية.

تدعم بعض الأنظمة الخارجية تنسيق سلسلة PHC الذي يهدف إلى تمثيل مخرجات دالة تجزئة كلمات المرور بطريقة عابرة للخوارزميات. بالنسبة لـ pbkdf2-sha256، تحتوي هذه السلسلة على نوع الخوارزمية، وعدد التكرارات، والملح المشفر بترميز Base64، والتجزئة المشفرة بترميز Base64. لحسن الحظ، يمكن لـ Postgres التعامل مع كل ذلك في استعلام واحد.

لتوليد سلاسل PHC لكل مستخدم في Discourse، يمكنك استخدام استعلام مستكشف البيانات مثل هذا:

SELECT users.id, users.username,
  concat(
    up.password_algorithm,
    replace(encode(up.password_salt::bytea, 'base64'), '=', ''),
    '$',
    replace(encode(decode(up.password_hash, 'hex'), 'base64'), '=', '')
  ) as phc
FROM users
INNER JOIN user_passwords up ON users.id = up.user_id
WHERE users.id > 0

إذا كنت تستخدم Auth0، فستحتاج إلى هذا الاستعلام بدلاً من ذلك:

SELECT
    user_emails.email,
    users.active as email_verified,
    concat(
        up.password_algorithm,
        replace(encode(up.password_salt::bytea, 'base64'), '=', ''),
        '$',
        replace(encode(decode(up.password_hash, 'hex'), 'base64'), '=', '')
    ) as password_hash
FROM users
INNER JOIN user_passwords up ON users.id = up.user_id
INNER JOIN user_emails 
ON users.id = user_emails.user_id 
AND user_emails.primary IS TRUE
AND users.id > 0
13 إعجابًا

ملاحظة هنا: قمت (بمساعدة من فريق Auth0 الودود) في النهاية بتعديل استعلام المثال لتوليد سلاسل PHC صالحة لاستيراد كلمات مرور المستخدمين إلى Auth0.

كما قمت بتشفير الملح كـ base64 بتغيير هذا السطر

salt,

إلى

replace(encode(users.salt::bytea, 'base64'), '=', ''),

لمزيد من التفاصيل، راجع الرابط التالي (بما في ذلك خطوات مفصلة حول كيفية استيراد مستخدمين Discourse وكلمات مرورهم إلى Auth0).

إعجاب واحد (1)

شكرًا لك @angus - هذا مثير للاهتمام لأننا شهدنا عميلًا يستخدم الاستعلام في المنشور الأصلي بنجاح لاستيراد المستخدمين إلى Auth0. أتساءل عما إذا كان قد حدث تغيير في عملية الاستيراد الخاصة بهم - كما أتذكر، كانت إمكانية استيراد سلاسل PHC إلى Auth0 جديدة جدًا في نوفمبر :thinking:

3 إعجابات

نعم، كنت أتساءل عن ذلك وفكرت في الأمر نفسه.

كما لم أكن متأكدًا تمامًا من الصياغة في مواصفات PHC. غير متأكد مما إذا كان هذا يعني أن الملح يجب ترميزه باستخدام Base64 أم لا.

يتكون الملح من تسلسل من الأحرف في: [a-zA-Z0-9/+.-] (أحرف صغيرة، أحرف كبيرة، أرقام، /، +، . و -). يجب أن تحدد مواصفات الدالة مجموعة قيم الملح الصالحة وأقصى طول لهذا الحقل. يجب على الدوال التي تعمل على أملاح ثنائية عشوائية أن تحدد أن هذا الحقل هو ترميز Base64 لقيمة ثنائية يكون طولها ضمن نطاق محدد أو مجموعة من النطاقات.

إعجابَين (2)

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

شكرًا لك.

لا يدعم جوهر Discourse استيراد كلمات المرور، رغم أنه قد يكون ذلك ممكنًا باستخدام نسخة معدلة من هذه الإضافة التابعة لجهة خارجية:

4 إعجابات

شكرًا لك! لقد وجدت المستودع على GitHub، لكنني لم أعثر على الموضوع هنا على ميتا.

إعجاب واحد (1)

مرحبًا @angus، نحن نقوم بتنظيف الأمور هنا.

هل صحيح أن كتلة كود المنشور الأصلي يجب أن تكون كالتالي:

SELECT id, username,
  concat(
    '$pbkdf2-sha256$i=64000,l=32$',
    replace(encode(users.salt::bytea, 'base64'), '=', ''),
    '$',
    replace(encode(decode(password_hash, 'hex'), 'base64'), '=', '')
  ) as phc
FROM users

وتشمل شيئًا مثل:

لمزيد من المعلومات حول استيراد كلمات مرور Discourse إلى Auth0، راجع: Bulk User Import Custom Password Hash Issue - Auth0 Community.

لنقل البيانات من Auth0 إلى Discourse، قد يساعدك هذا: Migrated password hashes support.

3 إعجابات

نعم، يبدو ذلك جيدًا.

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

كما أن تصدير كلمات المرور في PHC ليس بالضرورة مخصصًا لـ Auth0 فقط، لذا ربما يُشار إلى ذلك على أنه “مثال” فقط.

الاستعلام الكامل الذي استخدمته للتصدير كان:

SELECT
    user_emails.email,
    users.active as email_verified,
    concat(
        '$pbkdf2-sha256$i=64000,l=32$',
        replace(encode(users.salt::bytea, 'base64'), '=', ''),
        '$',
        replace(encode(decode(users.password_hash, 'hex'), 'base64'), '=', '')
    ) as password_hash
FROM users
INNER JOIN user_emails 
ON users.id = user_emails.user_id 
AND user_emails.primary IS TRUE
AND users.id > 0
إعجابَين (2)