同源
协议相同 (同为http或https)
域名相同
端口相同
三者之间是与关系
| http://www.example.com/dir/page.html | 原始网址 | | —————————————– | —————- | | http://www.example.com/dir2/other.html | 同源 | | http://example.com/dir/other.html | 不同源(域名不同) | | https://www.example.com/dir/page.html | 不同源(协议不同) | | http://www.example.com:8080/dir/page.html | 不同源(端口不同) |
目的
保证用户信息的安全,防止恶意的网站窃取数据
限制范围
- cookie、LocalStorage、IndexDB
- DOM
- AJAX请求
绕过
cookie
正常情况下只有同源的网页才能共享cookie,比如http://a.example.com/a.html
的cookie在http://b.example.com/b.html
上是拿不到的。但是如果设置相同document.domain
两个页面就能共享cookie
复现不出来
iframe
如果两个网页不同源,就拿不到对方的DOM,例如
跟上面cookie一样,如果设置相同的document.domain
,就能规避同源策略
在b.html
中加入<script>document.domain="0e1.cc"</script>
然而,对于完全不同源的网站,document.domain
也没有办法,所以目前有三种办法来解决
0x00. 片段识别符
片段识别符和之前的部分以#分隔,就是上图fragment
部分,改变片段识别符页面不会刷新,基于这个特性,就可以通过fragment
来传递信息
将b.html
的代码修改为
|
|
对iframe的src进行修改
0x01. windows.name
只要在一个窗口中,window.name
这个属性对所有网页是共享的
将b.html
的代码改为
|
|
window.postMessage
HTML5为了解决跨域通信的问题,引入了跨文档通信API。这个API引入了window.postMessage
方法window.postMessage()
方法可以安全地实现跨域通信
将b.html
的代码改为
|
|
AJAX
根据同源策略,AJAX只能将数据发到同源网站内。但是还是有办法进行跨域
- JSONP
- WebSocket
- CORS
JSONP
主要操作是添加一个<script>
,向服务器请求JSON数据,服务器收到请求后,把数据放到一个指定名字的回调函数里传回来。这种操作不受同源策略限制
a.html
|
|
b.html
|
|
WebSocket
WebSocket是一种通信协议,这个协议不实行同源策略,只要服务器支持,就能进行跨域通信
首先编写一个websocket服务端
|
|
在a.0e1.cc
上向b.test.com
发送websocket连接
CORS
有三类行为类型会触发同源策略
- Cross-Origin read
- Cross-Origin writes
- Cross-Origin embedding
一般情况下Cross-Origin read
是被禁止的,其余两种是允许的。Cross-Origin write
中的重定向、links(<a>
)、表单提交,Cross-Origin embedding
中的资源嵌入,例如<script src="…"></script>
,更多的例子可以查看MDN的文档
虽然能够在标签中使用不同源的资源,但是在标签内,比如<script>
,想要获取外域资源就会收到同源策略的限制。为了解决这个问题,W3C就提出了CORS
CORS(Cross-Origin Resource Sharing)跨域资源分享,是跨域AJAX的根本解决方法,允许任何类型的请求。浏览器一旦发现AJAX请求跨域,就会自动添加一些附加的头信息,有时还会多出一次附加的请求(OPTIONS
)
CORS将请求分为两类simple request和not-so-simple request
区分simple request跟not-so-simple request的方法是,simple request满足以下条件
请求方法是HEAD
、GET
、POST
之一,HTTP的头信息不超出以下几种字段
- Accept
- Accept-Language
- Content-Language
- Content-Type
- DPR
- Downlink
- Save-Data
- Viewport-Width
- Width
- Content-Type:只限于三个值
application/x-www-form-urlencoded
、multipart/form-data
、text/plain
如果是simple request,浏览器会在这次AJAX请求头里添加一个Origin
字段,用来说明本次请求来自哪个源
如果Origin
指定的域名在许可的范围内,服务器返回的响应头里会多出几个字段
例如上图的Access-Control-Allow-Origin
,如果该字段是*
,表示接受任意域名的请求
还有就是Access-Control-Expose-Headers
,CORS请求时,XMLHttpRequest
对象的getResponseHeader()
方法只能拿到6个基本字段:Cache-Control
、Content-Language
、Content-Type
、Expires
、Last-Modified
、Pragma
。如果想拿到其他字段,就必须在Access-Control-Expose-Headers
里面指定
还有就是Access-Control-Allow-Credentials
,如果为true
,表示服务器允许把Cookie
包含在请求中发送给服务器
当设置了Access-Control-Allow-Credentials
,Access-Control-Allow-Origin
就不能为*
对于not-so-simple request,浏览器将会在跨域之前发起一个preflight
请求进行检查,如果检查不通过,那么不会发起跨域请求。
首先会发起一个OPTIONS
请求
这回多了两个头,Access-Control-Request-Method
,列出浏览器的CORS请求用到了哪些方法;Access-Control-Request-Headers
,指定浏览器CORS请求会额外用到哪些头
收到OPTIONS
请求后,服务器检查字段后,允许跨域请求,就会做出回应
Access-Control-Allow-Methods
表示服务器所支持的跨域请求方法
Access-Control-Allow-Headers
表示服务器所支持的头
还有就是Access-Control-Max-Age
,表示这次OPTIONS
请求的有效期
通过浏览器的检查后就可以正常进行跨域请求了
参考
https://www.jianshu.com/p/2c07fbb52b45
http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html
http://www.ruanyifeng.com/blog/2016/04/cors.html