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

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

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

開發(fā)出高性能的 Web 應(yīng)用固然重要,但安全問題也不容小覷。本文我們繼續(xù)以 HTTP 為線索,展開來(lái)講一講瀏覽器安全相關(guān)的同源策略。

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

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

URL 中的源

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

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

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

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

而下面 2 個(gè)網(wǎng)址和示例 URL 都是同源。

https://kaiwu.lagou.com/course/courseInfo.htm?courseId=288#/sale:請(qǐng)求參數(shù)不同。

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

當(dāng)一個(gè)源訪問另一個(gè)源的資源時(shí)就會(huì)產(chǎn)生跨源。同源策略就是用來(lái)限制其中一些跨源訪問的,包括訪問 iframe 中的頁(yè)面、其他頁(yè)面的 cookie 訪問以及發(fā)送 AJAX 請(qǐng)求。最常見的跨源場(chǎng)景是域名不同,即常說(shuō)的“跨域”。本課時(shí)也按照約定俗成的說(shuō)法,用“跨域”來(lái)指代“跨源”。

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

請(qǐng)求跨域解決方案

對(duì)于瀏覽器請(qǐng)求跨域,常用的有下面 4 種方法。

跨域資源共享

跨域資源共享(CORS,Cross-Origin Resource Sharing)是瀏覽器為 AJAX 請(qǐng)求設(shè)置的一種跨域機(jī)制,讓其可以在服務(wù)端允許的情況下進(jìn)行跨域訪問。主要通過 HTTP 響應(yīng)頭來(lái)告訴瀏覽器服務(wù)端是否允許當(dāng)前域的腳本進(jìn)行跨域訪問。

跨域資源共享將 AJAX 請(qǐng)求分成了兩類:簡(jiǎn)單請(qǐng)求和非簡(jiǎn)單請(qǐng)求。其中簡(jiǎn)單請(qǐng)求符合下面 2 個(gè)特征。

請(qǐng)求方法為 GET、POST、HEAD。

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

任意一條要求不符合的即為非簡(jiǎn)單請(qǐng)求。

對(duì)于簡(jiǎn)單請(qǐng)求,處理流程如下:

瀏覽器發(fā)出簡(jiǎn)單請(qǐng)求的時(shí)候,會(huì)在請(qǐng)求頭部增加一個(gè) Origin 字段,對(duì)應(yīng)的值為當(dāng)前請(qǐng)求的源信息;

當(dāng)服務(wù)端收到請(qǐng)求后,會(huì)根據(jù)請(qǐng)求頭字段 Origin 做出判斷后返回相應(yīng)的內(nèi)容。

瀏覽器收到響應(yīng)報(bào)文后會(huì)根據(jù)響應(yīng)頭部字段 Access-Control-Allow-Origin 進(jìn)行判斷,這個(gè)字段值為服務(wù)端允許跨域請(qǐng)求的源,其中通配符“*”表示允許所有跨域請(qǐng)求。如果頭部信息沒有包含 Access-Control-Allow-Origin 字段或者響應(yīng)的頭部字段 Access-Control-Allow-Origin 不允許當(dāng)前源的請(qǐng)求,則會(huì)拋出錯(cuò)誤。

當(dāng)處理非簡(jiǎn)單的請(qǐng)求時(shí),瀏覽器會(huì)先發(fā)出一個(gè)預(yù)檢請(qǐng)求(Preflight)。這個(gè)預(yù)檢請(qǐng)求為 OPTIONS 方法,并且添加了 1 個(gè)請(qǐng)求頭部字段 Access-Control-Request-Method,值為跨域請(qǐng)求所使用的請(qǐng)求方法。

下圖是一個(gè)預(yù)檢請(qǐng)求的請(qǐng)求報(bào)文和響應(yīng)報(bào)文。因?yàn)樘砑恿瞬粚儆谏鲜龊?jiǎn)單請(qǐng)求的頭部字段,所以瀏覽器在請(qǐng)求頭部添加了 Access-Control-Request-Headers 字段,值為跨域請(qǐng)求添加的請(qǐng)求頭部字段 authorization。

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

預(yù)檢請(qǐng)求頭部信息

在服務(wù)端收到預(yù)檢請(qǐng)求后,除了在響應(yīng)頭部添加 Access-Control-Allow-Origin 字段之外,至少還會(huì)添加 Access-Control-Allow-Methods 字段來(lái)告訴瀏覽器服務(wù)端允許的請(qǐng)求方法,并返回 204 狀態(tài)碼。

在上面的例子中,服務(wù)端還根據(jù)瀏覽器的 Access-Control-Request-Headers 字段回應(yīng)了一個(gè) Access-Control-Allow-Headers 字段,來(lái)告訴瀏覽器服務(wù)端允許的請(qǐng)求頭部字段。

瀏覽器得到預(yù)檢請(qǐng)求響應(yīng)的頭部字段之后,會(huì)判斷當(dāng)前請(qǐng)求服務(wù)端是否在服務(wù)端許可范圍之內(nèi),如果在則繼續(xù)發(fā)送跨域請(qǐng)求,反之則直接報(bào)錯(cuò)。

JSONP

JSONP(JSON with Padding)的大概意思就是用 JSON 數(shù)據(jù)來(lái)填充,怎么填充呢?結(jié)合它的實(shí)現(xiàn)方式可以知道,就是把 JSON 數(shù)填充到一個(gè)回調(diào)函數(shù)中。這種比較 hack 的方式,依賴的是 script 標(biāo)簽跨域引用 js 文件不會(huì)受到瀏覽器同源策略的限制。

下面以一個(gè)具體例子來(lái)講解它的具體實(shí)現(xiàn)方式。

假設(shè)我們要在 http://ww.a.com 中向 http://www.b.com 請(qǐng)求數(shù)據(jù)。

1.全局聲明一個(gè)用來(lái)處理返回值的函數(shù) fn,該函數(shù)參數(shù)為請(qǐng)求的返回結(jié)果。

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

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

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

3.創(chuàng)建一個(gè) script 標(biāo)簽,把 URL 賦值給 script 的 src。

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

4.當(dāng)服務(wù)器接收到請(qǐng)求后,解析 URL 參數(shù)并進(jìn)行對(duì)應(yīng)的邏輯處理,得到結(jié)果后將其寫成回調(diào)函數(shù)的形式并返回給瀏覽器。

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

5.在瀏覽器收到請(qǐng)求返回的 js 腳本之后會(huì)立即執(zhí)行文件內(nèi)容,即在控制臺(tái)打印傳入的數(shù)據(jù)內(nèi)容。

JSONP 雖然實(shí)現(xiàn)了跨域請(qǐng)求,但也存在 3 個(gè)問題:

  • 只能發(fā)送 GET 請(qǐng)求,限制了參數(shù)大小和類型;
  • 請(qǐng)求過程無(wú)法終止,導(dǎo)致弱網(wǎng)絡(luò)下處理超時(shí)請(qǐng)求比較麻煩;
  • 無(wú)法捕獲服務(wù)端返回的異常信息。

Websocket

Websocket 是 html5 規(guī)范提出的一個(gè)應(yīng)用層的全雙工協(xié)議,適用于瀏覽器與服務(wù)器進(jìn)行實(shí)時(shí)通信場(chǎng)景。

什么叫全雙工呢?

這是通信傳輸?shù)囊粋€(gè)術(shù)語(yǔ),這里的“工”指的是通信方向,“雙工”是指從客戶端到服務(wù)端,以及從服務(wù)端到客戶端兩個(gè)方向都可以通信,“全”指的是通信雙方可以同時(shí)向?qū)Ψ桨l(fā)送數(shù)據(jù)。與之相對(duì)應(yīng)的還有半雙工和單工,半雙工指的是雙方可以互相向?qū)Ψ桨l(fā)送數(shù)據(jù),但雙方不能同時(shí)發(fā)送,單工則指的是數(shù)據(jù)只能從一方發(fā)送到另一方。

下面是一段簡(jiǎn)單的示例代碼。在 a 網(wǎng)站直接創(chuàng)建一個(gè) WebSocket 連接,連接到 b 網(wǎng)站即可,然后調(diào)用 WebScoket 實(shí)例 ws 的 send() 函數(shù)向服務(wù)端發(fā)送消息,監(jiān)聽實(shí)例 ws 的 onmessage 事件得到響應(yīng)內(nèi)容。

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

代理轉(zhuǎn)發(fā)

跨域是為了突破瀏覽器的同源策略限制,既然同源策略只存在于瀏覽器,那可以換個(gè)思路,在服務(wù)端進(jìn)行跨域,比如設(shè)置代理轉(zhuǎn)發(fā)。這種在服務(wù)端設(shè)置的代理稱為“反向代理”,對(duì)于用戶而言是無(wú)感知的。

另一種在客戶端使用的代理稱為“正向代理”,主要用來(lái)代理客戶端發(fā)送請(qǐng)求,用戶使用時(shí)必須配置代理服務(wù)器的網(wǎng)址,比如常用的 VPN 工具就屬于正向代理。

代理轉(zhuǎn)發(fā)實(shí)現(xiàn)起來(lái)非常簡(jiǎn)單,在當(dāng)前被訪問的服務(wù)器配置一個(gè)請(qǐng)求轉(zhuǎn)發(fā)規(guī)則就行了。

下面的代碼是 webpack-dev-server 配置代理的示例代碼。當(dāng)瀏覽器發(fā)起前綴為 /api 的請(qǐng)求時(shí)都會(huì)被轉(zhuǎn)發(fā)到 http://localhost:3000 這個(gè)網(wǎng)址,然后將響應(yīng)結(jié)果返回給瀏覽器。對(duì)于瀏覽器而言還是請(qǐng)求當(dāng)前網(wǎng)站,但實(shí)際上已經(jīng)被服務(wù)端轉(zhuǎn)發(fā)。

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

在 Nginx 服務(wù)器上配置同樣的轉(zhuǎn)發(fā)規(guī)則也非常簡(jiǎn)單,下面是示例配置。

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

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

頁(yè)面跨域解決方案

除了瀏覽器請(qǐng)求跨域之外,頁(yè)面之間也會(huì)有跨域需求,例如使用 iframe 時(shí)父子頁(yè)面之間進(jìn)行通信。

postMessage

HTML5 推出了一個(gè)新的函數(shù) postMessage() 用來(lái)實(shí)現(xiàn)父子頁(yè)面之間通信,而且不論這兩個(gè)頁(yè)面是否同源。

舉例來(lái)說(shuō),如果父頁(yè)面 https://lagou.com 要向子頁(yè)面 https://kaiwu.lagou.com 發(fā)消息,可以通過下面的代碼實(shí)現(xiàn)。

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

上面的代碼通過 window.open() 函數(shù)打開了子頁(yè)面,然后調(diào)用 child.postMessage() 函數(shù)發(fā)送了字符串?dāng)?shù)據(jù)“hi”給子頁(yè)面。

在子頁(yè)面中,只需要監(jiān)聽“message”事件即可得到父頁(yè)面的數(shù)據(jù)。代碼如下:

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

同樣的,父頁(yè)面也可以監(jiān)聽“message”事件來(lái)接收子頁(yè)面發(fā)送的數(shù)據(jù)。子頁(yè)面發(fā)送數(shù)據(jù)時(shí)則要通過 window.opener 對(duì)象來(lái)調(diào)用 postMessage() 函數(shù)。

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

改域

對(duì)于主域名相同,子域名不同的情況,可以通過修改 document.domain 的值來(lái)進(jìn)行跨域。如果將其設(shè)置為其當(dāng)前域的父域,則這個(gè)較短的父域?qū)⒂糜诤罄m(xù)源檢查。

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

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

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

總結(jié)

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

對(duì)于請(qǐng)求跨域,包括跨域資源共享、JSONP、Websocket、代理轉(zhuǎn)發(fā) 4 種方式,推薦優(yōu)先使用代理轉(zhuǎn)發(fā)和跨域資源共享。對(duì)于頁(yè)面跨域,包括 postMessage 和改域 2 種方式,使用頻率沒有請(qǐng)求跨域那么高,記住 2 種方式實(shí)現(xiàn)原理就好。

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

分享到:
標(biāo)簽:瀏覽器
用戶無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定