同源策略保护了什么、如何规避同源限制
同源策略保护了什么、如何规避同源限制
基本照抄阮一峰的博客:浏览器同源政策及其规避方法
同源策略是一个重要的安全策略,它用于限制一个origin的文档或者它加载的脚本如何能与另一个源的资源进行交互。它帮助阻隔恶意文档,减少可能被攻击的媒介。
例如cookie窃取,如果没有同源策略,当用户从网站a退出,进入另一个网站b时,网站b可能就拿到了用户在网站a中存储的cookie,泄露了用户的信息或伪装成用户向网站a的后端发送请求。
同源的要求:协议、域名、端口号相同
要求同源的场景:
如果不同源,以下三种行为会受到限制:
- Cookie、localStorage、IndexDB 无法读取
- DOM 无法获得
- AJAX 请求不能发送
规避限制的方法
-
cookie
若两个网页一级域名相同,只是二级域名不同,浏览器允许通过设置document.domain共享Cookie
举例:网页A:http://w1.example.com/a.html,网页B:http://w2.example.com/b.html
只要A设置document.domain = 'example.com'B就可以共享cookie,比如 即某子域名设置成一级域名,其余二级三级域名都可以共享这个子域名的cookie
网页A设置一个cookie:document.cookie = 'test1=hello'
网页B就可以读到这个cookie:var allCookie = document.cookie
这种方法只适用于cookie和iframe窗口,localStorage和IndexDB无法通过这种方式规避同源策略,而是要使用PostMessage API。
另外,服务器也可以在设置cookie的时候,指定cookie的所属域名为一级域名,比如.example.com。
Set-Cookie: key=value; domain=.example.com; path=/
这样的话,二级域名和三级域名不需要做任何设置,都可以读取这个cookie -
iframe
-
片段标识符
-
window.name
父窗口打开一个子窗口,载入一个不同源的网页,该网页将信息写入子窗口的window.name属性中,子窗口跳转到一个和主窗口同源的网址:location = 'http://parent.url.com/xxx.html,然后主窗口读取子窗口的window.name属性
优点是:window.name容量很大,可以放置很长的字符串。
缺点是:必须监听子窗口window.name属性的变化,影响网页性能。 -
window.postMessage HTML5新特性
跨文档通信 API (Cross-document messaging)
这个API为window对象添加了一个window.postMessage方法,允许跨窗口通信,不论这两个窗口是否同源。
例如,父窗口http://aaa.com向子窗口http://bbb.com发送消息,调用postMessage方法就可以了。var popup = window.open('http://bbb.com', 'title') popup.postMessage('Hello World!', 'http://bbb.com')该方法第一个参数是具体的信息内容,第二个参数是接收消息的窗口的源,也可以设为
*表示不限制域名,向所有窗口发出子窗口向父窗口发送消息的写法类似:
window.opener.postMessage('Nice to meet you', 'http://aaa.com')父窗口和子窗口都可以通过监听
message事件来获取对方的消息window.addEventListener('message', function (e) {console.log() }, false)message事件的事件对象event,提供以下三个属性。- event.source 发送消息的窗口
- event.origin 消息所来自的网址
- event.data 消息内容
子窗口通过
event.source属性引用父窗口,然后发送消息。window.addEventListener('message', receiveMessage) function receiveMessage(event) {event.source.postMessage('Nice to see you!', '*') }event.origin属性可以过滤不是发送给本窗口的消息window.addEventListener('message', receiveMessage) function receiveMessage(event) {if (event.origin !== 'http://aaa.com') return;if (event.data === 'Hello World') {event.source.postMessage('Hello', event.origin)} else {console.log(event.data)} } -
localStorage
通过
window.postMessage,读写其他窗口的localStorage也成为了可能下面是一个主窗口写入iframe子窗口的localStorage的例子window.onmessage = function (e) {if (e.origin !== 'http://bbb.com') {return;}var payload = JSON.parse(e.target)localStorage.setItem(payload.key, JSON.stringify(payload.data)) }父窗口发送消息的代码如下:
var win = document.getElementByTagName('iframe')[0].contentWindow; var obj = { name: 'Jack' } win.postMessage(JSON.stringify({key: 'storage', data: obj}), 'http://bbb.com')加强版的子窗口接收消息的代码如下:
window.onmessage = function (e) {if (e.origin !== 'http://bbb.com') return;var payload = JSON.parse(e.target)switch (payload.method) {case 'set':localStorage.setItem(payload.key, JSON.stringify(payload.data));break;case 'get':var parent = window.parentvar data = localStorage.getItem(payload.key)parent.postMessage(data, 'http://aaa.com')break;case 'remove':localStorage.removeItem(payload.key)break;} }加强版的父窗口发送消息代码如下:
var win = document.getElementByTagName('iframe')[0].contentWindow; var obj = { name: 'Jack' };win.postMessage(JSON.stringify({key: 'storage', method: 'set', data: obj}), 'http://bbb.com'); win.postMessage(JSON.stringify({key: 'storage', method: 'get'}), '*') window.onmessage = function (e) {if (e.origin !== 'http://aaa.com') return;console.log(JSON.parse(e.data).name) }基本思路为:
父窗口打开一个子窗口,并返回出了一个窗口对象(可调用此api的也可能是一个其他窗口的引用),用这个窗口对象给这个子窗口自身发送一个消息,目标域填写子窗口的域
子窗口获取到父窗口的引用(
window.parent),然后用这个引用给父窗口自身发送消息,目标域填写父窗口的。
-
-
AJAX规避跨域的三种方式(之后补充
- JSONP
- WebSocket
- CORS
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
