背景
同源策略(Same Origin Policy)是用来抵御一些跨源的会话访问。假如有一个用户在打开一个银行系统页面后,没有退出登录,之后他又打开一个带有恶意的js代码的网页,这些js代码可以直接访问银行网页。因为用户在银行页面没有退出登录,js代码就可以为所欲为,直接冒充用户进行一些系统操作。
银行系统当然是希望用户访问的其他页面的恶意代码,不能访问银行系统的会话的一些信息,比如cookie和一些放在请求头的授权信息。
所以同源策略的提出,就是为了防止这样的代码能够跨源来访问服务器,但是同源策略只拒绝读请求,对于写请求是没有阻止的,所以也就容易产生大量的写请求的CSRF攻击。
源的规则
源(Origin)是由(协议,域名,端口)三元组组成的,也就是说,只要其中之一不相同,就认为是不同源的,假设有一个URL为 huangzhian.tech/blog/origin…
对比URL | 结果 | 原因 |
---|---|---|
huangzhian.tech/blog/cross.… | 同源 | 协议、域名、端口相同 |
huangzhian.tech/blog/origin… | 跨源 | 协议不同 |
huangzhian.com/blog/origin… | 跨源 | 域名不同 |
huangzhian.tech:8081/blog/origin… | 跨源 | 端口不同 |
放宽同源策略限制
对某些情况,同源策略过于严格,比如对于使用#的片段标识符,或者使用window.name的,它们会在不同域之间交换数据,主流浏览器提供一下几种方式放宽同源策略:
Data tainting(不好翻译,叫数据污点)
以前的Netscape浏览器,它的导航栏里有一个taint检查特性,这个特性默认是关闭的,如果打开了,那么浏览器就会允许js去读取跨源的windows和frames属性。
document.domain属性
document.domain的概念是Netscape浏览器的一部分,是把两个windows(或frames)的domain设置成一样,比如脚本从huangzhian.tech和huangzhian.com加载,并把两个页面的document.domain设置成huangzhian.tech,那么它们之间就可以相互访问彼此的属性。
Cross-Origin Resource Sharing(CORS)
CORS应该是最常用的一种方式,它允许服务器在响应头带上Access-Control-Allow-Origin,这是个origin列表,表示允许这些网页跨源访问。Firefox 3.5, Safari 4 和Internet Explorer 10通过拿到响应头后,就可以根据这些,使用XMLHttpRequest来达到跨源访问服务器。
简单来说,当浏览器知道origin不一样的情况下,浏览器会在请求头带上origin,询问服务器是否允许跨源访问,如果服务器在响应头没有返回Access-Control-Allow-Origin,或者返回的Access-Control-Allow-Origin没有跨源的origin,请求就不会被允许。只有服务器返回了origin或者Access-Control-Allow-Origin为*时,请求才会被允许。
Cross-document messaging
cross-document messaging允许一个脚本给另外一个脚本传递文本消息,它通过window对象的postMessage()函数异步发送一个"onmessage"事件,只要用户定了事件处理器,收到这个事件后都会被触发执行。两个跨源页面还是不能直接访问彼此页面的方法和变量,但是可以通过消息来通信。
JSONP
在网页上添加
WebSockets
如果使用的是WebSocket通信,主流浏览器会直接允许跨源访问。但是浏览器识别到当前使用的是WebSocket,就会在请求头插入Origin,表示当前脚本的源,但是为了保证安全性,WebSocket服务器必须比较Origin,看看是否允许响应。也就是说,浏览器不会拦你,但会让服务器来判断是否允许继续通信。