对于ajax驱动的应用程序,x- requested头服务器检查是否足以保护CSRF ?

时间:2022-09-01 04:50:08

I'm working on a completely ajax-driven application where all requests pass through what basically amounts to a main controller which, at its bare bones, looks something like this:

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

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

Is this generally sufficient to protect against cross-site request forgeries?

这是否足以防止跨站点请求伪造?

It's rather inconvenient to have a rotating token when the entire page isn't refreshed with each request.

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

I suppose I could pass and update unique token as a global javascript variable with every request -- but somehow that feels clumsy and seems inherently unsafe anyway.

我认为我可以将unique token作为一个全局javascript变量传递并更新——但无论如何,这感觉有点笨拙,而且似乎本质上不安全。

EDIT - Perhaps a static token, like the user's UUID, would be better than nothing?

编辑——也许一个静态标记,比如用户的UUID,会比什么都没有要好?

EDIT #2 - As The Rook pointed out, this might be a hair-splitting question. I've read speculation both ways and heard distant whispers about older versions of flash being exploitable for this kind of shenanigans. Since I know nothing about that, I'm putting up a bounty for anyone who can explain how this is a CSRF risk. Otherwise, I'm giving it to Artefacto. Thanks.

编辑#2 -正如车里指出的,这可能是一个令人毛骨悚然的问题。我读过各种各样的猜测,也听过一些遥远的传言,说flash的旧版本会被这种诡计利用。由于我对此一无所知,我悬赏给任何能解释这是CSRF风险的人。否则,我就把它当作人工制品。谢谢。

6 个解决方案

#1


13  

I'd say it's enough. If cross-domain requests were permitted, you'd be doomed anyway because the attacker could use Javascript to fetch the CSRF token and use it in the forged request.

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

A static token is not a great idea. The token should be generated at least once per session.

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

EDIT2 Mike is not right after all, sorry. I hadn't read the page I linked to properly. It says:

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

A simple cross-site request is one that: [...] Does not set custom headers with the HTTP Request (such as X-Modified, etc.)

一个简单的跨站请求是:……不使用HTTP请求设置自定义头(如x修改等)

Therefore, if you set X-Requested-With, the request has to be pre-flown, and unless you respond to pre-flight OPTIONS request authorizing the cross-site request, it won't get through.

因此,如果您设置了x - requesteed - with,请求必须预先飞行,除非您响应飞行前选项请求授权跨站点请求,否则它将无法通过。

EDIT Mike is right, as of Firefox 3.5, cross-site XMLHttpRequests are permitted. Consequently, you also have to check if the Origin header, when it exists, matches your site.

编辑Mike是对的,Firefox 3.5允许跨站点xmlhttprequest。因此,您还必须检查源头在存在时是否与站点匹配。

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(); 

#2


1  

I do not believe that this is safe. The same origin policies are designed to prevent the documents from different domains from accessing the content that is returned from a different domain. This is why XSRF problems exist in the first place. In general XSRF doesn't care about the response. It is used to execute a specific type of request, like a delete action. In the simplest form, this can be done with a properly formatted img tag. Your proposed solution would prevent this simplest form, but doesn't protect someone from using the XMLHttp object to make the request. You need to use the standard prevention techniques for XSRF. I like to generate a random number in javascript and add it to the cookie and a form variable. This makes sure that the code can also write cookies for that domain. If you want more information please see this entry.

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

Also, to pre-empt the comments about XMLHttp not working in script. I used the following code with firefox 3.5 to make a request to google from html running in the localhost domain. The content will not be returned, but using firebug, you can see that the request is made.

另外,要防止对XMLHttp的注释不使用脚本。我在firefox 3.5中使用了下面的代码,从在localhost域中运行的html中向谷歌提出请求。不会返回内容,但是使用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");

#3


1  

Yes. It's a recognized approach to CSRF protection.

是的。这是一种公认的CSRF保护方法。

https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#Protecting_REST_Services:_Use_of_Custom_Request_Headers

https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet # Protecting_REST_Services:_Use_of_Custom_Request_Headers

#4


0  

I do not think this offers any kind of protection. An attacking site could still use xmlhttprequest for its cross-site request bypass your check.

我不认为这能提供任何保护。攻击站点仍然可以使用xmlhttprequest进行跨站点请求,而不需要检查。

#5


0  

Short answer : no. Any attacker would just use Ajax himself to attack your website. You should generate a random token with a short but not too much lifetime which you would update during each ajax request.

简短的回答:没有。任何攻击者都会使用Ajax攻击你的网站。您应该生成一个具有短但不太长生命期的随机令牌,在每个ajax请求期间更新该令牌。

You'd have to use an array of tokens in javascript as you may have multiple ajax request running at the same time.

您必须在javascript中使用标记数组,因为您可能同时运行多个ajax请求。

#6


0  

What you are doing is secure because xmlhttprequest is usually not vulnerable to cross-site request forgery.

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

As this is a client side problem, the safest way would be to check the security architecture of each browser :-)

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

(This is a summary; I am adding this answer because this question is very confusing, let's see what the votes say)

(这是一个总结;我加上这个答案是因为这个问题很让人困惑,让我们看看投票结果是什么)

#1


13  

I'd say it's enough. If cross-domain requests were permitted, you'd be doomed anyway because the attacker could use Javascript to fetch the CSRF token and use it in the forged request.

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

A static token is not a great idea. The token should be generated at least once per session.

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

EDIT2 Mike is not right after all, sorry. I hadn't read the page I linked to properly. It says:

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

A simple cross-site request is one that: [...] Does not set custom headers with the HTTP Request (such as X-Modified, etc.)

一个简单的跨站请求是:……不使用HTTP请求设置自定义头(如x修改等)

Therefore, if you set X-Requested-With, the request has to be pre-flown, and unless you respond to pre-flight OPTIONS request authorizing the cross-site request, it won't get through.

因此,如果您设置了x - requesteed - with,请求必须预先飞行,除非您响应飞行前选项请求授权跨站点请求,否则它将无法通过。

EDIT Mike is right, as of Firefox 3.5, cross-site XMLHttpRequests are permitted. Consequently, you also have to check if the Origin header, when it exists, matches your site.

编辑Mike是对的,Firefox 3.5允许跨站点xmlhttprequest。因此,您还必须检查源头在存在时是否与站点匹配。

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(); 

#2


1  

I do not believe that this is safe. The same origin policies are designed to prevent the documents from different domains from accessing the content that is returned from a different domain. This is why XSRF problems exist in the first place. In general XSRF doesn't care about the response. It is used to execute a specific type of request, like a delete action. In the simplest form, this can be done with a properly formatted img tag. Your proposed solution would prevent this simplest form, but doesn't protect someone from using the XMLHttp object to make the request. You need to use the standard prevention techniques for XSRF. I like to generate a random number in javascript and add it to the cookie and a form variable. This makes sure that the code can also write cookies for that domain. If you want more information please see this entry.

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

Also, to pre-empt the comments about XMLHttp not working in script. I used the following code with firefox 3.5 to make a request to google from html running in the localhost domain. The content will not be returned, but using firebug, you can see that the request is made.

另外,要防止对XMLHttp的注释不使用脚本。我在firefox 3.5中使用了下面的代码,从在localhost域中运行的html中向谷歌提出请求。不会返回内容,但是使用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");

#3


1  

Yes. It's a recognized approach to CSRF protection.

是的。这是一种公认的CSRF保护方法。

https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#Protecting_REST_Services:_Use_of_Custom_Request_Headers

https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet # Protecting_REST_Services:_Use_of_Custom_Request_Headers

#4


0  

I do not think this offers any kind of protection. An attacking site could still use xmlhttprequest for its cross-site request bypass your check.

我不认为这能提供任何保护。攻击站点仍然可以使用xmlhttprequest进行跨站点请求,而不需要检查。

#5


0  

Short answer : no. Any attacker would just use Ajax himself to attack your website. You should generate a random token with a short but not too much lifetime which you would update during each ajax request.

简短的回答:没有。任何攻击者都会使用Ajax攻击你的网站。您应该生成一个具有短但不太长生命期的随机令牌,在每个ajax请求期间更新该令牌。

You'd have to use an array of tokens in javascript as you may have multiple ajax request running at the same time.

您必须在javascript中使用标记数组,因为您可能同时运行多个ajax请求。

#6


0  

What you are doing is secure because xmlhttprequest is usually not vulnerable to cross-site request forgery.

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

As this is a client side problem, the safest way would be to check the security architecture of each browser :-)

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

(This is a summary; I am adding this answer because this question is very confusing, let's see what the votes say)

(这是一个总结;我加上这个答案是因为这个问题很让人困惑,让我们看看投票结果是什么)