同源策略、跨域、jsonp

1.什么是同源策略

1.要了解同源策略,我們必須先知道源即orgin

  • 以百度頁面為例,谷歌瀏覽器打開控制臺:輸入location.origin可得到百度的源
Y`S2F{Q{FHNK0K(FFAL)48V.png
  • 源包括協議版本,域名,端口號。如https://www.baidu.com/,它的協議版本是https,域名為www.baidu,com,默認的端口為443,所以可以省略,類似的還有http協議的默認端口為80,ftp(文本傳輸協議)的默認端口為21
  • 當知道的源以后,就很容易理解同源策略,即只有源相同(域名、協議、端口相同)的客戶端腳本才可以讀寫對方的資源,反之,不同客戶端的腳本不能在沒有明確授權的情況下讀寫對方的資源。舉例如下:
  1. 如:http://a.com/a.htmlhttp://b.com/a.html
    二者的域名不相同,不同源,不能讀取對方的數據
  2. 如:https://a.com/b.htmlhttp://a.com/b.html
    二者協議版本不一樣,不同源,不能讀寫對方的數據
  3. 如:http://a.com/b.htmlhttp://a.com:80/b.html
    前置省略了默認端口號80,但二者是同源,同時文件路徑是否相同和同源無關,所以二者可以讀寫雙方的數據
  • 同源的目的:同源政策的目的,是為了保證用戶信息的安全,防止惡意的網站竊取數據。
    設想這樣一種情況:A網站是一家銀行,用戶登錄以后,又去瀏覽其他網站。如果其他網站可以讀取A網站的 Cookie,會發生什么?
    很顯然,如果 Cookie 包含隱私(比如存款總額),這些信息就會泄漏。更可怕的是,Cookie 往往用來保存用戶的登錄狀態,如果用戶沒有退出登錄,其他網站就可以冒充用戶,為所欲為。因為瀏覽器同時還規定,提交表單不受同源政策的限制。
    由此可見,"同源政策"是必需的,否則 Cookie 可以共享,互聯網就毫無安全可言了。
  • 非同源而限制的三種行為:
  1. Cookie、LocalStorage 和 IndexDB 無法讀取
  2. DOM 無法獲得。
  3. AJAX 請求不能發送。

2.什么是跨域?跨域有幾種實現形式?

  • JavaScript出于安全方面的考慮,不允許跨域調用其他頁面的對象。但在安全限制的同時也給注入iframe或是ajax應用上帶來了不少麻煩。這里把涉及到跨域的一些問題簡單地整理一下:
    首先什么是跨域,簡單地理解就是因為JavaScript同源策略的限制,a.com 域名下的js無法操作b.com或是c.a.com域名下的對象。更詳細的說明可以看下表:
1.png
  • 跨域就是利用某種方法來突破同源策略的限制,實現獲取對方的資源的目的
  • 跨域的實現方式主要有五種:
  1. 降域:即雙方域名不相同,但同時綁定到某個主域名下,通過設置document.domain+iframe。具體的做法是可以在http://www.a.com/a.htmlhttp://script.a.com/b.html兩個文件中分別加上document.domain = ‘a.com’;然后通過a.html文件中創建一個iframe,去控制iframe的contentDocument,這樣兩個js文件之間就可以“交互”了。當然這種辦法只能解決主域相同而二級域名不同的情況,
    某一頁面的domain默認等于window.location.hostname。主域名是不帶www的域名,例如a.com,主域名前面帶前綴的通常都為二級域名或多級域名,例如www.a.com其實是二級域名。 domain只能設置為主域名,不可以在b.a.com中將domain設置為c.a.com
  2. JSONP:全稱為 JSON with padding ,其實質就是動態的創建script標簽來實現跨域,它是基于script可以相互引用,即雖然瀏覽器默認禁止了跨域訪問,但并不禁止在頁面中引用其他域的JS文件,并可以自由執行引入的JS文件中的function(包括操作cookie、Dom等等)。根據這一點,可以方便地通過創建script節點的方法來實現完全跨域的通信。
    3.CORS:Cross-origin resource sharing(全稱是"跨域資源共享"),它允許它允許瀏覽器向跨源服務器,發出XMLHttpRequest請求,從而克服了AJAX只能同源使用的限制。
  3. 使用HTML5 postMessage:HTML5中最酷的新功能之一就是 跨文檔消息傳輸Cross Document Messaging。下一代瀏覽器都將支持這個功能:Chrome 2.0+、Internet Explorer 8.0+, Firefox 3.0+, Opera 9.6+, 和 Safari 4.0+ 。 Facebook已經使用了這個功能,用postMessage支持基于web的實時消息傳遞。
  4. 其他:利用iframe和location.hash和window.name實現的跨域數據傳輸等

3.jsonp 的原理是什么?

就是利用<script>標簽沒有跨域限制的“漏洞”(歷史遺跡啊)來達到與第三方通訊的目的。當需要通訊時,本站腳本創建一個<script>元素,地址指向第三方的API網址,形如: <script src="http://www.example.net/api?param1=1&param2=2"></script> 并提供一個回調函數來接收數據(函數名可約定,或通過地址參數傳遞)。 第三方產生的響應為json數據的包裝(故稱之為jsonp,即json padding),形如: callback({"name":"hax","gender":"Male"})這樣瀏覽器會調用callback函數,并傳遞解析后json對象作為參數。本站腳本可在callback函數里處理所傳入的數據。

  • JSONP的安全隱患
    (1)任意網站只要通過jsonp方式就可以跨域訪問目標域名下的信息,解決辦法:在跨域請求數據時在參數中加上與目標域名約定好的一個token變量,這樣其他網站訪問該域名時,目的網站通過辨認這個約定好的信息而決定是否可以被跨域訪問。
    (2)不能用post方法獲取數據,由于基于src地址引用方式,在地址中附帶參數信息,因此只能用get方式獲取信息
    (3)callback方法由于是根據用戶需求自己實現的,可能會被惡意注入腳本,獲取隱私信息。
  • 參考資料:知乎-JSONP 的工作原理是什么?

4.CORS是什么

  1. CORS是一個W3C標準,全稱是"跨域資源共享"(Cross-origin resource sharing),CORS定義一種跨域訪問的機制,可以讓AJAX實現跨域訪問。CORS 允許一個域上的網絡應用向另一個域提交跨域 AJAX 請求。實現此功能非常簡單,只需由服務器發送一個響應標頭即可。
  2. CORS 的兼容性,CORS需要瀏覽器和服務器同時支持。目前,所有瀏覽器都支持該功能,IE瀏覽器不能低于IE10。因此,實現CORS通信的關鍵是服務器。只要服務器實現了CORS接口,就可以跨源通信。
  3. CORS 的請求分為兩類:簡單請求(simple request)和非簡單請求(not-so-simple request)。以簡單請求為例
  • 滿足以下條件就屬于簡單請求:
    1.請求方法為:HEAD,GET,POST
    2.HTTP的頭部信息為以下字段:
    Accept / Accept-Language / Content-Language / Last-Event-ID/Content-Type(只限于三個值application/x-www-form-urlencoded、multipart/form-data、text/plain)
  • 凡是不同時滿足上面兩個條件,就屬于非簡單請求。
  • 簡單請求的基本流程
    1.當你使用 XMLHttpRequest 發送請求時,瀏覽器發現該請求不符合同源策略,會給該請求加一個請求頭: Origin
    2.后臺進行一系列處理,如果確定接受請求則在返回結果中加入一個響應頭: Access-Control-Allow-Origin ;
  1. 瀏覽器判斷該相應頭中是否包含 Origin 的值,如果有則瀏覽器會處理響應,我們就可以拿到響應數據,如果不包含瀏覽器直接駁回,這時我們無法拿到響應數據
  • 例子:
    假設我們頁面或者應用已在 http://www.test1.com 上了,而我們打算從 http://www.test2.com 請求提取數據。一般情況下,如果我們直接使用 AJAX 來請求將會失敗。利用 CORS,http://www.test2.com 只需添加一個標頭,就可以允許來自 http://www.test1.com 的請求,下圖是我在PHP中的 hander() 設置,”號表示允許任何域向我們的服務端提交請求
    header("Access-Control-Allow-Origin:
    "); //*表示允許任何域向我們的服務端提交需求

    header("Access-Control-Allow-Origin:http://www.test1.com") //這樣就允許來自http://www.test1.com的需求了
    

通過在HTTP Header中加入擴展字段,服務器在相應網頁頭部加入字段表示允許訪問的domain和HTTP method客戶端檢查自己的域是否在允許列表中,決定是否處理響應。
服務器端在HTTP的響應頭中加入(頁面層次的控制模式):
Access-Control-Allow-Origin: example.com
Access-Control-Request-Method: GET, POST
Access-Control-Allow-Headers: Content-Type, Authorization, Accept, Range, Origin
Access-Control-Expose-Headers: Content-Range Access-Control-Max-Age: 3600
多個域名之間用逗號分隔,表示對所示域名提供跨域訪問權限。”*”表示允許所有域名的跨域訪問。

練習

1.本地搭建服務器,演示同源策略

      一. 本地搭建服務器(如果使用 SAE 可創建不同的代碼版本,這樣可通過      
      1.xxx.sinapp.com和2.xxx.sinapp.com 訪問了)
      2. 修改 本地host,通過不同域名訪問本地服務器。比如訪問http://a.com/index.html, http://b.com/ajax.php,本質是
      3. 在 index.html 里使用 ajax 接口訪問 http://b.com/ajax.php 里的數據。
      4. 查看輸出報錯
  • 卡在這一關很久了,因為一直不懂,現在又點懂了,老師視頻上用的node.js不會,所用用了本地PHP軟件測試
  • 1.第一步,打開host 文件,直接可在 win+r 在運行了,輸入它的地址 Windows/System32/drivers/etc ,即可找到,如圖;

![FUD_4]4@(373R({WX}6AM2G.png](http://upload-images.jianshu.io/upload_images/3361706-0ed330d1d707587b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

  • 2.直接用編輯器或記事本打開即可,若是發現host里面是空白,那是因為殺毒軟件360,qq管家剛剛修復過,所以是空的,里面加上這段代碼就行了

      # Copyright (c) 1993-1999 Microsoft Corp.
      #
      # This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
      #
      # This file contains the mappings of IP addresses to host names. Each
      # entry should be kept on an individual line. The IP address should
      # be placed in the first column followed by the corresponding host name.
      # The IP address and the host name should be separated by at least one
      # space.
      #
      # Additionally, comments (such as these) may be inserted on individual
      # lines or following the machine name denoted by a '#' symbol.
      #
      # For example:
      #
      #      102.54.94.97           rhino.acme.com          # source server
      #       38.25.63.10     x.acme.com              # x client host
    
  • 第三步,給本地默認IP 127.0.0.1 綁定 兩個域名,用于測試


    1.png.png
  • 第四步,在www.a.com/index.html ,通過ajax給www.b.com/test-1.php 發送請求
    以下是index.html 的代碼

        <!DOCTYPE html>
      <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>index</title>
    </head>
    <body>
      <script src="http://apps.bdimg.com/libs/jquery/1.9.1/jquery.js"></script>
      <script type="text/javascript">
      $.ajax({
          url:'http://www.b.wang.com/test-1.php',
          type:'get',
          dataType:'json',
          data:{
              username:'xiaoming',
              sex:'man'
          },
          success:function(data){
              alert(data)
          },
          error:function(){
              alert('出錯')
          }
      })
    </script>
      </body>
    </html>
    

以下是 www.b.wang.com的test-1.php的代碼
<?php
$data='獲取數據成功';
echo json_encode($data);
?>

  • 第五步,查看結果,分析原因,如圖:


    2.png

    ajax請求發送失敗,查看控制臺顯示:


    F}C[HBV8QG(OGH{N]DVBO8C.png

2.解決同源策略的限制

1.CORS,未來跨域方法的趨勢,使用ajax十分簡單,安全性高,但是兼容不好,至少要IE10以上,但是隨著時代進步,早晚是CORS的天下。

  • 具體方式:在www.b.wang.com/test-1.php中添header("Access-Control-Allow-Origin: http://www.a.wang.com");
    即允許來自源www.a.wang.com的請求;

    <?php 
      header("Access-Control-Allow-    Origin: http://www.a.wang.com");
      $data='獲取數據成功';
      echo json_encode($data);
     ?>
    
  • 結果成功的獲取到www.b.wang.com下的test-1.php的數據,如圖:

{~O$$3}E(`F}1IIYV{SZ}@I.png
  1. jsonp,利用動態的script便簽的創建獲取到數據
    index.html的代碼如下:
    <script type="text/javascript">
    function jsonp(data){
    alert(data)
    }
    var script=document.createElement('script');
    script.src='http://www.b.wang.com/test-1.php?callback=abc';
    document.body.insertBefore(script,document.body.firstChild);

     </script>
    

test-1.php 代碼如下:
jsonp('123456789');

  • 結果如圖:成功獲取到了數據:
E`RS(0E4)4E2YOUEDXRJ)4Y.png

版權和饑人谷和作者所有,若需轉載請注明出處

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,345評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,494評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,283評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,953評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,714評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,410評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,940評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,776評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,210評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,654評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內容