繁体   English   中英

PHP登录系统:记住我(持久性cookie)[重复]

[英]PHP login system: Remember Me (persistent cookie) [duplicate]

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

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

例如,Facebook 有他们的“记住我”复选框,这样你每次进入 facebook.com 时就已经登录了。

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

更新(2017-08-13) :要理解为什么我们要分离selectortoken ,而不是仅仅使用token ,请阅读这篇关于拆分 token 以防止对 SELECT 查询进行计时攻击的文章

我将提取这篇博文中概述的关于安全长期身份验证的策略,因为它涵盖了很多领域,我们只对“记住我”部分感兴趣。

序言 - 数据库结构

我们想要一个与用户表不同的表,看起来像这样(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 字节的随机数据(base64 编码为 12 个字符)作为我们的选择器。 这提供了 72 位的密钥空间,因此提供了 2 36位的抗碰撞性(生日攻击),这比我们的存储容量( integer(11) UNSIGNED )大了 16 倍。

我们将 33 字节(264 位)的随机性用于我们的实际身份验证器。 这在所有实际场景中都应该是不可预测的。

我们将身份验证器的 SHA256 哈希值存储在数据库中。 这降低了信息泄露后用户冒充的风险。

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

我们将选择器与验证器分开,因为数据库查找不是恒定时间的。 这消除了时间泄漏对搜索的潜在影响,而不会造成严重的性能损失。

这个问题被问了很多,这里有一些链接给你。

在这个问题的答案中还收集了一些很好的资源: 网站认证的权威指南

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM