同源策略
是什么?
同源策略是浏览器间标准化的一种安全措施。这里的“来源”通常指的是“域名”。它可以防止不同来源之间互相交互,以避免跨站请求伪造等攻击。
CSRF攻击是如何工作的?
浏览器允许网站在客户端计算机上存储信息,以cookie的形式。这些cookie有一些附属信息,例如cookie的名称、创建时间、过期时间和设置cookie的人等。一个cookie看起来像这样:
Cookie: cookiename=chocolate
这是一个巧克力曲奇饼干,应该可以从http://bakery.example
及其所有子域名中访问。
这个cookie可能包含一些敏感数据。在本例中,该数据是... 巧克力
。正如您所看到的那样高度敏感。
因此,浏览器会存储此cookie。每当用户向可访问此cookie的域发出请求时,该cookie将被发送到该域的服务器。服务器很开心。
这是一件好事。对于服务器来说,这是一种非常酷的存储和检索客户端信息的方法。
但问题在于,这使得http://malicious-site.example
可以将这些cookie发送到http://bakery.example
,而用户并不知情!例如,考虑以下场景:
# malicious-site.example/attackpage
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://bakery.example/order/new?deliveryAddress="address of malicious user"');
xhr.send();
如果您访问了恶意网站,且以上代码执行且不存在同源策略,那么恶意用户将代表您下订单并在他自己的地址上收到订单...您可能不喜欢这样。
发生这种情况是因为您的浏览器向 http://bakery.example
发送了您的巧克力 cookie,这使得 http://bakery.example
认为 您 正在 有意地 请求新订单。 但实际上不是这样。
换句话说,这是一种 CSRF 攻击。 跨站点伪造请求:“跨站点请求伪造”。由于同源策略,它不起作用。
同源策略如何解决此问题?
它阻止 malicious-site.example
向其他域发送请求。 简单。
换句话说,浏览器不会允许任何站点向任何其他站点发出请求。 它将通过这些请求防止不同来源之间的交互,如 AJAX。
但是,来自其他主机的资源加载,例如图片、脚本、样式表、iframe、表单提交等不受此限制。 我们需要使用CSRF Tokens来保护我们的面包店免受恶意站点攻击。
CSRF Tokens
正如所述,即使在不违反同源策略的情况下,恶意站点仍然可以执行此类操作:
<img src='http://bakery.example/order/new?deliveryAddress="address of malicious user"'/>
浏览器将尝试从该URL加载图像,导致向该URL发送所有Cookie的GET请求。为了防止这种情况发生,我们需要一些服务器端保护。
基本上,我们将适当熵的随机唯一令牌附加到用户会话中,在服务器上存储它,并将其与表单一起发送到客户端。当提交表单时,客户端会将该令牌与请求一起发送,服务器验证该令牌是否有效。
现在我们已经完成了这个过程,恶意网站再次发送请求将始终失败,因为没有可行的方式让恶意网站知道用户会话的令牌。
CORS
在必要时,可以通过跨站点请求来规避策略。这被称为CORS(Cross Origin Resource Sharing)。
这通过让“域”告诉浏览器放松限制并允许此类请求来实现。这个“告诉”的事情可以通过传递头文件来完成。例如:
Access-Control-Allow-Origin: //comma separated allowed origins list, or just *
因此,如果http://bakery.example
将此标头传递给浏览器,并且创建对http://bakery.example
的请求的页面存在于来源列表中,则浏览器将允许请求进行,并连同cookie一起发送。
按照定义来源的规则进行操作1。例如,对于同一域的不同端口,它们不属于同一来源。因此,如果端口不同,浏览器可能会拒绝此请求。像往常一样,我们亲爱的IE是个例外。IE以相同的方式处理所有端口。这是非标准的,没有其他浏览器会以此方式行事。不要依赖此特性。
JSONP
带填充的JSON只是绕过同源策略的一种方法,当CORS不可用时使用。这是冒险和不良实践。避免使用此方法。
该技术涉及向另一个服务器发出请求,如下所示:
<script src="http://badbakery.example/jsonpurl?callback=cake"></script>
由于同源策略不会阻止这个请求2,所以此请求的响应将会被加载到页面中。
这个URL最可能会响应JSON内容。但是,仅仅在页面上包含该JSON内容是无法帮助的。这肯定会导致错误。因此,http://badbakery.example
接受一个回调参数,并修改JSON数据,将其包装在传递给回调参数的任何内容中。
因此,不要返回,
{ user: "vuln", acc: "B4D455" }
这是无效的JavaScript代码,会抛出错误。如果运行该代码,会返回以下结果:
cake({user: "vuln", acc:"B4D455"});
如果它是有效的JavaScript,它将被执行并根据cake
函数存储在某个位置,以便页面上的其余JavaScript可以使用数据。这主要用于API向其他域发送数据。然而,这是一种不好的做法,会有风险,应该严格避免。
为什么JSONP不好?
首先,它非常有限。如果请求失败,你无法处理任何错误(至少不能以合理的方式)。你不能重试请求等操作。
它还要求你在全局作用域中拥有一个cake
函数,这不是很好。如果您需要使用不同回调执行多个JSONP请求,可能需要临时函数来解决这个问题,但这仍然是一种hackish方式。
最后,你正在向DOM插入随机的JavaScript代码。如果你不能100%确定远程服务将返回安全的cakes,那么你不能依赖它。
参考资料
1. https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy#Definition_of_an_origin
2. https://www.w3.org/Security/wiki/Same_Origin_Policy#Details
其他值得阅读的内容
http://scarybeastsecurity.blogspot.dk/2009/12/generic-cross-browser-cross-domain.html
https://www.rfc-editor.org/rfc/rfc3986(抱歉 :p)
https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy
https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)
deliveryAddress
攻击。一个img
标签就可以工作,除非你首先需要获取CSRF保护令牌。此外,JSONP有什么比使用CORS头更危险的地方吗? - Alexander O'MaraXMLHttpRequest
s。感谢您的反馈! - user3459110