CSRF令牌与多个选项卡冲突

时间:2013-11-18 20:29:40

标签: php security csrf csrf-protection

我在应用程序中构建了 CSRF 保护,只需在每个页面加载时生成随机令牌,将其置于会话中,然后将令牌绑定到{{ 1}}标签属性,如:

<body>

然后在每个表单操作或ajax请求中,我只需从body标签中获取令牌并将其发送出去。

这很有效,除了一个大问题。用户正在打开应用程序的多个选项卡,我看到令牌冲突。例如,用户加载第一页并生成令牌,然后他们切换选项卡,加载另一页,生成新令牌。最后,他们切换回第一页并提交格式化操作。这会导致无效的CSRF令牌错误。

重新设计此选项以防止与多个标签发生冲突的最佳方法是什么,同时尽可能保证其安全。

在登录正确的解决方案时,只是生成单一令牌,而不是在每次加载页面时生成新令牌?

3 个答案:

答案 0 :(得分:15)

假设您的应用程序使用SSL加以保护,那么通过在每个页面加载时生成新标记实际上没有创建任何值。它不会阻止攻击者利用XSS漏洞 - 他们无论如何都可以访问新生成的令牌。

记住CSRF令牌防范的内容:恶意的第三方页面盲目地尝试将数据发布到您的应用程序,希望用户登录。在这种攻击中,攻击者永远无法访问CSRF令牌,所以频繁更换它并不好。

不要浪费时间和资源来跟踪每个会话的多个令牌。只需在开始时生成一个即可完成。

答案 1 :(得分:2)

您可以在登录时使用单个令牌。正如@ Josh3736指出的那样,这很好用。

如果您确实希望每页有一个令牌,则可以在$ _SESSION中存储一组有效令牌。然后,您将在使用它们时使单个令牌到期。您也可以选择在超时期限后使它们过期,但只有在超时短于会话超时时才有意义。但是,再次,你真正完成了什么?对于CSRF而言,单个令牌完全正常。

答案 2 :(得分:0)

我遇到了这个确切的问题,在页面加载时,我正在生成这样的CSRF令牌:

$_SESSION["token"] = bin2hex(random_bytes(32));

多个标签导致CSRF不匹配,所以我改为:

if (!isset($_SESSION['token'])) {
    $_SESSION['token'] = bin2hex(random_bytes(32));
}

服务器端,我这样做(精简版):

$csrf = preg_replace("/[^a-zA-Z0-9]+/", "", $_POST["token"]);
if ($csrf !== $_SESSION["token"]) {
    // Give an error
    die ("No valid CSRF token provided");
}

这可以防止XSS攻击,但是并不能阻止某人进入页面,获取PHP会话ID(来自标头)和CSRF令牌,并使用诸如Postman或WGET之类的工具来汇总hack API帖子,等

这可能就是为什么存在这个问题的原因...了解CSRF令牌用于防御的范围。