1

我有一个问题,我无法找到任何解决方案。问题是当用户打开页面时,会像这样生成一个安全令牌并添加到会话数组中

$token = generate_csrf_token();
$_SESSION['tokens'][] = $token;

我在表单提交中使用这个 $token 作为 CSRF 安全性的隐藏输入。现在,问题是,如果用户发表任何评论,我可以在像这样发布评论后从数组中删除 $token

$token = $_POST['token'];

// comment posting process

$key = array_search($token, $_SESSION['tokens']);
unset($_SESSION['tokens'][$key]);

但是如果用户没有发表任何评论并退出页面,如何,我可以从$_SESSION['tokens'][]数组中删除该 $token。如果我不删除,这可能会导致数组中有这么多未使用的 $token。

4

2 回答 2

1

在正常情况下,一旦用户退出页面,他引用会话的 cookie 将被清除。(当他关闭浏览器时)。下次他打开浏览器并访问您的页面时,他将开始一个新会话。

现在因为他丢失了对您会话的引用并且没有其他人在使用它,所以会话文件将不再被访问,并且一旦它没有被访问一段时间,垃圾收集器就会清除它。

因此,当用户离开页面时,您无需担心“清除安全令牌”。这是自动处理的。除非你自己搞砸了会话管理。有关可以更改的选项,请参阅会话设置信息。

现在,如果您的目标是在用户仍在使用同一会话的页面上时清除令牌,则有几个选项。

第一个是每个会话使用一个安全令牌。如果用户关闭页面(阅读:在您的站点上加载另一个页面),那么他将在$_SESSION['token'](无数组)中发出一个新令牌并清除旧令牌。这确实需要您POST在更改之前检查令牌。

另一种选择是只保留最后 5 个左右的标记。然后,您可以保持其清洁,而无需更改令牌检查。您可以使用array_shift来做到这一点

<?
$tokens[] = 'new token';
if (count($tokens)>5) {
  array_shift($tokens); //first is removed, so the last 5 remain
}
?>

我能想到的最后一种方法是在令牌中添加时间,并在页面请求中循环遍历所有令牌并检查时间。如果时间超过 xx 分钟,请将其删除。

于 2013-04-29T06:49:44.393 回答
1

与任何异步客户端-服务器状态一样,答案是超时。你不能保证一个令牌会被使用,即使它最终会被使用,你也不知道什么时候会被使用。对于未使用的令牌也没有明确的反馈机制;未使用的令牌根本就不会被使用。

因此,将时间戳与每个令牌相关联。您会定期检查所有存储的令牌并删除您认为已过期的令牌。选择一个合理的到期时间框架。例如:

// run garbage collection roughly every 100 page loads
if (mt_rand(0, 100) == 0) {
    foreach ($_SESSION['tokens'] as $i => $token) {
        if ($token['timestamp'] < time() - 3600) {
            unset($_SESSION['tokens'][$i]);
        }
    }
}

由于会话最终会通过相同的机制自行到期,也许您可​​以简单地将其留给会话到期。

于 2013-04-29T06:49:44.640 回答