如何从数组中删除未使用的安全令牌


How to Remove Un-used Security Tokens from the Array

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

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

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

$token = $_POST['token'];
// comment posting process
$key = array_search($token, $_SESSION['tokens']);
unset($_SESSION['tokens'][$key]);

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

在正常情况下,一旦用户退出一个页面,他的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分钟,则删除。

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

因此,将时间戳与每个令牌关联起来。定期检查所有存储的令牌,并删除您认为过期的令牌。选择一个合理的过期时间。例如:
// 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]);
        }
    }
}

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