日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

開發出高性能的 Web 應用固然重要,但安全問題也不容小覷。本文我們繼續以 HTTP 為線索,展開來講一講瀏覽器安全相關的同源策略。

瀏覽器的同源策略(Same Origin Policy)

源(Origin)是由 URL 中協議、主機名(域名 domain)以及端口共同組成的部分。在下面的網址中,源由協議 https、主機名 kaiwu.lagou.com 和默認端口 443 共同組成。

URL 中的源

如果兩個 URL 的源相同,我們就稱之為同源。下面的 3 個 URL 和示例 URL 都是不同的源。

http://kaiwu.lagou.com/course/courseInfo.htm?courseId=180#/content:協議不同。

https://kaiwu.lagou.com:80/course/courseInfo.htm?courseId=180#/content:端口不同。

https://lagou.com/course/courseInfo.htm?courseId=180#/content:主機名不同。

而下面 2 個網址和示例 URL 都是同源。

https://kaiwu.lagou.com/course/courseInfo.htm?courseId=288#/sale:請求參數不同。

https://kaiwu.lagou.com:URL 路徑不同。

當一個源訪問另一個源的資源時就會產生跨源。同源策略就是用來限制其中一些跨源訪問的,包括訪問 iframe 中的頁面、其他頁面的 cookie 訪問以及發送 AJAX 請求。最常見的跨源場景是域名不同,即常說的“跨域”。本課時也按照約定俗成的說法,用“跨域”來指代“跨源”。

同源策略在保障安全的同時也帶來了不少問題,比如 iframe 中的子頁面與父頁面無法通信,瀏覽器與其他服務端無法交互數據。所以我們需要一些跨域方案來解決這些問題。

請求跨域解決方案

對于瀏覽器請求跨域,常用的有下面 4 種方法。

跨域資源共享

跨域資源共享(CORS,Cross-Origin Resource Sharing)是瀏覽器為 AJAX 請求設置的一種跨域機制,讓其可以在服務端允許的情況下進行跨域訪問。主要通過 HTTP 響應頭來告訴瀏覽器服務端是否允許當前域的腳本進行跨域訪問。

跨域資源共享將 AJAX 請求分成了兩類:簡單請求和非簡單請求。其中簡單請求符合下面 2 個特征。

請求方法為 GET、POST、HEAD。

請求頭只能使用下面的字段:Accept(瀏覽器能夠接受的響應內容類型)、Accept-Language(瀏覽器能夠接受的自然語言列表)、Content-Type (請求對應的類型,只限于 text/plain、multipart/form-data、Application/x-www-form-urlencoded)、Content-Language(瀏覽器希望采用的自然語言)、Save-Data(瀏覽器是否希望減少數據傳輸量)。

任意一條要求不符合的即為非簡單請求。

對于簡單請求,處理流程如下:

瀏覽器發出簡單請求的時候,會在請求頭部增加一個 Origin 字段,對應的值為當前請求的源信息;

當服務端收到請求后,會根據請求頭字段 Origin 做出判斷后返回相應的內容。

瀏覽器收到響應報文后會根據響應頭部字段 Access-Control-Allow-Origin 進行判斷,這個字段值為服務端允許跨域請求的源,其中通配符“*”表示允許所有跨域請求。如果頭部信息沒有包含 Access-Control-Allow-Origin 字段或者響應的頭部字段 Access-Control-Allow-Origin 不允許當前源的請求,則會拋出錯誤。

當處理非簡單的請求時,瀏覽器會先發出一個預檢請求(Preflight)。這個預檢請求為 OPTIONS 方法,并且添加了 1 個請求頭部字段 Access-Control-Request-Method,值為跨域請求所使用的請求方法。

下圖是一個預檢請求的請求報文和響應報文。因為添加了不屬于上述簡單請求的頭部字段,所以瀏覽器在請求頭部添加了 Access-Control-Request-Headers 字段,值為跨域請求添加的請求頭部字段 authorization。

聊聊瀏覽器同源策略與跨域方案詳解

預檢請求頭部信息

在服務端收到預檢請求后,除了在響應頭部添加 Access-Control-Allow-Origin 字段之外,至少還會添加 Access-Control-Allow-Methods 字段來告訴瀏覽器服務端允許的請求方法,并返回 204 狀態碼。

在上面的例子中,服務端還根據瀏覽器的 Access-Control-Request-Headers 字段回應了一個 Access-Control-Allow-Headers 字段,來告訴瀏覽器服務端允許的請求頭部字段。

瀏覽器得到預檢請求響應的頭部字段之后,會判斷當前請求服務端是否在服務端許可范圍之內,如果在則繼續發送跨域請求,反之則直接報錯。

JSONP

JSONP(JSON with Padding)的大概意思就是用 JSON 數據來填充,怎么填充呢?結合它的實現方式可以知道,就是把 JSON 數填充到一個回調函數中。這種比較 hack 的方式,依賴的是 script 標簽跨域引用 js 文件不會受到瀏覽器同源策略的限制。

下面以一個具體例子來講解它的具體實現方式。

假設我們要在 http://ww.a.com 中向 http://www.b.com 請求數據。

1.全局聲明一個用來處理返回值的函數 fn,該函數參數為請求的返回結果。

function fn(result) {
  console.log(result)
}

2.將函數名與其他參數一并寫入 URL 中。

var url = 'http://www.b.com?callback=fn¶ms=...';

3.創建一個 script 標簽,把 URL 賦值給 script 的 src。

var script = document.createElement('script');
script.setAttribute("type","text/JAVAscript");
script.src = url;
document.body.appendChild(script);

4.當服務器接收到請求后,解析 URL 參數并進行對應的邏輯處理,得到結果后將其寫成回調函數的形式并返回給瀏覽器。

fn({
  list: [],
  ...
})

5.在瀏覽器收到請求返回的 js 腳本之后會立即執行文件內容,即在控制臺打印傳入的數據內容。

JSONP 雖然實現了跨域請求,但也存在 3 個問題:

  • 只能發送 GET 請求,限制了參數大小和類型;
  • 請求過程無法終止,導致弱網絡下處理超時請求比較麻煩;
  • 無法捕獲服務端返回的異常信息。

Websocket

Websocket 是 html5 規范提出的一個應用層的全雙工協議,適用于瀏覽器與服務器進行實時通信場景。

什么叫全雙工呢?

這是通信傳輸的一個術語,這里的“工”指的是通信方向,“雙工”是指從客戶端到服務端,以及從服務端到客戶端兩個方向都可以通信,“全”指的是通信雙方可以同時向對方發送數據。與之相對應的還有半雙工和單工,半雙工指的是雙方可以互相向對方發送數據,但雙方不能同時發送,單工則指的是數據只能從一方發送到另一方。

下面是一段簡單的示例代碼。在 a 網站直接創建一個 WebSocket 連接,連接到 b 網站即可,然后調用 WebScoket 實例 ws 的 send() 函數向服務端發送消息,監聽實例 ws 的 onmessage 事件得到響應內容。

var ws = new WebSocket("ws://b.com");
ws.onopen = function(){
  // ws.send(...);
}
ws.onmessage = function(e){
  // console.log(e.data);
}

代理轉發

跨域是為了突破瀏覽器的同源策略限制,既然同源策略只存在于瀏覽器,那可以換個思路,在服務端進行跨域,比如設置代理轉發。這種在服務端設置的代理稱為“反向代理”,對于用戶而言是無感知的。

另一種在客戶端使用的代理稱為“正向代理”,主要用來代理客戶端發送請求,用戶使用時必須配置代理服務器的網址,比如常用的 VPN 工具就屬于正向代理。

代理轉發實現起來非常簡單,在當前被訪問的服務器配置一個請求轉發規則就行了。

下面的代碼是 webpack-dev-server 配置代理的示例代碼。當瀏覽器發起前綴為 /api 的請求時都會被轉發到 http://localhost:3000 這個網址,然后將響應結果返回給瀏覽器。對于瀏覽器而言還是請求當前網站,但實際上已經被服務端轉發。

// webpack.config.js
module.exports = {
  //...
  devServer: {
    proxy: {
      '/api': 'http://localhost:3000'
    }
  }
};

在 Nginx 服務器上配置同樣的轉發規則也非常簡單,下面是示例配置。

location /api {
    proxy_pass   http://localhost:3000;
}

通過 location 指令匹配路徑,然后通過 proxy_pass 指令指向代理地址即可。

頁面跨域解決方案

除了瀏覽器請求跨域之外,頁面之間也會有跨域需求,例如使用 iframe 時父子頁面之間進行通信

postMessage

HTML5 推出了一個新的函數 postMessage() 用來實現父子頁面之間通信,而且不論這兩個頁面是否同源。

舉例來說,如果父頁面 https://lagou.com 要向子頁面 https://kaiwu.lagou.com 發消息,可以通過下面的代碼實現。

// https://lagou.com
var child = window.open('https://kaiwu.lagou.com');
child.postMessage('hi', 'https://kaiwu.lagou.com');

上面的代碼通過 window.open() 函數打開了子頁面,然后調用 child.postMessage() 函數發送了字符串數據“hi”給子頁面。

在子頁面中,只需要監聽“message”事件即可得到父頁面的數據。代碼如下:

// https://kaiwu.lagou.com
window.addEventListener('message', function(e) {
  console.log(e.data);
},false);

同樣的,父頁面也可以監聽“message”事件來接收子頁面發送的數據。子頁面發送數據時則要通過 window.opener 對象來調用 postMessage() 函數。

// https://kaiwu.lagou.com
window.opener.postMessage('hello', 'https://lagou.com');

改域

對于主域名相同,子域名不同的情況,可以通過修改 document.domain 的值來進行跨域。如果將其設置為其當前域的父域,則這個較短的父域將用于后續源檢查。

比如,有一個頁面,它的地址是 https://www.lagou.com/parent.html,在這個頁面里面有一個 iframe,其 src 是 http://kaiwu.lagou.com/child.html。

這時只要把 http://www.lagou.com/parent.html 和 http://kaiwu.lagou.com/child.html 這兩個頁面的 document.domain 都設成相同的域名,那么父子頁面之間就可以進行跨域通信了,同時還可以共享 cookie。

但要注意的是,只能把 document.domain 設置成更高級的父域才有效果,例如在 http://kaiwu.lagou.com/child.html 中可以將 document.domain 設置成 kaiwu.lagou.com。

總結

本文介紹了瀏覽器的同源策略,并分別從請求跨域與頁面跨域兩個方向介紹了幾種常用的跨域方案。

對于請求跨域,包括跨域資源共享、JSONP、Websocket、代理轉發 4 種方式推薦優先使用代理轉發和跨域資源共享。對于頁面跨域,包括 postMessage 和改域 2 種方式,使用頻率沒有請求跨域那么高,記住 2 種方式實現原理就好。

最后留一道思考題:說一說你還知道瀏覽器的哪些安全策略?

分享到:
標簽:瀏覽器
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定