網(wǎng)絡(luò)基礎(chǔ):HTTP 和 HTTPS

HTTP

在以前的文章中,我大力推薦過《圖解 HTTP》這本書。這是一本好書,但是 HTTP 協(xié)議本身是一個靜態(tài)協(xié)議:跟 HTML 一樣是一堆標(biāo)記的集合,十分簡單。

我們首先明確一個簡單的事實(shí):TCP 首部后面的部分,依然是一堆二進(jìn)制數(shù)據(jù),但是此時,采用 HTTP 協(xié)議解析這堆數(shù)據(jù)之后,其內(nèi)容終于可讀了。

HTTP 是什么

HTTP 是 WWW(萬維網(wǎng))擁有的標(biāo)準(zhǔn)協(xié)議,用于在客戶端和服務(wù)器之間傳遞信息:服務(wù)器給客戶端傳遞網(wǎng)頁,客戶端給服務(wù)端傳遞需要的頁面的 URL,上傳文件等。

前提

在討論 HTTP 協(xié)議之前,我們必須首先認(rèn)識到 HTTP 協(xié)議是站在巨人的肩膀上的:

HTTP 往下看,是 TCP 協(xié)議保證了可靠傳輸,再往下是 IP 協(xié)議保證了 Internet 的大和諧,再往下是以太網(wǎng)協(xié)議在局域網(wǎng)內(nèi)傳遞信息,再向底層追究,是雙絞線中的電壓變化將 0、1 一步步向下傳遞的。

HTTP 協(xié)議很簡單,但卻提供一個體驗良好的應(yīng)用標(biāo)準(zhǔn),到今天依然生命力旺盛。為什么?因為 TCP/IP 協(xié)議簇將復(fù)雜度消化了。

一個普通的 GET 例子

我們使用 Charles 反向代理軟件可以輕易地得到 HTTP 協(xié)議的細(xì)節(jié)。下面我們展示一個普通的 GET 例子。使用瀏覽器訪問 http://killtyz.com (自己嘗試的時候不要選擇 HTTPS 網(wǎng)站):

請求內(nèi)容

GET / HTTP/1.1

Host: killtyz.com

Upgrade-Insecure-Requests: 1

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8

Accept-Encoding: gzip, deflate

Accept-Language: zh-CN,zh;q=0.9

解釋:

第一行有三個元素:HTTP 方法、uri、HTTP 版本

之后的每一行均以 : 作為間隔符,左邊是 key,右邊是 value(當(dāng)然都是在 trim 之后)

HTTP 協(xié)議中,換行采用 \r\n,不是 Linux 系統(tǒng)文本編碼采用的 \n,而是跟 Windows 一樣的。

響應(yīng)內(nèi)容

HTTP/1.1 200 OK

Date: Thu, 25 Jan 2018 10:36:10 GMT

Server: Apache

Content-Length: 1321

Content-Type: text/html; charset=UTF-8

Proxy-Connection: Close


<!DOCTYPE html>

<html lang="en">

<head>

? <meta charset="UTF-8">

? <title>KillTYZ 干掉拖延癥</title>

? <link rel="stylesheet">

? <link rel="stylesheet" href="/css/main.css">

? <script src="http://libs.baidu.com/jquery/1.11.1/jquery.min.js"></script>

? <script src="http://libs.baidu.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>

? <script src="/js/main.js"></script>

</head>

<body>

? <div id="wrap">

? ? <div id="head">

? ? ? <div class="logo">

? ? ? ? <img id="logo" src="/images/logo.png" alt="logo">

? ? ? </div>

? ? ? <div class="title">

? ? ? ? <h2>干掉拖延癥</h2>

? ? ? </div>

? ? </div>

? ? <div class="content">

? ? ? <div id="box">

? ? ? ? <div id="add">

? ? ? ? ? <input id="add-input" type="text" class="form-control" placeholder="添加任務(wù)">

? ? ? ? </div>

? ? ? ? <div id="list" class="list-group">

? ? ? ? </div>

? ? ? </div>

? ? </div>

? ? <div id="foot">

? ? ? ?2018 <a >KillTYZ</a> | <a >Github Repo</a>

? ? ? <br>Powered by <a >TinyLara</a>

? ? </div>

? </div>

</body>

</html>

響應(yīng)的基本套路和請求一樣,第一行的三個元素分別是 協(xié)議版本、狀態(tài)碼、狀態(tài)碼的簡短解釋。需要注意的只有一點(diǎn):

HTTP header 和 HTTP body

兩個換行即 \r\n\r\n 之前的內(nèi)容成為 HTTP header

兩個換行之后的內(nèi)容稱為 HTTP body

HTTP body 就是你在瀏覽器查看源代碼看到的內(nèi)容

POST 例子

一下均為 Request 的 HTTP 內(nèi)容。

Content-Type: application/x-www-form-urlencoded


POST /api/app HTTP/1.1

Host: killtyz.com

Content-Length: 18

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36

Cache-Control: no-cache

Content-Type: application/x-www-form-urlencoded

Accept: */*

Accept-Encoding: gzip, deflate

Accept-Language: zh-CN,zh;q=0.9


post=man&key=value

Content-Type: multipart/form-data


POST /api/app HTTP/1.1

Host: killtyz.com

Content-Length: 5195

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36

Cache-Control: no-cache

Origin: chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop

Postman-Token: 45479b21-15fa-9232-ab8b-52c7dde8523d

Content-Type: multipart/form-data; boundary=----WebKitFormBoundary1s68Wb5ccTHj384y

Accept: */*

Accept-Encoding: gzip, deflate

Accept-Language: zh-CN,zh;q=0.9


------WebKitFormBoundary1s68Wb5ccTHj384y

Content-Disposition: form-data; name="image"; filename="QQ20141011-2.jpg"

Content-Type: image/jpeg


***二進(jìn)制文件內(nèi)容***

------WebKitFormBoundary1s68Wb5ccTHj384y

Content-Disposition: form-data; name="post"


man

------WebKitFormBoundary1s68Wb5ccTHj384y

Content-Disposition: form-data; name="oo"

xx

------WebKitFormBoundary1s68Wb5ccTHj384y--

Cookie 相關(guān) Header

Set-Cookie:響應(yīng)的 HTTP header 中如果有這個字段,那么瀏覽器會把這個字段的 value 設(shè)定到本地的 Cookie 里,配合服務(wù)端的 Session 可以實(shí)現(xiàn)登錄狀態(tài)臨時記錄的功能。

Cookie:會出現(xiàn)在請求的 HTTP header 中。Set-Cookie 設(shè)置的 Cookie 會有一個作用域名,一般為 www.baidu.com 或者 .baidu.com,在瀏覽器本地記錄的眾多 Cookie 中,只要有滿足這個作用域名要求的,下一次 HTTP 請求發(fā)出的時候會把這些條 Cookie 全部帶上。

更多詳細(xì)解釋需要的時候可以自己查,都是明碼實(shí)價,童叟無欺的。

HTTPS

HTTPS 這個名字取得不好,讓很多人都誤解了,以為他是和 HTTP 類似的協(xié)議,這是不對的。

HTTPS 全稱為 HTTP Over TLS。(SSL/TLS 是一系列承前啟后的加密協(xié)議族,此處統(tǒng)稱為 TLS。)

什么是 TLS

TLS 中文名稱為安全傳輸層協(xié)議,其目的是在客戶端與服務(wù)端之間建立一個 防竊聽、防篡改 的可信信息傳遞通道。

技術(shù)細(xì)節(jié)不再闡述

TLS 真正的組成非常的復(fù)雜,本文不想討論那些技術(shù)細(xì)節(jié),更不想討論客戶聯(lián)和服務(wù)端建立連接的繁瑣方式,什么先非對稱加密再對稱加密,一概不討論;本文只進(jìn)行概述、闡述特點(diǎn)。

技術(shù)特點(diǎn)

TLS 采用非對稱加密和對稱加密結(jié)合的方式,在客戶端和服務(wù)器之間建立起一個 防竊聽、防篡改 的通信通道。TLS 具有以下特點(diǎn):

基于 TCP 協(xié)議,不需要再苦苦解決網(wǎng)絡(luò)可靠性問題

采用服務(wù)端部署證書的形式提供對稱加密基礎(chǔ)

TLS 連接首次建立的過程十分消耗資源,不僅費(fèi) CPU 還非常耗時(和簡單不可靠的 HTTP比)

TLS 沒有完美實(shí)現(xiàn) 防竊聽、防篡改 功能:中間人攻擊依然存在相當(dāng)大的可能性

TLS 實(shí)現(xiàn)原理

我從證書的兩種簽名方式來講解 TLS 實(shí)現(xiàn)原理的簡單描述,并分別闡述當(dāng)前 HTTPS 證書的兩大層面的功能。

自簽名 TLS 證書

任何一臺安裝了 OpenSSL 開源軟件的計算機(jī)均可以生成 TLS 證書并簽名。制造自簽名證書分為以下幾步:

使用 RSA 算法生成私鑰。私鑰為絕密,由于證書公開,所以擁有私鑰的人將實(shí)質(zhì)上擁有證書的所有權(quán)。

生成與私鑰一對一的根證書,并填入 TLS 證書需要的必要信息(common name 等)。

采用嚴(yán)格配對的 私鑰+證書 部署 Apache 或 Nginx。

第三方簽名的 TLS 證書

分為以下幾步:

使用 RSA 算法生成私鑰。私鑰為絕密,由于證書公開,所以擁有私鑰的人將實(shí)質(zhì)上擁有證書的所有權(quán)。

生成與私鑰一對一的 csr 文件。

將此文件上傳到證書頒發(fā)商的網(wǎng)站,他們將用他們的 根證書 或者 從根證書派發(fā)出的二級證書 為我們的 csr 文件簽名,得到 TLS 證書。期間會填入經(jīng)過他們實(shí)際驗證的必要信息,如 common name 和公司名稱。

采用嚴(yán)格配對的 私鑰+證書 部署 Apache 或 Nginx。

最重要的一點(diǎn)

RSA 公鑰加密算法從數(shù)學(xué)上決定了無法從公開的信息(證書)反推出私鑰。所以說,只要私鑰不泄露,哪怕有人自己寫代碼強(qiáng)制使用公開的 TLS 證書和他自己偽造的私鑰也是不可能的:數(shù)學(xué)上無法成立,根本就沒法和客戶端正常交互建立 TLS 連接。

防竊聽、防篡改

防竊聽:TLS 內(nèi)部攜帶的數(shù)據(jù)就是完整的 HTTP 協(xié)議,request 和 response 都會被加密,完全無法破解,除非 RSA 算法被破解。TLS 還會在表面上加上少許 HTTP header,只有極少數(shù)必要信息如域名等。所以,就算 Twitter 用了 HTTPS,功夫網(wǎng)還是能夠偵測出你在訪問 Twitter。

防篡改:TLS 會對每一次數(shù)據(jù)交互進(jìn)行嚴(yán)格的校驗。HTTP 時代大家飽受運(yùn)營商劫持的困擾,本質(zhì)就是對 HTTP 數(shù)據(jù)的篡改,明文的嘛,正常。TLS 層中的數(shù)據(jù)被修改一位,這個 TLS 連接就會崩塌,兩邊瞬間就都知道了。

當(dāng)前 HTTPS 技術(shù)的兩層功能

加密。無論證書是自簽名還是服務(wù)商簽名,只要證書沒有過期,就可以實(shí)現(xiàn)加密,保證信息傳遞的防竊聽、防篡改。

可信。全球數(shù)十家服務(wù)商的根證書是預(yù)置在操作系統(tǒng)內(nèi)部的:iOS、macOS、Windows 都是這樣。因為我們的計算機(jī)信任根證書,所以才信任由其派生出的二級及三級證書??尚烹m然會在 Chrome 上被標(biāo)紅,但卻可以“仍然繼續(xù)”跳過;而證書過期則不行:TLS 連接都無法建立,Chrome 想繼續(xù)都繼續(xù)不了呀。

TLS 的局限

TLS 雖然很強(qiáng)大,還是有一些問題。我們先說小問題,再說大問題。

安全要求不完善

TLS 證書是標(biāo)準(zhǔn)證書,和 HTTP 業(yè)務(wù)無關(guān),這就導(dǎo)致我們必須采用現(xiàn)成的字段來保存這個證書可以用于那些域名:common name 字段。

我們知道,協(xié)議 + 域名 + 端口 組成了一個“域”,域是瀏覽器中的基本安全單位,用在很多地方。TLS 證書等于說放開了端口這個要求,這樣一來一個證書就可以被部署到任意的 N 個端口上。

中間人攻擊風(fēng)險依舊

中間人攻擊指的是中間有一個人偽造是你想連接的那臺服務(wù)器,竊取你的信息:在咖啡廳開一個假 wifi,就可以通過修改 DNS 的方式假裝你的筆記本是百度的服務(wù)器,這樣就可以獲取想要的信息了。TLS 防止的是傳輸過程中的防竊聽、防篡改,無法解決服務(wù)端偽造問題。

中間人攻擊分為三個方式:

HTTP 轉(zhuǎn) HTTPS。早期網(wǎng)銀攻擊經(jīng)常采用這種方式:用戶訪問網(wǎng)銀網(wǎng)站,瀏覽器默認(rèn)發(fā)出的是 HTTP 請求,本來該網(wǎng)站會將用戶跳轉(zhuǎn)到 HTTPS,但是中間人從中作梗:跟客戶交流時采用 HTTP,跟銀行交流時采用 HTTPS,這樣你的銀行卡和密碼就全暴露了。

合法證書方式。采用特殊手段簽出一張合法的證書,正大光明地做中間人。

終端自殘式。破壞自己的終端,強(qiáng)制讓自己的操作系統(tǒng)信任一張全域名證書:這樣任何網(wǎng)絡(luò)請求都是明文了。所以 HTTPS 防不了 APP 破解者。

除非客戶端和服務(wù)端預(yù)先進(jìn)行信息約定,不然從理論上講是不可能建立一個完全可信的加密數(shù)據(jù)通道的。

防止中間人攻擊的方法

只有一個:在 APP 中內(nèi)置證書,每次建立連接時都進(jìn)行比對。感興趣的可以到我的網(wǎng)站搜 SSL,我專門闡述了如何設(shè)置 SSL pinning(鋼釘)。

總結(jié)

HTTP 真的是一種十分簡單的協(xié)議,HTTPS 只要了解了 TLS 的基本概念也不復(fù)雜,復(fù)雜度都在 TCP/IP 那里被消化了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容