نظام تسجيل الدخول PHP: تذكرني (ملف تعريف الارتباط المستمر) [مكرر

StackOverflow https://stackoverflow.com/questions/3128985

سؤال

هذا السؤال لديه بالفعل إجابة هنا:

أرغب في إضافة خيار اختيار "تذكرني" قبل تسجيل الدخول.

ما هي أفضل طريقة لتخزين ملف تعريف الارتباط بشكل آمن في متصفح المستخدم؟

على سبيل المثال ، لدى Facebook خانة الاختيار "تذكرني" بحيث في كل مرة تدخل فيها facebook.com ، قمت بتسجيل الدخول بالفعل.

يستخدم تسجيل الدخول الحالي لي جلسات بسيطة.

هل كانت مفيدة؟

المحلول

يتم طرح هذا السؤال كثيرًا ، إليك بعض الروابط لك.

هناك أيضًا بعض الموارد الرائعة التي تم جمعها معًا في إجابة هذا السؤال: الدليل النهائي لمصادقة الموقع

نصائح أخرى

تحديث (2017-08-13): لفهم سبب انفصالنا selector و token, ، بدلا من مجرد استخدام أ token, ، يرجى القراءة هذه المقالة حول تقسيم الرموز لمنع هجمات التوقيت على استفسارات تحديد.

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

ديباجة - بنية قاعدة البيانات

نريد جدولًا منفصلاً عن جدول المستخدمين الذي يبدو مثل هذا (MySQL):

CREATE TABLE `auth_tokens` (
    `id` integer(11) not null UNSIGNED AUTO_INCREMENT,
    `selector` char(12),
    `token` char(64),
    `userid` integer(11) not null UNSIGNED,
    `expires` datetime,
    PRIMARY KEY (`id`)
);

الأشياء المهمة هنا هي ذلك selector و token هي حقول منفصلة.

بعد تسجيل الدخول

إذا لم يكن لديك random_bytes(), ، فقط احصل على نسخة من Random_compat.

if ($login->success && $login->rememberMe) { // However you implement it
    $selector = base64_encode(random_bytes(9));
    $authenticator = random_bytes(33);

    setcookie(
        'remember',
         $selector.':'.base64_encode($authenticator),
         time() + 864000,
         '/',
         'yourdomain.com',
         true, // TLS-only
         true  // http-only
    );

    $database->exec(
        "INSERT INTO auth_tokens (selector, token, userid, expires) VALUES (?, ?, ?, ?)", 
        [
            $selector,
            hash('sha256', $authenticator),
            $login->userId,
            date('Y-m-d\TH:i:s', time() + 864000)
        ]
    );
}

إعادة صياغة في تحميل الصفحة

if (empty($_SESSION['userid']) && !empty($_COOKIE['remember'])) {
    list($selector, $authenticator) = explode(':', $_COOKIE['remember']);

    $row = $database->selectRow(
        "SELECT * FROM auth_tokens WHERE selector = ?",
        [
            $selector
        ]
    );

    if (hash_equals($row['token'], hash('sha256', base64_decode($authenticator)))) {
        $_SESSION['userid'] = $row['userid'];
        // Then regenerate login token as above
    }
}

تفاصيل

نستخدم 9 بايت من البيانات العشوائية (Base64 مشفرة على 12 حرفًا) لمحددنا. هذا يوفر 72 بت من الفضاء وبالتالي 236 أجزاء من مقاومة الاصطدام (هجمات أعياد الميلاد) ، والتي هي أكبر من سعة التخزين لدينا (integer(11) UNSIGNED) بعامل 16.

نستخدم 33 بايت (264 بت) من العشوائية لمصادقنا الفعلي. يجب أن يكون هذا لا يمكن التنبؤ به في جميع السيناريوهات العملية.

نقوم بتخزين تجزئة SHA256 للمصادقة في قاعدة البيانات. هذا يخفف من مخاطر انتحال المستخدم بعد تسرب المعلومات.

نعيد حساب تجزئة SHA256 لقيمة المصادقة المخزنة في ملف تعريف الارتباط للمستخدم ثم قارنها مع تجزئة SHA256 المخزنة باستخدام hash_equals() لمنع هجمات التوقيت.

لقد فصلنا المحدد عن المصادقة لأن عمليات البحث DB ليست وقتًا ثابتًا. هذا يزيل التأثير المحتمل لتسربات التوقيت على عمليات البحث دون التسبب في نجاح شديد في الأداء.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top