PHP login system: Remember Me (persistent cookie)
我想在登录前添加一个"记住我"复选框选项。
在用户浏览器中安全存储cookie的最佳方法是什么?
例如,Facebook有他们的"记住我"复选框,这样每当你进入facebook.com,你就已经登录了。
我当前的登录使用简单会话。
Update (2017-08-13): To understand why we're separating
selector andtoken , instead of just using atoken , please read this article about splitting tokens to prevent timing attacks on SELECT queries.
号
我将提取这篇关于安全长期认证的博客文章中概述的策略,因为这涉及很多领域,我们只对"记住我"部分感兴趣。
前言-数据库结构我们需要一个与用户表分开的表,如下所示(mysql):
1 2 3 4 5 6 7 8 | 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`) ); |
这里重要的是,
如果你没有
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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) ] ); } |
号页面加载时重新验证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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位的抗碰撞(生日攻击),比我们的存储容量(
我们使用33字节(264位)的随机性作为实际验证器。在所有实际场景中,这都是不可预测的。
我们将authenticator的sha256散列存储在数据库中。这可以降低信息泄漏后用户冒充的风险。
我们重新计算存储在用户cookie中的authenticator值的sha256哈希,然后使用
我们将选择器与authenticator分离,因为db查找不是恒定时间。这消除了定时泄漏对搜索的潜在影响,而不会造成严重的性能损失。
这个问题经常被问到,这里有一些链接给你。
- 实施安全"记住我"的最佳实践
- "在这台电脑上记住我"-它应该如何工作?
- "让我登录"-最好的方法
在回答这个问题时,我们还收集了一些很好的资源:网站认证的最终指南