同源策略
同源策略(Same Origin Policy, SOP)是Web应用程序的一种安全模型,它控制了网页中DOM之间的访问。
同源三要素:主机
、协议
、端口
同源策略作用
浏览器的同源策略会导致跨域,这里同源策略又分为以下两种:
- DOM同源策略:禁止对不同源页面DOM进行操作。这里主要场景是
iframe
跨域的情况,不同域名的iframe
是限制互相访问的。 XmlHttpRequest
同源策略:禁止使用XHR对象向不同源的服务器地址发起HTTP请求。
同源策略没有禁止脚本的执行,而是禁止读取HTTP回复。
我们会发现,SOP
其实在防止CSRF
上作用非常有限,CSRF
的请求往往在发送出去的那一瞬间就已经达到了攻击的目的,比如发送了一段敏感数据,或请求了一个具体的功能,是否能读取回复并不那么重要(唯一的作用是可以防止CSRF请求读取异源的授权Token)。 另外,一般静态资源通常不受同源策略限制,如js/css/jpg/png
等。
要注意,这里的CSRF
攻击指的是通过链接或者脚本去访问恶意网站的情况,而不是通过ajax
访问的情况,ajax的同源策略正是为了防止CSRF
攻击。
跨源访问
同源策略控制了不同源之间的交互,例如在使用XMLHttpRequest
或 <img>
标签时则会受到同源策略的约束。交互通常分为三类:
跨域写
(Cross-origin writes):通常被允许,例如链接,重定向和表单提交,一些不常见的HTTP
请求方法例如PUT,DELETE
等需要先发送预请求(preflight),例如发送OPTIONS
来查询可用的方法。跨域嵌入
(Cross-origin embedding):通常被允许跨域读
:通常被禁止,然而,我们可以用其他方法达到读取的效果。
以下是一些跨域请求的例子:
<script src="..."></script>
标签嵌入跨域脚本。语法错误信息只能在同源脚本中捕捉到。<link rel="stylesheet" href="...">
标签嵌入CSS。由于CSS的松散的语法规则,CSS的跨域需要一个设置正确的Content-Type
消息头。不同浏览器有不同的限制: IE, Firefox, Chrome, Safari (跳至CVE-2010-0051)部分 和 Opera。<img>
嵌入图片。支持的图片格式包括PNG,JPEG,GIF,BMP,SVG,…<video>
和<audio>
嵌入多媒体资源。<object>
,<embed>
和<applet>
的插件。@font-face
引入的字体。一些浏览器允许跨域字体( cross-origin fonts),一些需要同源字体(same-origin fonts)。<frame>
和<iframe>
载入的任何资源。站点可以使用X-Frame-Options
消息头来阻止这种形式的跨域交互。
一个经久不衰的BUG
早在2011年,一个用户在Mozilla的Bug追踪系统中就提交了一个issue,声称他可以判定某个网站的访客是否登录了gmail,facebook等等。
嵌入iframe来获取一个访问网站的用户是否登陆了gmail:
|
|
src的代码试图访问一张gmail中攻击者上传的图片,如果用户没有登陆gmail,就无法成功加载。从而达到判断用户是否登陆gmail的效果。这种方法可以推广到任何对不应跨源访问的资源没有正确设置同源策略的网站。
跨域的解决方案
document.domain跨子域
常见于不同子域共享数据
如果两个window
或者frames
包含的脚本可以把domain
设置成一样的值,那么就可以规避同源策略,每个window
之间可以互相沟通。例如,orders.example.com
下页面的脚本和catalog.example.com
下页面的脚本可以设置他们的document.domain
属性为example.com
,从而让这两个站点下面的文档看起来像在同源下,然后就可以让每个文档读取另一个文档的属性。
这种方式也不是一直都有用,因为端口号是在内部保存的,有可能被保存成null。换句话说,example.com
的端口号80
,在我们更新document.domain
属性的时候可能会变成null
。为null
的端口可能不被认为是80
,这主要依赖浏览器实现。
# CORS 跨域资源共享
CORS是一个W3C标准,全称是”跨域资源共享”(Cross-origin resource sharing)
这种方式使用了一个新的Origin
请求头和一个新的Access-Control-Allow-Origin
响应头扩展了HTTP
。允许服务端设置Access-Control-Allow-Origin
头标识哪些站点可以请求文件,或者设置Access-Control-Allow-Origin
头为*
,允许任意站点访问文件。浏览器,例如Firefox3.5,Safari4,IE10使用这个头允许跨域HTTP请求。
# jsonp
# 服务器代理
代理是万能的,什么都不影响了
# 使用postMessage实现页面之间通信
信息传递除了客户端与服务器之前的传递,还存在以下几个问题:
- 页面和新开的窗口的数据交互。
- 多窗口之间的数据交互。
- 页面与所嵌套的
iframe
之间的信息传递。
window.postMessage
是一个HTML5的api,允许两个窗口之间进行跨域发送消息。这个应该就是以后解决dom跨域通用方法了,具体可以参照MDN。
#WebSocket
现代浏览器允许脚本直连一个WebSocket地址
而不管同源策略。然而,使用WebSocket URI
的时候,在请求中插入Origin
头就可以标识脚本请求的源。为了确保跨站安全,WebSocket
服务器必须根据允许接受请求的白名单中的源列表比较头数据。
对同源策略的利用
URI解析
IP
是URI
的重要组成部分,如果留心了RFC的人就会知道,IP不止有一种格式。下面的标注形式其实都代表了同一个IP:216.58.209.68
。
|
|
当然,不同浏览器对URI
的解析方式是不一样的,可能并不能正确跳转的google
的页面,但当浏览器URI
解析存在漏洞时,就会有作用。
|
|
设计缺陷导致SOP绕过
在Java6,7中,如果两个域名解析到相同的IP,则会认为他们同源。假设我们有attacker.com和victim.com,两者都共享主机123.123.123.123。攻击者attacker.com可以在自己控制的域名下上传一个jar文件来访问victim.com的内容。
访问本地文件的同源策略
不同的浏览器使用不同的浏览器引擎,而不同的引擎对于同源策略的处理也并非完全一致。
|
|
文件1与2在不同的浏览器引擎中可能认为是同源/非同源
IE的特别之处
TrustZones(信任域):当一个URI被加入到了IE的信任网站区域中时,浏览器会无视同源策略。
IE在考虑同源策略时不包括端口, 这意味着不同端口上的应用程序可以读取到比如用户的登陆账户密码/cookie等。
通过变更自身的源绕过同源策略:
IE 6,7版中网页可以通过document.domain
设置自身的来源为任意其他来源。如今网页仍然可以更改源,但是有一些限制。
网页可以变更自身的源为父级域名。
例如http://malicious.eth.space/1.html
可以通过执行
|
|
来绕过同源策略的限制,从而可以读取http://eth.space/login.html
上的内容。这其中的应用大家可以自己去想。
防御
CORS cross-origin sharing stander 跨源资源共享机制
使用windows.postMessage
使用JSONP
CSP 内容安全策略
禁止(你的资源被)跨源访问
为了禁止跨域写,我们需要引入CSRF令牌
,然而我们需要正确的配置同源策略,否则CSRF令牌本身也将被恶意网页读取。
为了禁止跨域读,我们可以通过设置X-Frame-Options
头来禁止该页面被嵌入到恶意页面中,就如同在“经久不衰的BUG”中一样。
为了禁止跨域嵌入,确保你的资源本身无法嵌入到各种跨域访问方式中,比如<script data-original=></script> <img data-original=x></img>,<svg onload=>
,各种字体加载等等。同时,使用CSRF令牌也可以有效避免被跨域嵌入。