在工做的一段時間裏,給我最大的感觸就是:公司有很是多的子系統,並且子系統與子系統之間交互很是的頻繁,雖然公司擁有封裝了HttpClient及增長了路由功能的R系統(該系統目的就是知足現下系統與系統之間通訊頻繁的問題),可是你們都知道HttpClient只限於服務器端使用,當咱們想用客戶端腳本,好比Javascript來調用其餘系統(不一樣域)的接口時,就會出現跨域通訊的問題。那麼爲何會出現跨域通訊問題呢?當遇到跨域通訊問題時,咱們又有幾種解決方案呢?另外,跨域通訊又會引起哪些潛在的問題呢?下面我將慢慢解釋這幾個問題。javascript
1、產生跨域通訊問題的本質緣由php
"無規矩不成方圓",這句話你們都知道,當咱們在互聯網的浪潮中衝浪的時候,咱們無需考慮任何安全問題。由於互聯網爲了網民的安全,定製了不少策略(規矩),有一種策略叫同源策略,是每一種瀏覽器都必須實現並遵照的!那麼同源策略到底限制了什麼呢?css
同源策略規定:不一樣域的客戶端腳本在沒有明確受權的狀況下,不能讀寫對方的資源(比如你不能碰別人的女友同樣),這裏有幾個關鍵字頗有必要解釋一下。html
一、域、子域、同域java
所謂同域(源)指:當A域與B域具備相同的協議、域名、端口時稱爲同域(源)node
二、客戶端腳本:由瀏覽器解釋和執行的腳本語言,好比現下流行的Javascript,ActionScript,以前流行的VBScript nginx
三、受權:服務端能夠對客戶端的訪問進行受權,那麼客戶端也能夠受權,好比HTML5中新標準中,當目標站點返回HTTP響應頭Access-Control-Allow-Origin:http://www.cnblogs.com(A),那麼瀏覽器就容許A站點去訪問目標站點。 apache
四、讀寫權限:Web上的資源不少,好比HTTP請求頭的Referer只讀,cookie便可寫亦可讀json
五、資源:資源是個普遍的概念,只要是數據均可以認爲是資源。同源策略裏的資源特指Web客戶端的資源(HTTP頭,DOM樹..)api
在這裏特別要注意的是,同源策略雖然限制了客戶端的資源,但對靜態的資源文件是沒有加以限制的,例如客戶端腳本文件,樣式CSS文件、圖片,flash資源等靜態文件。(<script src=""><img src=""> <link rel=""><iframe src="">),但若是A域的js,想修改B域的dom元素也會形成跨域問題(2014.4.28補充)
2、爲何須要同源策略限制
咱們舉例說明:好比一個黑客程序,他利用iframe把真正的銀行登陸頁面嵌到他的頁面上,當你使用真實的用戶名,密碼登陸時,他的頁面就能夠經過Javascript讀取到你的表單中input中的內容,這樣用戶名,密碼就輕鬆到手了。若是沒有該策略的限制,後果可想而知。
3、同源策略的應用場景
前面介紹了同源策略的規定其存在的價值,那麼瀏覽器的同源策略究竟在哪些場景會起做用呢?下面的三種場景是比較常見的!
一、窗口與窗口(不一樣域)之間的交互
二、iframe嵌入了不一樣域的資源(瀏覽器並不限制iframe嵌入不一樣域的資源,但限制客戶端腳本去訪問)
三、AJax應用(異步),請求不一樣域的資源
4、繞過同源策略解決跨域通訊的方式
互聯網的發展催生了跨域通訊的需求,各類跨域方法和協議知足了需求但也增長了各類風險(風險下面會講)。尤爲是如今mashup的盛行。那麼怎麼去繞過瀏覽器的同源策略呢?下面我會講在實際應用中比較經常使用的繞過同源策略的方式,這些方式會分爲:客戶端技術和服務端技術。但這兩種方式的本質就是利用同源策略的一個漏洞(同源策略雖然限制了客戶端的資源,但對靜態的資源文件是沒有加以限制的)和瀏覽器中不能直接來跨域訪問,而在服務器端沒有跨域安全限制(能夠在服務端完成跨域訪問,而在客戶端來取得結果)。客戶端技術利用的是前者,而服務端技術利用的是後者。
客戶端技術
一、動態Script標籤,返回的數據格式必須是text/javascript(並不是必定是JSON,能夠是任何數據類型),跨域通訊盛行以後,慢慢就產生了JSONP的概念(就是將動態插入Script標籤的技術美稱爲JSONP,但網上卻有一大堆關於JSONP的解釋,簡直是誤導衆生啊!)
1 <html> 2 <head> 3 <title>How Many Pictures Of Madonna Do We Have?</title> 4 <script type="text/javascript"> 5 // 回調函數 6 function ws_results(obj) 7 { 8 // obj的格式能夠是任意數據類型,好比JSON,字符串,xml 9 // 咱們只須要相應的解析便可 10 // 服務器端的返回格式必定得是這樣 ws_results(obj); 11 alert(obj.ResultSet.totalResultsAvailable); 12 } 13 14 function onClick() 15 { 16 var script = document.createElement("script"); 17 script.type = "text/javascript"; 18 script.src = "http://search.yahooapis.com/ImageSearchService/V1/imageSearch?appid=YahooDemo&query=Madonna&output=json&callback=ws_results"; 19 document.body.appendChild(script); 20 } 21 </script> 22 </head> 23 <body> 24 <input type="button" value="click me!" onclick="onClick()"> 25 </body> 26 </html>
二、Iframe+document.domain
1 /* 2 對於主域相同而子域不一樣的例子,能夠經過設置document.domain的辦法來解決。具體的作法是能夠在http://www.a.com/a.html和http://script.a.com/b.html兩個文件中分別加上document.domain = ‘a.com’;而後經過a.html文件中建立一個iframe,去控制iframe的contentDocument,這樣兩個js文件之間就能夠「交互」了。固然這種辦法只能解決主域相同而二級域名不一樣的狀況,若是你異想天開的把script.a.com的domian設爲alibaba.com那顯然是會報錯地! 3 */代碼以下: 4 www.a.com上的a.html 5 document.domain = 'a.com'; 6 var ifr = document.createElement('iframe'); 7 ifr.src = 'http://script.a.com/b.html'; 8 ifr.style.display = 'none'; 9 document.body.appendChild(ifr); 10 ifr.onload = function(){ 11 var doc = ifr.contentDocument || ifr.contentWindow.document; 12 // 在這裏操縱b.html 13 alert(doc.getElementsByTagName("h1")[0].childNodes[0].nodeValue); 14 }; 15 16 script.a.com上的b.html 17 document.domain = 'a.com'; 18 /* 19 這種方式適用於{www.kuqin.com, kuqin.com, script.kuqin.com, css.kuqin.com}中的任何頁面相互通訊。 20 備註:某一頁面的domain默認等於window.location.hostname。主域名是不帶www的域名,例如a.com,主域名前面帶前綴的一般都爲二級域名或多級域名,例如www.a.com實際上是二級域名。 domain只能設置爲主域名,不能夠在b.a.com中將domain設置爲c.a.com。 21 這種方式的缺陷: 22 一、安全性,當一個站點(b.a.com)被攻擊後,另外一個站點(c.a.com)會引發安全漏洞。 23 二、若是一個頁面中引入多個iframe,要想可以操做全部iframe,必須都得設置相同domain。 24 */
三、Iframe->window.name 詳情可查看http://www.cnblogs.com/rainman/archive/2011/02/21/1960044.html
1 <html> 2 <head> 3 <title>ddd</title> 4 </head> 5 <body> 6 <script type="text/javascript"> 7 function check() 8 { 9 var btn = document.getElementById("test_submit"); 10 var frm = document.forms["test_form"]; 11 var ifm = document.getElementById("test_iframe"); 12 frm.action = "http://xxx.xxx.xxx/post.php"; 13 frm.target = "test_iframe"; 14 frm.submit(); 15 btn.disabled = "disabled"; 16 ifm.onload = function(){ 17 btn.disabled = ""; 18 var str = ifm.contentWindow; 19 alert(str.document.body.innerHTML); 20 ifm.src = "about:blank"; 21 ifm.onload = null; 22 } 23 return false; 24 25 } 26 27 </script> 28 <form id="test_form" name="test_form" > 29 <input type="hidden" name="content" value="xxx" /> 30 <input type="submit" name="test_submit" id="test_submit" /> 31 </form> 32 <iframe id="test_iframe" name="test_iframe" width="1" height="1" style="display:none"></iframe> 33 </body> 34 </html> 35 36 Iframe實現post跨域
四、5因爲用得很少,在這裏就不詳細解釋了!詳細可查看http://book.51cto.com/art/200903/113178.htm
服務端技術
在那麼多處理方式中,固然每種方式都有它們的優缺點,當咱們去選擇這些方式的時候,咱們應該如下面幾個方面去考慮。
一、本身是否能夠操做其它域的服務端的資源
二、請求的方式是get仍是post
三、跨域通訊的方式(跨域通訊有2種:本域和子域通訊和本域和其它域通訊)
5、繞過同源策略引起的問題
在避免同源策略時會向惡意用戶露出攻擊面,當惡意代碼被插入 Web 應用程序中時當前的應用程序也易於受到攻擊。遺憾的是,惡意代碼進入 Web 應用程序的方法多種多樣。使咱們防不勝防。兩種比較常見的的XSS(反射式與存儲式)和CSRF,有興趣的能夠具體去了解一下!
6、其它同源策略
Cookie 同源策略:Cookie中的同源只關注域名,忽略協議和端口。因此https://localhost:8080/和http://localhost:8081/的Cookie是共享的。