نظام تسجيل الدخول PHP: تذكرني (ملف تعريف الارتباط المستمر) [مكرر
-
01-10-2019 - |
سؤال
هذا السؤال لديه بالفعل إجابة هنا:
- "اجعلني مسجلاً" - أفضل طريقة 12 إجابة
أرغب في إضافة خيار اختيار "تذكرني" قبل تسجيل الدخول.
ما هي أفضل طريقة لتخزين ملف تعريف الارتباط بشكل آمن في متصفح المستخدم؟
على سبيل المثال ، لدى 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 ليست وقتًا ثابتًا. هذا يزيل التأثير المحتمل لتسربات التوقيت على عمليات البحث دون التسبب في نجاح شديد في الأداء.