我真的是在瞎逼逼,因為光是 HTTP妒挎,就足夠講一塊磚頭了绳锅。而且,HTTP 只是協(xié)議棧的應(yīng)用層的其中一個協(xié)議:)酝掩,不過其他協(xié)議都不在本文討論范圍之內(nèi)鳞芙。如有疏漏,請指正期虾。
概述:HTTP vs HTTPS vs HTTP/2 vs SSL vs TLS:這些都是啥子跟啥子原朝?
很多縮寫詞被用于描述客戶端與服務(wù)器端交流的過程。這些詞經(jīng)常被不熟悉內(nèi)部原理的人混淆镶苞。
HTTP (Hypertext Transfer Protocol) 是客戶端和服務(wù)器端都必須實現(xiàn)的基本交流協(xié)議竿拆。它涉及到請求 (requests),響應(yīng) (responses)宾尚,會話 (sessions),緩存 (caching)谢澈,認(rèn)證 (* authentication) 以及更多煌贴。在這個協(xié)議以及 HTML (Hypertext Markup Language*) 上的工作,開始于 1989 年锥忿,由在 CERN 的 Sir Tim Berners-Lee 和他的團(tuán)隊主持牛郑。這個協(xié)議的第一個官方版本 (HTTP 1.0) 發(fā)布于 1996 年,隨后在 1997 年發(fā)布了現(xiàn)在廣泛使用的版本 (HTTP 1.1)敬鬓。
這個協(xié)議在瀏覽器和服務(wù)器間傳輸明文 (clear) 信息淹朋,允許通過傳輸信息的網(wǎng)絡(luò)查看傳輸?shù)男畔Ⅲ细鳌_@會產(chǎn)生安全的擔(dān)憂,所以 HTTP Secure (HTTPS) 被引入了础芍。HTTPS 允許客戶端和服務(wù)器端先建立一個加密的通道杈抢,然后通過這個通道傳輸明文信息,有效地防止了信息的竊聽仑性。
加密通道是通過 Transport Layer Security (TLS) 協(xié)議創(chuàng)建的惶楼,這個協(xié)議以前叫 Secure Socket Layer (SSL)。這兩個術(shù)語經(jīng)痴锔耍互換著使用歼捐。SSL 3.0 正在被 TLS 1.0 替代。SSL 是 Netscape 開發(fā)的協(xié)議晨汹,而 TLS 是一個 IETF 標(biāo)準(zhǔn)豹储。在寫這篇文章的時候,所有版本的 SSL (1.0, 2.0, 3.0) 都由于許多的安全問題而被廢棄淘这,使用它們將會在現(xiàn)代瀏覽器中產(chǎn)生警告剥扣,TLS 版本 (1.0, 1.1, 1.2) 正在使用中,1.3 版本現(xiàn)在還是草案慨灭。
所以朦乏,在大約 1996 或 1997 的某個時間,我們有了互聯(lián)網(wǎng)的當(dāng)前穩(wěn)定版本 (有或者沒有 SSL/TLS 的 HTTP 1.1)氧骤,這個 HTTP 版本仍然驅(qū)動著現(xiàn)在絕大多數(shù)網(wǎng)站呻疹。以前,HTTP 用于非敏感通信筹陵,比如閱讀新聞刽锤,而 HTTPS 用于敏感通信,比如認(rèn)證和電子商務(wù)朦佩。然而并思,對隱私權(quán)的關(guān)注不斷增加,一些瀏覽器如 Google Chrome 現(xiàn)在會標(biāo)記 HTTP 網(wǎng)站 為 “not private”语稠,將在未來針對 HTTP 引入警告宋彼。
HTTP 協(xié)議的下一代升級版 —— HTTP/2,于 2015 年發(fā)布仙畦,正在被越來越多的網(wǎng)站所采納输涕。這個協(xié)議增加了新的特色,如 壓縮 (compression)慨畸,多路復(fù)用 (multiplexing)莱坎,請求優(yōu)先級 (prioritization of requests)等,用于減少等待時間寸士、提升性能和安全性檐什。
在 HTTP 1.1 版本碴卧,安全連接是可選的,你可以使用 HTTP 或 HTTPS乃正,但在 HTTP/2住册,安全連接幾乎是強(qiáng)制的,即使標(biāo)準(zhǔn)定義了有 TLS 的 HTTP/2 和沒有 TLS 的 HTTP/2烫葬,但大部分瀏覽器提供商已經(jīng)聲明它們將只支持擁有 TLS 的 HTTP/2界弧。
HTTP
HTTP 的基本性質(zhì)
簡單
HTTP 的消息被設(shè)計為簡單可讀。這一點只要你打開瀏覽器控制臺看看請求和響應(yīng)頭就知道了搭综。
可擴(kuò)展
除了規(guī)范規(guī)定的那些 header垢箕,我們會看到很多非官方規(guī)定的 header,這些擴(kuò)展的 header 可以用來實現(xiàn)新的功能兑巾。
無狀態(tài)
這意味著即使你對服務(wù)器發(fā)起過一次請求条获,當(dāng)你再發(fā)起一次請求時,服務(wù)器也不知道你拜訪過它蒋歌,基本的 HTTP 請求中是不含狀態(tài)信息的帅掘。所幸我們可以增加 cookie 的頭部擴(kuò)展來記錄狀態(tài)信息。
使用可靠連接
HTTP 依賴于運輸層的 TCP 協(xié)議進(jìn)行消息傳遞堂油,而 TCP 是可靠的修档。
狀態(tài)碼
狀態(tài)碼的第一個數(shù)字代表當(dāng)前響應(yīng)類型
- 1xx - 信息,請求已被服務(wù)器接收府框,繼續(xù)處理
- 2xx - 成功吱窝,請求已成功被服務(wù)器接收、理解迫靖、并接受
- 3xx - 重定向院峡,需要后續(xù)操作才能完成這一請求
- 4xx - 客戶端錯誤,請求含有詞法錯誤或者無法被執(zhí)行
- 5xx - 服務(wù)器端錯誤系宜,服務(wù)器在處理某個正確請求時發(fā)生錯誤
HTTP 的請求方法
較少用的方法
- OPTIONS:請求服務(wù)器告知其支持的各種功能照激。可以詢問服務(wù)器通常支持哪些方法盹牧,或者對某些特殊資源支持哪些方法
- HEAD:向服務(wù)器發(fā)出指定資源的請求俩垃,但服務(wù)器在響應(yīng)中只返回首部,不會返回實體的主體即資源的 body 部分
- PUT:向服務(wù)器寫入資源
- DELETE:請服務(wù)器刪除請求 URL 所指定的資源
- TRACE:HTTP 請求在傳輸?shù)倪^程中是可能會被修改的汰寓。這個方法允許客戶端在最終將請求發(fā)送給服務(wù)器時吆寨,看看它變成了什么樣子。主要用于測試或診斷
- CONNECT:這個方法將請求的連接轉(zhuǎn)換為透明的 TCP/IP 隧道踩寇,通常用于加快基于 SSL 加密的通信
- PATCH:這個方法請求對資源進(jìn)行局部修改
常用方法
GET && POST
GET 是最常用的方法,用于請求服務(wù)器發(fā)送某個資源六水。POST 方法用于向服務(wù)器發(fā)送數(shù)據(jù)俺孙,注意這和 PUT 的寫入資源是不同的辣卒,寫入的資源是存儲在服務(wù)器的,而發(fā)送的數(shù)據(jù)會發(fā)送到其他地方去處理睛榄,這可能會導(dǎo)致新資源的創(chuàng)建或已存在資源的更新荣茫,POST 通常用于支持 HTML 表單。
這兩個方法有什么區(qū)別场靴?
冪等
在數(shù)學(xué)中啡莉,冪等有兩種主要含義:
- 在某二元運算下,冪等元素是指被自己重復(fù)運算的結(jié)果等于它自己的元素旨剥。例如 0 * 0 仍然為 0咧欣,所以 0 在乘法下是冪等的。
- 某一元運算為冪等的時轨帜,其作用在任一元素兩次后會和其作用一次的結(jié)果相同魄咕,例如 恒等函數(shù)
f(x) = x
就是冪等的。在計算機(jī)網(wǎng)絡(luò)中蚌父,假如在不考慮諸如錯誤或者過期等問題的情況下哮兰,若干次請求的副作用與單次請求相同或者根本沒有副作用,那么這些請求方法就能夠被視作是“冪等”的苟弛。
我們知道喝滞,GET 用于表單數(shù)據(jù)提交時,表單數(shù)據(jù)會被編碼在請求的 URI 上膏秫,這樣極不安全右遭,因為請求的地址可能在情趣到達(dá)目的地之前被打印,然后被第三方看到荔睹。而 POST 提交的數(shù)據(jù)是放在請求體中的狸演,比 GET 提交數(shù)據(jù)安全,當(dāng)然僻他,沒有 HTTPS宵距,POST 提交的數(shù)據(jù)也能被看到。
但是最主要的區(qū)別吨拗,應(yīng)該為如下三點:
安全性(safe): GET 請求是安全的满哪,這里的安全是指 GET 方法只獲取信息而不做其他操作。而 POST 請求則是不安全的劝篷,因為它會更新或創(chuàng)建資源哨鸭。
冪等性(idempotent): GET 請求是冪等的,冪等就是上面所說的若干次請求的副作用與單次請求相同娇妓,而 POST 請求則是不冪等的像鸡。
可緩存性(cacheable): GET 請求的響應(yīng)是可緩存的,POST 請求的響應(yīng)一般是不可緩存的哈恰,除非設(shè)置了合適的 Cache-Control 或 Expires 頭部字段只估。
HTTPS
為什么優(yōu)先要使用 HTTPS志群?
有三個主要原因:
- 機(jī)密性 (Confidentiality)
這能保護(hù)通信的雙方在公共媒介中免遭信息竊聽。如果沒有 HTTPS蛔钙,當(dāng)你通過 WiFi 接入點網(wǎng)上購物時锌云,WiFi 接入點的運營者就能看到你的信用卡之類的隱私信息。
- 數(shù)據(jù)完整性 (Integrity)
這能保證信息能不受改變地完整到達(dá)目的地吁脱。比如桑涎,WiFi 可以在我們的網(wǎng)站上增加廣告,降低圖片質(zhì)量或者改變文章的內(nèi)容兼贡。HTTPS 能確保網(wǎng)站不被更改攻冷。
- 身份驗證 (Authentication)
這能保證網(wǎng)站不會是假冒的,域名是哪個紧显,站點就是哪個讲衫。比如,一些運行 WiFi 接入點的猥瑣之人可以把瀏覽器導(dǎo)向一些假冒的網(wǎng)站孵班。HTTPS 能確保example.com
就是真的example.com
涉兽,有些安全證書甚至要檢查網(wǎng)站的合法身份,讓你知道yourbank.com
是YourBank, Inc
篙程,即 YourBank 公司枷畏。
使用 HTTP 頭部字段保護(hù)你的 web 應(yīng)用
禁用秘密信息的緩存
瀏覽器默認(rèn)緩存 HTTP 的 GET 請求的響應(yīng),如果使用的是共享個人電腦 (網(wǎng)吧不就是么虱饿?)拥诡,那么猥瑣之人就能通過訪問瀏覽器的緩存得到他人的隱私信息。所以我們要在返回隱私信息時使用三個響應(yīng)頭字段來禁用客戶端的緩存:
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
cache-control 字段用來指定在這次的請求/響應(yīng)鏈中的所有緩存機(jī)制都必須遵守的指令氮发。上面的三個指令告訴客戶端和代理在使用緩存前必須送請求到服務(wù)器進(jìn)行驗證渴肉,不要儲存響應(yīng),在請求發(fā)生之后的 0 秒后緩存即過期爽冕,在使用緩存的響應(yīng)前檢查其狀態(tài)并禁止使用過期的響應(yīng)仇祭。Pragma: no-cache
這個字段用于向后兼容 HTTP 1.0,確保老客戶端能不緩存響應(yīng)颈畸。Expires: -1
這個字段用于指定響應(yīng)過期的時間戳乌奇。指定為-1
的話,客戶端就會立即把響應(yīng)當(dāng)做過期的眯娱,這就避免了緩存礁苗。
請在需要保護(hù)隱私時才禁用緩存,否則你的應(yīng)用加載速度將大打折扣徙缴。
強(qiáng)制 HTTPS
HTTPS 的重要性我在前面已經(jīng)說了试伙,要強(qiáng)制 HTTPS,我們要使用 HTTP Strict Transport Security (HSTS) 頭部字段,具體可以設(shè)置為Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
迁霎。
max-age
是指示瀏覽器為當(dāng)前域名緩存這個頭部字段指定秒數(shù)吱抚,這里是緩存一年。includeSubDomains
指示瀏覽器將 HSTS 應(yīng)用于當(dāng)前域名的所有子域名考廉。preload
強(qiáng)制瀏覽器總是安全地加載你的 web 應(yīng)用,甚至在你第一次訪問網(wǎng)站且未收到響應(yīng)前携御,這個特性是通過將一個安全預(yù)加載的域名的列表硬編碼到瀏覽器代碼中實現(xiàn)的昌粤,要使用這個特性你需要在 HSTS Preload List Submission 注冊你的域名,當(dāng)然啦啄刹,使用這個指令你得確保你的應(yīng)用能只使用 HTTPS涮坐。
允許 XSS 過濾
XSS 即跨站腳本攻擊,是很普遍也很簡單的網(wǎng)絡(luò)攻擊手法誓军。我們會使用X-XSS-Protection: 1; mode=block
袱讹,X-XSS-Protection這個字段指示瀏覽器是否為當(dāng)前頁面開啟瀏覽器內(nèi)建的 XSS 過濾機(jī)制并覆蓋瀏覽器本身的相關(guān)設(shè)置。1
表示允許過濾器昵时,反之為0
捷雕,mode=block
指示瀏覽器在檢測到 XSS 攻擊后禁止加載整個頁面。
控制 Framing
一個 iframe 是一個可以允許在一個父 web 應(yīng)用中嵌套一個 web 應(yīng)用的 DOM 元素壹甥。這個元素可以讓點擊劫持 (* clickjacking) 更容易救巷。點擊劫持可以欺騙用戶點擊非用戶本意的東西。為了阻止這種攻擊句柠,我們使用X-Frame-Options: SAMEORIGIN
浦译,X-Frame-Options*這個字段指示瀏覽器是否允許你的 web 應(yīng)用嵌套在另一個 web 應(yīng)用中,SAMEORIGIN 表示你的應(yīng)用可以在同域名頁面的 frame 中展示溯职。注意當(dāng)在 Content-Security-Policy 字段中指定了 frame-ancestors 時精盅,則 X-Frame-Options 被忽略,見 這里谜酒。
明確白名單
CSP (Content Security Policy) 定義了一個非常強(qiáng)大的基于瀏覽器的安全機(jī)制叹俏,允許對你的 web 應(yīng)用中的資源加載和腳本執(zhí)行加以控制。有了它甚带,你可以將允許腳本加載她肯、ajax 調(diào)用、圖片和樣式表加載的域列入白名單鹰贵,可以允許或禁止內(nèi)聯(lián)腳本和動態(tài)腳本等晴氨。我們可以通過簡單設(shè)置Content-Security-Policy: script-src 'self'
來允許同源的腳本加載以及阻止動態(tài)腳本和內(nèi)聯(lián)腳本執(zhí)行。Content-Security-Policy 是個比較復(fù)雜的頭部字段碉输,詳細(xì)的配置可以在這里看到籽前。
阻止 Content-Type 嗅探
為了使用戶體驗更連貫,很多瀏覽器實現(xiàn)了一個叫 “Content-Type 嗅探” 或 “MIME 嗅探” 的功能,這個功能使瀏覽器能通過實際資源的比特位檢測 HTTP 中響應(yīng)資源的類型而不理會響應(yīng)頭中的Content-Type
字段聲明的資源類型枝哄。但這會導(dǎo)致 MIME 混淆攻擊 (MIME confusion attack)肄梨。于是乎,我們要使用X-Content-Type-Options: nosniff
挠锥,指示瀏覽器在處理獲取的資源時不要使用嗅探众羡。
HTTP/2
多數(shù)主流瀏覽器已經(jīng)在2015年底支持了該協(xié)議。此外蓖租,根據(jù) W3Techs 的數(shù)據(jù)粱侣,在2017年5月,在排名前一千萬的網(wǎng)站中蓖宦,有13.7% 支持了HTTP/2齐婴。這真真是極吼滴!有圖有真相稠茂。
HTTP/2 相比 HTTP 1.x 的主要區(qū)別
是二進(jìn)制的而非文本的
有別于 HTTP/1.1 中的明文請求柠偶,HTTP/2 將一個 TCP 連接分為若干個流 (stream),每個流中可以傳輸若干消息 (message)睬关,每個消息由若干最小的二進(jìn)制幀 (frame) 組成诱担。這樣更利于高效地解析,而且不容易出錯共螺,畢竟 HTTP/1.x 的 header 中有空白行该肴、大小寫、換行藐不、空行之類的規(guī)定匀哄。
是完全多路復(fù)用而非按順序和阻塞的
HTTP/1.x 有一個 head-of-line blocking 的問題,它會讓一個連接一次只能發(fā)送一個請求雏蛮。多路復(fù)用允許多個請求和響應(yīng)消息同時發(fā)出涎嚼,甚至可以混合一個消息的一部分和另一個消息。
只開一個連接用于并發(fā)的請求
HTTP/1.x 中為了加載資源會同時打開多個 TCP 連接挑秉,每個連接在響應(yīng)時又都會發(fā)送大量數(shù)據(jù)法梯,存在中間網(wǎng)絡(luò) (intervening network) 緩沖區(qū)溢出的危險,導(dǎo)致網(wǎng)絡(luò)阻塞和重發(fā) (* retransmits*)犀概。而且立哑,使用那么多的 TCP 連接也是一種大量占用網(wǎng)絡(luò)資源的行為。
壓縮頭部
在大型網(wǎng)站中姻灶,一個頁面往往要請求大量資源并得到相應(yīng)铛绰,算上那些往返的話,那么頭部就會占據(jù)相當(dāng)大的開銷产喉,所以壓縮頭部的好處便變得顯而易見了捂掰。
允許服務(wù)器主動推送資源給客戶端
在 HTTP/1.x 中敢会,當(dāng)瀏覽器請求了一個頁面,服務(wù)器發(fā)送了 HTML 頁面的響應(yīng)这嚣,然后服務(wù)器需要等待瀏覽器解析了 HTML 文件后再發(fā)起嵌入在 HTML 頁面中的多個資源的請求鸥昏,想想都覺得慢。而服務(wù)器端推送避免了這種往返的延遲姐帚,服務(wù)器會主動推送它認(rèn)為的客戶端會需要緩存的資源吏垮。要小心的是,這個功能濫用的話罐旗,會損害性能惫皱。
如何擁抱 HTTP/2?
HTTP/2 是向后兼容 HTTP/1.1 的尤莺,所以完全不需要擔(dān)心現(xiàn)有的網(wǎng)站會發(fā)生什么問題。然而生棍,很多對于 HTTP/1.1 來說是最佳實踐的技巧卻會在使用 HTTP/2 時降低性能颤霎。再者,從 HTTP/1.1 轉(zhuǎn)向 HTTP/2 勢必是漫長的涂滴,因為服務(wù)器端升級容易友酱,但只要一日絕大多數(shù)人仍然使用著老舊甚至是史前瀏覽器,客戶端就會是扎心窩的痛柔纵。我們需要做些過渡時期的事缔杉。
轉(zhuǎn)向 TLS
第一要務(wù)是讓你的網(wǎng)站運行在安全連接上,因為廠商大佬們已經(jīng)說過了:我們哥們幾個只支持有 TLS 的 HTTP/2搁料,那些不支持 TLS 的可以歇菜了或详。所以國內(nèi)大片的 HTTP 網(wǎng)站們要好好考慮轉(zhuǎn)向 HTTPS 的事了。
雪碧圖不再總是最佳的選擇
在 HTTP/1.1 中郭计,對于瀏覽器來說霸琴,獲取一個巨大的圖片文件比請求多個小圖片文件高效,這是因為多個請求會互相排隊昭伸,增加加載時間梧乘。通常的做法是把多個小圖片轉(zhuǎn)成一個雪碧圖。
轉(zhuǎn)成一個雪碧圖就只需要一個 HTTP 請求了庐杨。但是咧选调,如果一個頁面中只使用到雪碧圖中的一個圖標(biāo),仍然下載整個雪碧圖就顯得不是很好了灵份。HTTP/2 擁有多路復(fù)用的能力仁堪,所以多個請求排隊的事已經(jīng)不存在了,很多時候單個地請求圖片將是更好的選擇各吨。當(dāng)然枝笨,需要使用所有圖標(biāo)時袁铐,雪碧圖仍然是需要的。
使用 Data URI 內(nèi)嵌圖片是一種阻礙
在 HTTP/1.1 中横浑,為了減少 HTTP 請求剔桨,你可以把圖片直接以 Data URI 的形式嵌入 CSS 或 HTML 文件中。因為轉(zhuǎn)成的字符編碼會很長徙融,自然增加了 CSS 或 HTML 文件的大小洒缀。在 HTTP/2 中,HTTP 請求變得廉價欺冀,這種 “最佳實踐” 便變成了一種妨礙树绩。
合并 CSS 文件和 JavaScript 文件未必好
我們在應(yīng)用的構(gòu)建階段,通常會合并那些小的 CSS 和 JavaScript 文件隐轩,本意是減少 HTTP 請求饺饭。但是在 HTTP/2 中,HTTP 請求是廉價的职车,合并便不再顯得有優(yōu)勢瘫俊。可能更糟糕的是悴灵,如果你因為合并引入了很多非本頁面所需的文件扛芽,反而拖慢了加載速度,當(dāng)然积瞒,你是可以通過 webpack 來配置相應(yīng)頁面所需的相應(yīng)文件的川尖,可是別忘了,合并文件是要引入大量處理合并的代碼的茫孔,在 HTTP/2 廉價的請求中叮喳,這些多余的處理代碼看來有點多余,止增笑耳银酬。
域名分片可能會坑你
在 HTTP/1.1 中嘲更,每個域名能打開的連接是受到限制的,大概為 6 - 8 個揩瞪,具體取決于瀏覽器實現(xiàn)赋朦。如果你實在要加載大量資源,其中一個方法就是從多個域名中獲取資源李破,這就是域名分片 (domain sharding)宠哄。這個方法能實現(xiàn)更好的加載時間,也有能導(dǎo)致問題嗤攻,當(dāng)然毛嫉,準(zhǔn)備這種服務(wù)就會有額外的開支。HTTP/2 則移除了域名分片的需求妇菱,在 HTTP/2 下承粤,瀏覽器只為每個域名打開一個連接暴区,但是人家有多路復(fù)用嘛,并發(fā)請求的數(shù)量根本不受限制 (當(dāng)然也可以通過 SETTINGS_MAX_CONCURRENT_STREAMS 來限制)辛臊。而且仙粱,域名分片在 HTTP/2 中還會損害性能,因為它創(chuàng)建了額外的 TCP 連接彻舰,妨礙 HTTP/2 為資源進(jìn)行優(yōu)先級排序伐割。
當(dāng)前對于 HTTP/1.1 的最佳實踐是限制域名分片為 2 個域名。好消息是為了減少工作并在 HTTP/1.1 和 HTTP/2 都能達(dá)到很好的效果刃唤,有方法可以讓 HTTP/2 合并你的連接隔心,具體方法見 Google 家的 slide 26纲菌。
實現(xiàn)
可喜的是深滚,現(xiàn)在已經(jīng)有大量的 HTTP/2 的服務(wù)器端實現(xiàn)了丧凤,涵蓋了多種語言隔披,參見
Implementations。
Reference
- The Complete Guide To Switching From HTTP To HTTPS
- An overview of HTTP
- Hypertext Transfer Protocol
- Method Definitions
- HTTP協(xié)議中GET和POST方法的區(qū)別
- How To Secure Your Web App With HTTP Headers
- List of HTTP header fields - Wikipedia
- RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2)
- HTTP/2 - Wikipedia
- Getting Ready For HTTP2: A Guide For Web Designers And Developers
- HTTP/2 Frequently Asked Questions