【问题标题】:CSRF token collisions with multiple tabsCSRF 令牌与多个选项卡发生冲突
【发布时间】:2020-06-23 09:39:09
【问题描述】:

我在我的应用程序中构建了 CSRF 保护,只需在 每个 页面加载时生成一个随机令牌,将其放入会话中,然后将令牌绑定到 @987654321 @tag 属性如:

<body data-csrf-token="csrf_GeJf53caJD6Q5WzwAzfy">

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

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

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

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

【问题讨论】:

    标签: php security csrf csrf-protection


    【解决方案1】:

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

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

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

    【讨论】:

    • 我是在用户第一次导航到login 页面还是在login 表单操作页面中生成令牌?现在,即使在登录页面上,我也会将 CSRF 令牌传递给登录操作。
    • 这有点难以回答。登录页面上的 CSRF 令牌具有少量价值 - 小于登录用户看到的表单上的令牌,但更频繁地更改令牌。登录表单上的 CSRF 令牌真正为您提供的只是对一种分布式蛮力攻击的少量保护,在这种攻击中,攻击者会欺骗毫无戒心的用户浏览器尝试登录并使用另一个侧通道攻击来查看它们是否有效。另一方面,假设一个合法用户打开登录页面,等待 20 分钟(会话到期),然后尝试登录。
    • ...如果您是一个非常大、非常高价值的网站,前者可能只是一个问题;后者更有可能导致用户感到沮丧。我会在登录操作页面上生成令牌。
    【解决方案2】:

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

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

    【讨论】:

    • 我是否曾经从数组中清除令牌?如果用户打开 11 个选项卡,理论上 CSRF 令牌数组中会有 11 个元素?
    • 我不同意。每个会话生成多个令牌并不是“更好”。
    • @josh3736:很公平。我的回答不是很清楚。如果他真的想要每页一个,我的意思是“更好”。我已经对其进行了编辑以澄清。
    【解决方案3】:

    我遇到了这个确切的问题,在页面加载时我正在生成一个这样的 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 之类的工具将黑客 API 帖子放在一起,等等

    这可能就是这个问题存在的原因......了解 CSRF 令牌的保护范围。

    【讨论】:

      猜你喜欢
      • 2015-01-23
      • 2017-06-24
      • 2018-06-05
      • 2013-11-26
      • 1970-01-01
      • 2012-04-10
      • 2014-01-02
      • 2020-09-01
      • 2012-01-11
      相关资源
      最近更新 更多