跨域通訊

在工做的一段時間裏,給我最大的感觸就是:公司有很是多的子系統,並且子系統與子系統之間交互很是的頻繁,雖然公司擁有封裝了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的盛行。那麼怎麼去繞過瀏覽器的同源策略呢?下面我會講在實際應用中比較經常使用的繞過同源策略的方式,這些方式會分爲:客戶端技術和服務端技術。但這兩種方式的本質就是利用同源策略的一個漏洞(同源策略雖然限制了客戶端的資源,但對靜態的資源文件是沒有加以限制的)和瀏覽器中不能直接來跨域訪問,而在服務器端沒有跨域安全限制(能夠在服務端完成跨域訪問,而在客戶端來取得結果)。客戶端技術利用的是前者,而服務端技術利用的是後者。

  客戶端技術

  1. iframe + document.domain(僅適用於子域之間,例如bbs.pclady.com.cn和www.pclady.com.cn) 
  2. iframe(其原理:在iframe加載新頁面時,window.name的值是保持不變的,由此能夠重定向iframe的引用地址,由外域轉到本域) -> JQuery的window.name插件(封裝了iframe的實現) -- 支持post請求
  3. 動態Script標籤->Jsonp -> JQuery的$.getScript(弊端只支持get請求,沒有差錯控制機制)
  4. HTML5 postMessage(須要現代的瀏覽器才兼容,像以前的ie6不兼容)
  5. Flash + crossdomain跨域(須要用戶安裝flash,在互聯網應用裏用戶體驗很差)

一、動態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>
View Code

二、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 */
View Code

三、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跨域
Iframe實現post跨域

四、5因爲用得很少,在這裏就不詳細解釋了!詳細可查看http://book.51cto.com/art/200903/113178.htm

  服務端技術

  1. 正向代理:與瀏覽器原理同樣
  2. 反向代理:利用apache server或者nginx等Http服務器進行對url進行重寫
  3. HttpClient: 模擬Http請求(經過HttpClient對其它域發出HTTP請求,只要不經過瀏覽器就不會有同源策略的限制)

在那麼多處理方式中,固然每種方式都有它們的優缺點,當咱們去選擇這些方式的時候,咱們應該如下面幾個方面去考慮。

  一、本身是否能夠操做其它域的服務端的資源

  二、請求的方式是get仍是post

  三、跨域通訊的方式(跨域通訊有2種:本域和子域通訊本域和其它域通訊)

5、繞過同源策略引起的問題

  在避免同源策略時會向惡意用戶露出攻擊面,當惡意代碼被插入 Web 應用程序中時當前的應用程序也易於受到攻擊。遺憾的是,惡意代碼進入 Web 應用程序的方法多種多樣。使咱們防不勝防。兩種比較常見的的XSS(反射式與存儲式)和CSRF,有興趣的能夠具體去了解一下!

6、其它同源策略

   Cookie 同源策略:Cookie中的同源只關注域名,忽略協議和端口。因此https://localhost:8080/和http://localhost:8081/的Cookie是共享的。

相關文章
相關標籤/搜索