Ajax 和 CSRF 保护

信息安全 csrf 阿贾克斯
2021-08-24 09:45:50

无需赘述,我有一个 100% Ajax 的网站。对站点的所有请求(GET 和 POST)都是通过 Ajax 完成的。现在我必须实现 CSRF 保护,我遇到的所有解决方案都归结为在标头中发送 CSRF 令牌,但大多数解决方案都从 HTML 或 GET 请求附带的 cookie 中获取此令牌。

现在因为我的网站是 100% Ajax 并且它不会重新加载。我想知道是否可以在每个 POST 请求之前向服务器发出 GET 请求以获取令牌,然后将其与 POST 请求一起提交到标头中,例如

提交 GET 请求以aaa.com/get-csrf-token获取令牌,然后将该令牌与标头中的请求一起提交,如果来自另一个站点的某人向 GET 请求aaa.com/get-csrf-token并且服务器返回一个令牌,那么据我所知他们仍然无法读取该值。

由于令牌是按会话生成的,因此我可以简单地检查提交的令牌是否与我在与该会话关联的 memchache 中拥有的令牌相同。

有人可以告诉我这是否可行吗?

3个回答

是的,你可以这样做。这应该没问题。这是对 CSRF 的合理防御。

请确保副作用操作只能通过 POST(绝不通过 GET)发生,并且所有 POST 检查令牌的存在。此外,请确保将令牌生成为加密强的伪随机数(例如,使用CryptGenRandom()/dev/urandomSecureRandom或类似的)并将其存储在会话状态中。

我不知道这是否比 cookie 双重提交有任何好处——但你可以这样做,它应该可以成功地防止 CSRF。

实际上,每个任务的两个请求是性能开销。您可以使用单个请求简单地实现这一点。您可以在 POST 请求期间简单地验证令牌,并在每个请求中发回新令牌。使用 JS 确保您获取最新的 cookie 值并将其附加到每个 AJAX 发送的请求中。

事实上,如果你想消除对 Web 应用程序的 CSRF 保护的痛苦,你可以看到OWASP CSRF Protector Project,(目前仅适用于 php),它完成了所需的一切,以减轻 CSRF 并与 AJAX(两者XHRactiveXObject)

而不是在每个请求之前都获得一个请求 - 这个怎么样?

  <script>
        var current_token=<?php echo $_SESSION['csrf_token']; ?>

            $.ajax({ 
                type: "POST",
                url:"script.php",
                data: {'token':current_token},
                success: function(data) {
                                var result=JSON.parse(data);
                                current_token=result.token;
                            },
                error:function(error){
                                console.log(error);
                }
          });
  </script>

这是script.php

 <?php

     if($_POST['current_token']==$_SESSION['csrf_token']){

          //do your thing 
          $token="new token" //generate new token here
          $_SESSION['token']=$token;
          $response['token']=$token;
          $out=json_encode($response);
          die ($out);       
    }else{ 
         //request failed - handle as error and ask to re-login or whatever 
    }

解释-

  • 您发送 AJAX,验证会话令牌并发布令牌
  • 如果成功,生成新令牌
  • 更新 $_SESSION['token'] 中的令牌并将新令牌发回
  • 使用成功函数检索令牌并在 JavaScript 中更新

或者,由于新令牌可能被 XSS 欺骗,这是否会产生新的漏洞?