这个问题在这里已经有一个答案:

我想在登录之前添加一个“记住我”复选框选项。

在用户的浏览器中安全存储cookie的最佳方法是什么?

例如,Facebook拥有他们的“记住我”复选框,以便每次输入Facebook.com都已登录。

我当前的登录使用简单会议。

有帮助吗?

解决方案

这个问题得到了很多问,这里有一些链接。

在这个问题的答案中,还有一些很棒的资源: 网站身份验证的权威指南

其他提示

更新(2017-08-13): :了解为什么我们分开 selectortoken, ,而不是仅使用 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`)
);

这里重要的是 selectortoken 是单独的字段。

登录后

如果你没有 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个字节的随机数据(基本64编码为12个字符)。这提供了72位键空间,因此236 碰撞阻力(生日攻击),它比我们的存储容量大(integer(11) UNSIGNED)16倍。

我们为实际身份验证者使用33个字节(264位)随机性。在所有实际情况下,这都是不可预测的。

我们在数据库中存储了身份验证器的SHA256哈希。这可以减轻信息泄漏后用户模仿的风险。

我们重新计算存储在用户cookie中的身份验证器值的sha256哈希,然后将其与存储的sha256哈希进行比较 hash_equals() 防止正时攻击。

我们将选择器与身份验证器分开,因为DB查找不是恒定的时间。这消除了计时泄漏对搜索的潜在影响,而不会引起剧烈的性能。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top