【问题标题】:protecting against CSRF on ajax requests and forms without submit buttons在没有提交按钮的情况下防止 ajax 请求和表单上的 CSRF
【发布时间】:2012-04-25 23:24:28
【问题描述】:

我对网络安全还很陌生。我想知道在没有提交按钮(即状态更新)的情况下在 ajax 请求和表单上使用令牌以保护 CSRF 的正确方法是什么。有人可以给我看一个代码示例吗?我知道如何正确处理带有提交按钮的表单。同样在我的 ajax 文件夹中,我有一个带有以下内容的 htaccess:

SetEnvIfNoCase X-Requested-With XMLHttpRequest ajax
Order Deny,Allow
Deny from all
Allow from env=ajax

这对于 ajax 请求是否足够安全,或者我是否也应该为 ajax 请求实现令牌安全性?

【问题讨论】:

    标签: ajax security token csrf


    【解决方案1】:

    您需要做的就是在页面加载时生成一个秘密(令牌)。将它放在页面上,并在会话中。通常,如果可以的话,我会将它作为隐藏字段放在表单中,或者如果它是一个更大的非常 ajaxy 页面的一部分,我会将它放在相关元素上的 value 属性中,比如包装整个页面的 div。其他人会添加一个带有变量的脚本标签。

    然后,每当您进行 AJAX 调用或发送表单时,您都会包含一个密码字段。 (Cheekysoft 的回答更详细地介绍了如何使用原始 JS 执行此操作,它可以与 jQuery 或您可能使用的任何其他框架大致相同。)将其与后端的会话值匹配以确保它们仍然存在一样的(来自同一个来源),你很好。

    如果您想增加安全性,请在每个请求中重新生成密钥,并将该新密钥与请求的数据一起返回。让所有 ajax 请求用新值替换隐藏字段或值属性。如果您正在执行大量请求或并发请求,这并不能很好地工作。确实,如果您通过 HTTPS 执行此操作,则每次加载整个页面时生成一个就足够了,您应该这样做。

    如果您不是通过 HTTPS 执行此操作,那真的没关系,坐在网吧/星巴克的人可以窃取会话并重新加载页面。

    如果您要经常这样做,那么值得查看 jQuery 和 various plugins,这将有助于为您提供 CSRF 保护。 Also, my way isn't the only way.

    【讨论】:

    • 感谢您的回复。如果我根据您的链接之一将其作为请求标头发送:var csrf_token = '<?=$ajaxtoken_value?>'; $("body").bind("ajaxSend", function(elm, xhr, s){ if (s.type == "POST") { xhr.setRequestHeader('X-CSRF-Token', csrf_token); } }); 我将如何检查 ajax 端?我是否必须使用发布请求检索令牌?
    • @Anonymous 这取决于您选择的语言。这看起来像 PHP,所以我会检查类似 getallheaders 的内容
    • 我知道如何检查它:if($_SERVER['HTTP_X_CSRF_TOKEN'] == $_SESSION['ajaxtoken_value']) { 谢谢。唯一的问题是请求是通过http。我将如何更改我的设置以便通过 https 完成请求?
    • @Anonymous 您是否已经有其他通过 ssl 的东西? (https)如果是这样,可能您只需将文件移动到 httpsdocs 文件夹并在请求 URL 中将 http 更改为 https。如果不。这是互联网的一个问题,因为它涉及设置 SSL。
    • 我想我需要设置 SSL。感谢您迄今为止的所有帮助!
    【解决方案2】:

    如果您的 XHR 是 GET 请求,请将令牌作为 URL 参数包含并让 PHP 脚本从 $_GET[] 读取它。如果您的 XHR 是 POST,请将令牌弹出到 POST 数据中并让 PHP 脚本从 $_POST[] 读取它。

    GET 请求

    var token = getElementById( 'myHiddenField' ).value;
    var xhr = new XMLHttpRequest();
    xhr.open( 'GET', 'server.php?token=' + token );
    xhr.send( null );
    

    POST 请求

    var token = getElementById( 'myHiddenField' ).value;
    var xhr = new XMLHttpRequest();
    xhr.open( 'POST', 'server.php', true );
    xhr.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded' );
    xhr.onreadystatechange = function() {
      if (xhreq.readystate != 4) { return; }
      // do client side stuff here
    };
    xhr.send( 'token=' + token );
    

    【讨论】:

    • 您可能还应该包括一些关于何时何地生成令牌的注释。以及如何确保您在两端检查同一个。
    • @DampeS8N 出于完整性考虑,请随意编辑,但 OP 表示他对表单帖子中的 CSRF 令牌感到满意。
    • 感谢您的回复。如果我将其作为请求标头发送: var csrf_token = '=$ajaxtoken_value?>'; $("body").bind("ajaxSend", function(elm, xhr, s){ if (s.type == "POST") { xhr.setRequestHeader('X-CSRF-Token', csrf_token); } });我将如何检查 ajax 方面?我是否必须使用发布请求检索令牌?
    • @Cheekysoft 是的,但是从谷歌来到这里的 100 人可能需要这些信息。现在是将不良做法扼杀在萌芽状态的时候了。
    • @Anonymous 将令牌设置为客户端 javascript 调用中的附加 HTTP 标头是一个不错的选择。在服务器端,您可以使用此问题stackoverflow.com/questions/541430/… 中的方法在 PHP 中阅读。
    猜你喜欢
    • 1970-01-01
    • 2011-12-04
    • 1970-01-01
    • 1970-01-01
    • 2015-05-30
    • 1970-01-01
    • 2016-08-29
    • 2021-12-20
    • 1970-01-01
    相关资源
    最近更新 更多