在以前的文章中,筆者簡要介紹了一下 HTTPS 的工做原理,在擴展閱讀中,筆者提到了中間人攻擊(Man In The Middle Attack,簡稱 MITM)而在本文中,筆者將進一步解釋什麼是中間人攻擊。segmentfault
如下內容來自維基百科中的中間人攻擊詞條:瀏覽器
在 密碼學和 計算機安全領域中, 中間人攻擊(Man-in-the-middle attack, 縮寫:MITM)是指攻擊者與通信的兩端分別創建獨立的聯繫,並交換其所收到的數據,使通信的兩端認爲他們正在經過一個私密的鏈接與對方直接對話,但事實上整個會話都被攻擊者徹底控制。在中間人攻擊中,攻擊者能夠攔截通信雙方的通話並插入新的內容。在許多狀況下這是很簡單的(例如,在一個未加密的 Wi-Fi 無線接入點的接受範圍內的中間人攻擊者,能夠將本身做爲一箇中間人插入這個網絡)。
簡單來講攻擊者就是一個介入通訊的傳話員,攻擊者知道通訊雙方的全部通訊內容,並且能夠任意增長、刪除、修改雙方的通訊內容,而雙方對此並不知情。安全
而中間人攻擊不只僅侷限於針對 HTTPS,對於開放性的鏈接,中間人攻擊很是容易。好比在一個未加密的 Wi-Fi 網絡中,一個攻擊者能夠很容易地將本身插入雙方的通訊之中以截取或者修改通訊的內容。服務器
這就是一個典型中間人攻擊的過程。在 HTTPS 中,Tom 就是客戶端,Jerry 是服務端,而郵遞員就是客戶端和服務端之間的任何實體(包括代理服務器、路由器、反向代理服務器等等),兩把鑰匙分別是公鑰和私鑰。通訊雙方並不知道(且一般很難發覺)本身其實在和中間人通訊而非直接和對方通訊。在通訊過程當中,Tom 和 Jerry 並無驗證對方的身份,這就致使了郵遞員能夠任意查看、修改或者丟棄雙方的通訊內容。網絡
從上面的例子看起來,彷佛任何在通訊雙方的實體均可以實施中間人攻擊,那麼 HTTPS 是如何防止中間人攻擊的呢?要防止被中間人攻擊,那麼就要確保通訊中的信息來自他聲稱的那我的,且沒有被修改過。在現實中,有多種方式能夠肯定某個實體的身份,好比我的的簽名 / 私章、組織的公章、甚至古時的信物。大部分狀況下,只須要在信件最後蓋上籤上本身的名字或者蓋上組織的公章,那麼接收者就能夠肯定這封信件就來自於他所聲稱的那我的 / 組織。在二進制的世界中,可使用數字簽名來確保某段消息 / 某份文件確實是由他所聲稱的那個實體所發出來的。網站
在以前的文章中,咱們介紹過非對稱加密,其中公鑰是公開的,而私鑰只有擁有者知道。用私鑰對某個文件 / 某段消息的散列值進行簽名就像一我的親手在信件最後簽上了本身的名字同樣,證實這份文件 / 這段消息確實來自私鑰的擁有者(由於公鑰是公開的,私鑰只有擁有者知道,因此若是能用其公開的公鑰解開數字簽名,那就證實這條消息確實來自於他私鑰的擁有者),這就能夠確保消息是來自他所聲稱的那個實體。這樣,在通訊中,雙方每次在寫完消息以後,計算消息的散列值,並用本身的私鑰加密生成數字簽名,附在信件後面,接收者在收到消息和數字簽名以後,先計算散列值,再使用對方的公鑰解密數字簽名中的散列值,進行對比,若是一致,就能夠確保該消息確實是來自於對方,而且沒有被篡改過。加密
不過有個問題,若是中間人在會話創建階段把雙方交換的真實公鑰替換成本身的公鑰了,那麼中間人仍是能夠篡改消息的內容而雙方並不知情。爲了解決這個問題,須要找一個通訊雙方都信任的第三方來爲雙方確認身份。這就像你們都相信公證處,公證處拿着本身的公章爲每一封信件都蓋上了本身的章,證實這封信確實是由本人發出的,這樣就算中間人能夠替換掉通訊雙方消息的簽名,也沒法替換掉公證處的公章。這個公章,在二進制的世界裏,就是數字證書,公證處就是 CA(數字證書認證機構)。操作系統
數字證書就是申請人將一些必要信息(包括公鑰、姓名、電子郵件、有效期)等提供給 CA,CA 在經過各類手段確認申請人確實是他所聲稱的人以後,用本身的私鑰對申請人所提供信息計算散列值進行加密,造成數字簽名,附在證書最後,再將數字證書頒發給申請人,申請人就可使用 CA 的證書向別人證實他本身的身份了。對方收到數字證書以後,只須要用 CA 的公鑰解密證書最後的簽名獲得加密以前的散列值,再計算數字證書中信息的散列值,將二者進行對比,只要散列值一致,就證實這張數字證書是有效且未被篡改過的。設計
通訊過程的安全性自下而上就是這樣保證的:代理
至此,整個信任鏈就創建起來了,只須要有一臺設備上安裝了能夠信任的根證書,就能夠用來分發更多安全的操做系統了。以後的全部信任鏈都是安全的了。
(題外話)這些設備在到消費者手裏以前有沒有被惡意修改,誰都不知道。密碼學家想法設法想用程序而非人類(由於人類容易收到外界影響,是沒法徹底信任的)來保證安全,到最後仍是離不開人類,而人類偏偏是這些精妙設計中最容易出現問題的一環。
HTTP 協議最初的時候是明文的,由於安全問題因此如今不少網站都在逐漸過渡到 HTTPS,然而對於大部分使用者來講,他們並不知道 HTTP 和 HTTPS 之間的區別,在瀏覽器輸入地址的時候都是直接輸入 www.example.com
而非 https://www.example.com
,在大部分狀況下,若是一個網站啓用了 HTTPS,服務器會將這個請求使用 301
或者 302
狀態碼以及一個 Location
頭部將請求從 80 端口重定向至使用 HTTPS 的 443 端口。可是,若是中間人劫持了使用者的網絡請求,那麼中間人能夠阻止客戶端與服務器創建 HTTPS 鏈接,而是一直使用不安全的 HTTP 鏈接,而中間人則和服務器創建正常的 HTTPS 鏈接,讓客戶端覺得本身正在和真實服務器通訊。這種攻擊手法稱做 SSLTrip。
爲了解決這個問題,IETF(互聯網工程任務小組)引入了一個策略,叫作 HSTS (HTTP Strict Transport Security, HTTP 嚴格傳輸安全)。HSTS 的做用是強制客戶端與服務端創建安全的 HTTPS 鏈接,而非不安全的 HTTP 鏈接。若是一個站點啓用了 HSTS 策略,那麼客戶端在第一次與該站點創建鏈接以後,在將來的一段時間內(由一個 HTTP 頭部控制,這個頭部爲:Strict-Transport-Security),客戶端與該站點的全部鏈接都會直接使用 HTTPS,即便客戶端訪問的是 HTTP,也會直接在客戶端重定向到 HTTPS 鏈接。
假設 https://example.com
的響應頭部含有 Strict-Transport-Security: max-age=31536000; includeSubDomains
,這意味着:
example.com
或者其子域名發送請求,必須採用 HTTPS 來發起鏈接。即便用戶在地址欄裏寫的是 http://example.com
,那也直接重寫爲 https://example.com
並直接發起 HTTPS 鏈接。若是站點沒有啓用 HSTS,用戶能夠忽略證書無效的警告,繼續創建鏈接,而若是站點啓用了 HSTS,那麼用戶即便想冒風險,瀏覽器也不會繼續訪問。
HSTS 能夠很大程度上防止 SSLTrip 攻擊,不過這樣仍是有個問題,那就是要啓用 HSTS,瀏覽器至少要和服務器創建一次 HTTPS 鏈接,若是中間人一直阻止瀏覽器與服務器創建 HTTPS 鏈接,那麼 HSTS 就失效了。解決這個問題有個辦法,那就是將 HSTS 站點列表內置到瀏覽器中,這樣只要瀏覽器離線判斷該站點啓用了 HSTS,就會跳過原先的 HTTP 重定向,直接發起 HTTPS 請求。