同源策略和Ajax跨域訪問

1. 什麼是同源策略 

    理解跨域首先必需要了解同源策略。同源策略是瀏覽器上爲安全性考慮實施的很是重要的安全策略。
    何謂同源:
        URL由協議、域名、端口和路徑組成,若是兩個URL的協議、域名和端口相同,則表示他們同源。
    同源策略:
        瀏覽器的同源策略,限制了來自不一樣源的"document"或腳本,對當前"document"讀取或設置某些屬性。 
        從一個域上加載的腳本不容許訪問另一個域的文檔屬性。

    舉個例子:
        好比一個惡意網站的頁面經過iframe嵌入了銀行的登陸頁面(兩者不一樣源),若是沒有同源限制,惡意網頁上的javascript腳本就能夠在用戶登陸銀行的時候獲取用戶名和密碼。

    在瀏覽器中,<script>、<img>、<iframe>、<link>等標籤均可以加載跨域資源,而不受同源限制,但瀏覽器限制了JavaScript的權限使其不能讀、寫加載的內容。
    另外同源策略只對網頁的HTML文檔作了限制,對加載的其餘靜態資源如javascript、css、圖片等仍然認爲屬於同源。

    代碼示例(http://localhost:8080/和http://localhost:8081因爲端口不一樣而不一樣源):javascript

 1 http://localhost:8080/test.html  
 2         <html>  
 3             <head><title>test same origin policy</title></head>  
 4             <body>  
 5                 <iframe id="test" src="http://localhost:8081/test2.html"></iframe>  
 6                 <script type="text/javascript">  
 7                     document.getElementById("test").contentDocument.body.innerHTML = "write somthing";  
 8                 </script>  
 9             </body>  
10         </html>  
11   
12 http://localhost:8081/test2.html  
13         <html>  
14             <head><title>test same origin policy</title></head>  
15             <body>  
16                 Testing.  
17             </body>  
18         </html>  

在Firefox中會獲得以下錯誤:
        Error: Permission denied to access property 'body'

    Document對象的domain屬性存放着裝載文檔的服務器的主機名,能夠設置它。
    例如來自"blog.csdn.net"和來自"bbs.csdn.net"的頁面,都將document.domain設置爲"csdn.net",則來自兩個子域名的腳本便可相互訪問。
    出於安全的考慮,不能設置爲其餘主domain,好比http://www.csdn.net/不能設置爲sina.com。php

2. Ajax跨域

    Ajax (XMLHttpRequest)請求受到同源策略的限制。
    Ajax經過XMLHttpRequest可以與遠程的服務器進行信息交互,另外XMLHttpRequest是一個純粹的Javascript對象,這樣的交互過程,是在後臺進行的,用戶不易察覺。
    所以,XMLHTTP實際上已經突破了原有的Javascript的安全限制。
    舉個例子:
        假設某網站引用了其它站點的javascript,這個站點被compromise並在javascript中加入獲取用戶輸入並經過ajax提交給其餘站點,這樣就能夠源源不斷收集信息。
        或者某網站由於存在漏洞致使XSS注入了javascript腳本,這個腳本就能夠經過ajax獲取用戶信息並經過ajax提交給其餘站點,這樣就能夠源源不斷收集信息。
   若是咱們又想利用XMLHTTP的無刷新異步交互能力,又不肯意公然突破Javascript的安全策略,能夠選擇的方案就是給XMLHTTP加上嚴格的同源限制。
   這樣的安全策略,很相似於Applet的安全策略。IFrame的限制還僅僅是不能訪問跨域HTMLDOM中的數據,而XMLHTTP則根本上限制了跨域請求的提交。(實際上下面提到了CORS已經放寬了限制)

   隨着Ajax技術和網絡服務的發展,對跨域的要求也愈來愈強烈。下面介紹Ajax的跨域技術。css

2.1 JSONP

    JSONP技術實際和Ajax沒有關係。咱們知道<script>標籤能夠加載跨域的javascript腳本,而且被加載的腳本和當前文檔屬於同一個域。所以在文檔中能夠調用/訪問腳本中的數據和函數。若是javascript腳本中的數據是動態生成的,那麼只要在文檔中動態建立<script>標籤就能夠實現和服務端的數據交互。
    JSONP就是利用<script>標籤的跨域能力實現跨域數據的訪問,請求動態生成的JavaScript腳本同時帶一個callback函數名做爲參數。其中callback函數本地文檔的JavaScript函數,服務器端動態生成的腳本會產生數據,並在代碼中以產生的數據爲參數調用callback函數。當這段腳本加載到本地文檔時,callback函數就被調用。html

Jsonp原理: 
首先在客戶端註冊一個callback, 而後把callback的名字傳給服務器。
此時,服務器先生成 json 數據。
而後以 javascript 語法的方式,生成一個function , function 名字就是傳遞上來的參數 jsonp.
最後將 json 數據直接以入參的方式,放置到 function 中,這樣就生成了一段 js 語法的文檔,返回給客戶端。
客戶端瀏覽器,解析script標籤,並執行返回的 javascript 文檔,此時數據做爲參數,傳入到了客戶端預先定義好的 callback 函數裏(動態執行回調函數)。java

HTML代碼:jquery

 1 <meta content="text/html; charset=utf-8" http-equiv="Content-Type" />  
 2 <script type="text/javascript">  
 3     function jsonpCallback(result) {   4         for(var i in result) {  
 5             alert(i+":"+result[i]);//循環輸出a:1,b:2,etc.  
 6         }  
 7     }  
 8 </script>  
 9 <script type="text/javascript" src="http://www.xxxx.com/server.php?callback=jsonpCallback"></script> 

將上述JS客戶端代碼用jQuery的方法來實現,也很是簡單。ajax

 $.getJSONjson

$.ajaxapi

$.get跨域

JS代碼(方式1):

 1 <script type="text/javascript" src="jquery.js"></script>  
 2 <script type="text/javascript">  
 3     $.ajax({  
 4         url:"http://crossdomain.com/services.php",  
 5         dataType:'jsonp',  
 6         data:'',  
 7         jsonp:'callback',  
 8         success:function(result) {  
 9             for(var i in result) {  
10                 alert(i+":"+result[i]);//循環輸出a:1,b:2,etc.  
11             }  
12         },  
13         timeout:3000  
14     });  
15 </script>  

JS代碼(方式2):

1 <script type="text/javascript" src="jquery.js"></script>  
2 <script type="text/javascript">  
3     $.getJSON("http://crossdomain.com/services.php?callback=?",  
4     function(result) {  
5         for(var i in result) {  
6             alert(i+":"+result[i]);//循環輸出a:1,b:2,etc.  
7         }  
8     });  
9 </script>  

PHP代碼:server.php

1 <?php  
2 //服務端返回JSON數據  
3 $arr=array('a'=>1,'b'=>2,'c'=>3,'d'=>4,'e'=>5);  
4 $result=json_encode($arr);  
5 //echo $_GET['callback'].'("Hello,World!")';  
6 //echo $_GET['callback']."($result)";  
7 //動態執行回調函數  
8 $callback=$_GET['callback'];  
9 echo $callback."($result)";  

2.2 Proxy 

    使用代理方式跨域更加直接,由於SOP的限制是瀏覽器實現的。若是請求不是從瀏覽器發起的,就不存在跨域問題了。
    使用本方法跨域步驟以下:
    1. 把訪問其它域的請求替換爲本域的請求
    2. 本域的請求是服務器端的動態腳本負責轉發實際的請求
    各類服務器的Reverse Proxy功能均可以很是方便的實現請求的轉發,如Apache httpd + mod_proxy。
    Eg.
    爲了經過Ajax從http://localhost:8080訪問http://localhost:8081/api,能夠將請求發往http://localhost:8080/api。
    而後利用Apache Web服務器的Reverse Proxy功能作以下配置:
        ProxyPass /api http://localhost:8081/api

 

參考:

  https://blog.csdn.net/shimiso/article/details/21830313

  http://justcoding.iteye.com/blog/1366102

相關文章
相關標籤/搜索