Open Twlig opened 2 years ago
同源策略是浏览器最核心也最基本的安全功能。保证用户信息的安全,防止恶意的网站窃取数据。对于不同源的站点之间的相互请求会做限制。
同源策略需同时满足的三个要求:
http:www.test.com与https:www.test.com 不同源——协议不同 http:www.test.com与http:www.admin.com 不同源——域名不同 http:www.test.com与http:www.test.com:8081 不同源——端口不同
如果非同源,共有三种行为受到限制:
注意:跨域限制仅仅是浏览器的行为,通过代理服务器,或者其他工具发送请求就能轻松绕过
浏览器端 假设我们点击一个按钮去获取数据,获取数据的请求准备从浏览器发出,这时浏览器先会检测这条请求是同源还是跨域,也就是与按钮所在页面的地址是同源还是跨域,如果是同源,好说,直接发送出去;如果是跨域的请求,那就得hold住先,浏览器会在请求的http header中加上一个Origin字段,标明这个请求是从哪里发出来的,例如: Origin:http://neighbour.com:9000/
服务器端 服务器收到请求会给与响应,响应的header里写明跨域的配置信息,告诉浏览器,它允许哪些域名发来的请求访问,哪些method可以执行。浏览器收到响应后自动判断能不能真正执行请求。
跨域流程
浏览器在发送跨域请求的时候会判断一下是简单请求还是非简单请求,简单请求:先执行后判断是否跨域。非简单请求浏览器则会先发送一次OPTIONS预检请求,根据预检请求的结果,决定是否正式发送请求。
简单请求
Content-Type
application/x-www-form-urlencoded
multipart/form-data
text/plain
application/json
非简单请求
除上述简单请求之外都是非简单请求
跨域问题在前端和后端都有解决方案。有以下两点值得注意:
前端解决方案
document.domain + iframe跨域
document.domain
iframe
此方案仅限主域相同,子域不同的跨域应用场景。实现原理:两个页面都通过JS强制设置document.domain为基础主域,就实现了同域。
location.hash + iframe跨域
location.hash
实现原理: a与b跨域相互通信,通过中间页c来实现。 三个页面,不同域之间利用iframe的location.hash传值,相同域之间直接JS访问来通信。
具体实现:A域:a.html -> B域:b.html -> A域:c.html,a与b不同域只能通过hash值单向通信,b与c也不同域也只能单向通信,但c与a同域,所以c可通过parent.parent访问a页面所有对象
parent.parent
window.name + iframe跨域
window.name
window.name属性的独特之处:name值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)
name
通过iframe的src属性由外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。
src
postMessage跨域
postMessage
postMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数不多可以跨域操作的window属性之一,它可用于解决以下方面的问题:
XMLHttpRequest
用法:postMessage(data,origin)方法接受两个参数:
postMessage(data,origin)
JSON.stringify()
动态创建script
script标签不受同源策略的限制
代理服务器
由于同源策略是对浏览器和外域服务器的限制,如果是代理到本地服务器处理,然后由本地服务器与外域服务器通信,再由本地服务器转向浏览器,就可以绕过同源策略。处理的方法有Vue设置代理,或者Nginx,或者后端设置一个代理都可以。
jsonp
jsonp的原理就是利用 Githubissues.
同源策略
同源策略是浏览器最核心也最基本的安全功能。保证用户信息的安全,防止恶意的网站窃取数据。对于不同源的站点之间的相互请求会做限制。
同源策略需同时满足的三个要求:
如果非同源,共有三种行为受到限制:
注意:跨域限制仅仅是浏览器的行为,通过代理服务器,或者其他工具发送请求就能轻松绕过
跨域流程
浏览器端 假设我们点击一个按钮去获取数据,获取数据的请求准备从浏览器发出,这时浏览器先会检测这条请求是同源还是跨域,也就是与按钮所在页面的地址是同源还是跨域,如果是同源,好说,直接发送出去;如果是跨域的请求,那就得hold住先,浏览器会在请求的http header中加上一个Origin字段,标明这个请求是从哪里发出来的,例如: Origin:http://neighbour.com:9000/
服务器端 服务器收到请求会给与响应,响应的header里写明跨域的配置信息,告诉浏览器,它允许哪些域名发来的请求访问,哪些method可以执行。浏览器收到响应后自动判断能不能真正执行请求。
跨域流程
跨域请求类型
浏览器在发送跨域请求的时候会判断一下是简单请求还是非简单请求,简单请求:先执行后判断是否跨域。非简单请求浏览器则会先发送一次OPTIONS预检请求,根据预检请求的结果,决定是否正式发送请求。
简单请求
Content-Type
:只限于三个值application/x-www-form-urlencoded
、multipart/form-data
、text/plain
(没有application/json
, 如果发送JSON格式的body请求数据是一个非简单请求)非简单请求
除上述简单请求之外都是非简单请求
跨域解决方案
跨域问题在前端和后端都有解决方案。有以下两点值得注意:
前端解决方案
document.domain
+iframe
跨域此方案仅限主域相同,子域不同的跨域应用场景。实现原理:两个页面都通过JS强制设置
document.domain
为基础主域,就实现了同域。location.hash
+iframe
跨域实现原理: a与b跨域相互通信,通过中间页c来实现。 三个页面,不同域之间利用iframe的location.hash传值,相同域之间直接JS访问来通信。
具体实现:A域:a.html -> B域:b.html -> A域:c.html,a与b不同域只能通过hash值单向通信,b与c也不同域也只能单向通信,但c与a同域,所以c可通过
parent.parent
访问a页面所有对象window.name
+iframe
跨域window.name
属性的独特之处:name
值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的name
值(2MB)通过
iframe
的src
属性由外域转向本地域,跨域数据即由iframe
的window.name
从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。postMessage
跨域postMessage
是HTML5XMLHttpRequest
Level 2中的API,且是为数不多可以跨域操作的window属性之一,它可用于解决以下方面的问题:用法:
postMessage(data,origin)
方法接受两个参数:JSON.stringify()
序列化。动态创建script
script标签不受同源策略的限制
代理服务器
由于同源策略是对浏览器和外域服务器的限制,如果是代理到本地服务器处理,然后由本地服务器与外域服务器通信,再由本地服务器转向浏览器,就可以绕过同源策略。处理的方法有Vue设置代理,或者Nginx,或者后端设置一个代理都可以。
jsonp
jsonp的原理就是利用 Githubissues.