跨源限制
在瀏覽器裏
對源(url協議,主機名,端口號)不一樣的通訊進行限制,在web領域 爲了確保安全,只有同源的通訊才能被容許進行,稱爲同源策略
雖然能夠在html裏使用iframe以實如今一個頁面中同時顯示來自不一樣域的文檔,不過js仍然只能訪問同一源的文檔
若是文檔的url和iframe的不一樣,則沒法經過文檔中包含的js對iframe內的dom進行操做,而iframe內的js也沒法操做文檔裏的dom
若是不這樣 ,就會發生諸如不一樣域的cookie可以互相訪問等安全問題javascript
對於XMLHttpRequest來講,同源策略的含義是,一個XMLHttpRequest對象只能發送至一個特定的服務器,即提供了使用該XMLHttpRequest對象的文檔下載服務器
跨源通訊php
js裏的跨源通訊
JSONP
iframe攻擊
window.postMessage()
XMLHttpRequest level 2css
1.JSONP
利用script標籤的src將其它域的js文件載入,若是在此處動態建立script標籤的話,就能實現對其它域中數據的動態讀取
不過僅僅是取得了數據,還沒法在客戶端使用。所以產生jsonp(json with padding ,padding指向json數據中添加函數名)
服務端會對數據添加函數名後返回
代碼示例html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <script src="//cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script> </head> <body> <script> var url="http://b.cn/do.php?callback=foo"; //注意 foo函數的定義要先於 引入 url裏的內容 function foo(res){ console.log(res); console.log(res.a); } function loadData(url){ var elem=document.createElement('script'); elem.src=url; document.getElementsByTagName('head')[0].appendChild(elem); } loadData(url); </script> </body> </html>
b.cn/do.phpjava
<?php $arr=['a'=>'ajax','b'=>'bbc']; $callback=$_GET['callback']; $json=$callback."(".json_encode($arr).");"; echo $json; //foo({"a":"ajax","b":"bbc"}); ?>
請求的內容是執行代碼的內容,在客戶端是定義聲明部分
jsonp的缺點
沒法在post請求類型中使用
只能作到動態建立script標籤並讀取數據而沒法從客戶端發出數據jquery
2. XMLHttpRequest level 2
XMLHttpRequest沒法跨源通訊
在XMLHttpRequest level2中 只要服務器端許可就能夠實現web
a.cn/a.htmlajax
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <script src="//cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script> </head> <body> <div class="btn" style="cursor: pointer;text-align:center;width: 100px;height: 50px;line-height:50px;color:white;background: green">click</div> <script> $(function(){ $(".btn").click(function(){ var xhr=new XMLHttpRequest(); xhr.onreadystatechange=function(){ var state=xhr.readyState; if(state==4){ console.log(xhr.getAllResponseHeaders()); } } xhr.open('GET','http://b.cn/do.php?a=1&b=2'); xhr.withCredentials=true; //默認不發送cookie的,當設個參數設置爲true服務端 Access-Control-Allow-Origin 必須明確指定 不可爲* 並且必須設置 header('Access-Control-Allow-Credentials:true'); xhr.setRequestHeader("content-type",'multipart/form-data'); // xhr.setRequestHeader("content-type",'application/x-www-form-urlencoded'); xhr.send('p1=1'); }); }); </script> </body> </html>
http://b.cn/do.php
代碼
<?php header('Access-Control-Allow-Origin:http://a.cn'); header('Access-Control-Allow-Credentials:true'); header('Access-Control-Allow-Methods:POST'); var_dump($_POST); var_dump($_GET); var_dump(file_get_contents("php://input")); var_dump($_COOKIE);
關於跨源發送cookie 算法
xhr.withCredentials=true; json
這裏跨源指的是 跨的二級的域,根域必須相同,並且cookie的域必須是根域
好比 a.a.cn能夠經過這裏所說的跨源 在向b.a.cn發送ajax請求時 帶上 .a.cn下的cookie
不要覺得 域在.a.cn下的cookie ,a.a.cn在向b.a.cn發請求時 會自動帶上
也不要認爲cookie的跨源能跨根域,是不可能的
3.postMessage()
window.postMessage
是一個安全的跨源通訊的方法。通常狀況下,當且僅當執行腳本的頁面使用相同的協議(一般都是 http)、相同的端口(http默認使用80端口)和相同的 host(兩個頁面的document.domain 的值相同)時,才容許不一樣頁面上的腳本互相訪問。 window.postMessage
提供了一個可控的機制來安全地繞過這一限制,當其在正確使用的狀況下。
調用 window.postMessage時,
將分發一個
MessageEvent
事件到目標窗口, 在全部掛起必須執行的腳本完成後. (例如:當一個事件處理程序調用window.postMessage時,仍剩餘事件處理程序, 先前的掛起等待超時等)。MessageEvent 有消息類型,它被設置爲第一個參數值提供給window.postMessage的data屬性,
對應的window調用window.postMessage的時候,window.postMessage主文檔的來源的origin屬性被稱爲源屬性,指哪一個調用window.postMessage的窗口。 (事件的其餘標準屬性都存在與對應的預期值。)
otherWindow.postMessage(message, targetOrigin);
otherWindow
message
targetOrigin
經過窗口的origin屬性來指定哪些窗口能接收到消息事件,其值能夠是字符串"*"(表示無限制)或者一個URI。在發送消息的時候,若是目標窗口的協議、主機地址或端口這三者的任意一項不匹配targetOrigin提供的值,那麼消息就不會被髮送;只有三者徹底匹配,消息纔會被髮送。這個機制用來控制消息能夠發送到哪些窗口;例如,當用
postMessage傳送密碼時,這個參數就顯得尤其重要,必須保證它的值與這條包含密碼的信息的預期接受者的orign屬性徹底一致,來防止密碼被惡意的第三方截獲。若是你明確的知道消息應該發送到哪一個窗口,那麼請始終提供一個有確切值的targetOrigin,而不是*。不提供確切的目標將致使數據泄露到任何對數據感興趣的惡意站點
。
a.cn/a.html
<!DOCTYPE html> <html> <head> <title>Post Message</title> </head> <body> <div style="width:200px; float:left; margin-right:200px;border:solid 1px #333;"> <div id="color">Frame Color</div> </div> <div> <iframe id="child" src="http://b.cn/b.html"></iframe> </div> <script type="text/javascript"> window.onload=function(){ window.frames[0].postMessage('getcolor','http://b.cn'); } window.addEventListener('message',function(e){ console.log('a:',e); var color=e.data; document.getElementById('color').style.backgroundColor=color; },false); </script> </body> </html>
b.cn/b.html
<!doctype html> <html> <head> <style type="text/css"> html,body{ height:100%; margin:0px; } </style> </head> <body style="height:100%;"> <div id="container" onclick="changeColor();" style="widht:100%; height:100%; background-color:rgb(204, 102, 0);"> click to change color </div> <script type="text/javascript"> var container=document.getElementById('container'); window.addEventListener('message',function(e){ if(e.source!=window.parent) return; var color=container.style.backgroundColor; window.parent.postMessage(color,'*'); },false); function changeColor () { var color=container.style.backgroundColor; if(color=='rgb(204, 102, 0)'){ color='rgb(204, 204, 0)'; }else{ color='rgb(204,102,0)'; } container.style.backgroundColor=color; window.parent.postMessage(color,'*'); } </script> </body> </html>