30

我正在开发一个完全由 ajax 驱动的应用程序,其中所有请求都通过基本上相当于一个主控制器的东西,它的基本结构看起来像这样:

if(strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
    fetch($page);
}

这通常足以防止跨站点请求伪造吗?

当每个请求都没有刷新整个页面时,拥有一个旋转令牌是相当不方便的。

我想我可以通过每个请求将唯一令牌作为全局 javascript 变量传递和更新——但不知何故,这感觉很笨拙,而且无论如何似乎天生就不安全。

编辑 - 也许像用户的 UUID 这样的静态令牌总比没有好?

编辑#2 - 正如The Rook指出的那样,这可能是一个令人毛骨悚然的问题。我已经阅读了两种方式的猜测,并听到了关于旧版本的闪存可用于这种恶作剧的传言。由于我对此一无所知,因此我悬赏任何能够解释这是 CSRF 风险的人。否则,我会把它交给Artefacto。谢谢。

4

6 回答 6

19

我会说这已经足够了。如果允许跨域请求,那么您无论如何都注定要失败,因为攻击者可以使用 Javascript 获取 CSRF 令牌并在伪造请求中使用它。

静态令牌不是一个好主意。每个会话至少应生成一次令牌。

EDIT2迈克毕竟是不对的,抱歉。我没有正确阅读我链接到的页面。它说:

一个简单的跨站点请求是: [...] 不使用 HTTP 请求设置自定义标头(例如 X-Modified 等)

因此,如果设置X-Requested-With,则请求必须是预飞行的,并且除非您响应OPTIONS授权跨站请求的预飞行请求,否则它不会通过。

编辑Mike 是对的,从 Firefox 3.5 开始,允许跨站点 XMLHttpRequests 。因此,您还必须检查Origin标头(如果存在)是否与您的站点匹配。

if (array_key_exists('HTTP_ORIGIN', $_SERVER)) {
    if (preg_match('#^https?://myserver.com$#', $_SERVER['HTTP_ORIGIN'])
        doStuff();
}
elseif (array_key_exists('HTTP_X_REQUESTED_WITH', $_SERVER) &&
        (strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest'))
    doStuff(); 
于 2010-07-26T00:07:58.153 回答
1

我不相信这是安全的。同源策略旨在防止来自不同域的文档访问从不同域返回的内容。这就是为什么首先存在 XSRF 问题的原因。一般来说,XSRF 并不关心响应。它用于执行特定类型的请求,例如删除操作。在最简单的形式中,这可以通过格式正确的 img 标签来完成。您提出的解决方案将阻止这种最简单的形式,但不会保护某人使用 XMLHttp 对象发出请求。您需要使用 XSRF 的标准预防技术。我喜欢在 javascript 中生成一个随机数并将其添加到 cookie 和表单变量中。这确保代码也可以为该域编写 cookie。如果您想了解更多信息,请参阅这个条目

此外,要抢占有关 XMLHttp 无法在脚本中工作的评论。我将以下代码与 firefox 3.5 一起使用,从在 localhost 域中运行的 html 向 google 发出请求。内容不会返回,但是使用firebug,可以看到请求已经发出。

<script>
var xmlhttp = false; 

if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
    try {
        xmlhttp = new XMLHttpRequest();
    } catch (e) {
        xmlhttp = false;
    }
}
if (!xmlhttp && window.createRequest) {
    try {
        xmlhttp = window.createRequest();
    } catch (e) {
        xmlhttp = false;
    }
}

xmlhttp.open("GET", "http://www.google.com", true);
xmlhttp.onreadystatechange = function() {
    if (xmlhttp.readyState == 4) {
        alert("Got Response");
        alert(xmlhttp.responseText)
    }
}

xmlhttp.send(null)
alert("test Complete");

于 2010-07-27T15:42:23.497 回答
0

简短的回答:没有。任何攻击者只会使用 Ajax 自己来攻击您的网站。您应该生成一个生命周期较短但不会过长的随机令牌,您将在每个 ajax 请求期间对其进行更新。

您必须在 javascript 中使用一系列令牌,因为您可能同时运行多个 ajax 请求。

于 2010-07-23T07:16:28.057 回答
0

您所做的是安全的,因为 xmlhttprequest 通常不易受到跨站点请求伪造的影响。

由于这是客户端问题,最安全的方法是检查每个浏览器的安全架构:-)

(这是一个总结;我添加这个答案是因为这个问题非常令人困惑,让我们看看投票怎么说)

于 2010-07-26T08:37:09.680 回答
0

我不认为这提供了任何形式的保护。攻击站点仍然可以使用xmlhttprequest其跨站点请求绕过您的检查。

于 2010-07-23T07:05:50.047 回答
0

不,这可以很容易地绕过,通过向包含此标头的服务器及其凭据的请求发出跨域 Flash 请求,请参阅:https ://www.geekboy.ninja/blog/exploiting-json-cross -site-request-forgery-csrf-using-flash/?unapproved=6685&moderation-hash=91554c30888cfb21580f6873e0569da0

防止 CSRF 的最佳方法是使 Header 或 Parameter 包含每个请求的密钥,

于 2020-05-10T12:12:17.827 回答