HTTPS 中間人攻擊及其防範

HTTPS 中間人攻擊及其防範

以前的文章中,筆者簡要介紹了一下 HTTPS 的工做原理,在擴展閱讀中,筆者提到了中間人攻擊(Man In The Middle Attack,簡稱 MITM)而在本文中,筆者將進一步解釋什麼是中間人攻擊。segmentfault

什麼是中間人攻擊

如下內容來自維基百科中的中間人攻擊詞條:瀏覽器

密碼學計算機安全領域中, 中間人攻擊(Man-in-the-middle attack, 縮寫:MITM)是指攻擊者與通信的兩端分別創建獨立的聯繫,並交換其所收到的數據,使通信的兩端認爲他們正在經過一個私密的鏈接與對方直接對話,但事實上整個會話都被攻擊者徹底控制。在中間人攻擊中,攻擊者能夠攔截通信雙方的通話並插入新的內容。在許多狀況下這是很簡單的(例如,在一個未加密的 Wi-Fi 無線接入點的接受範圍內的中間人攻擊者,能夠將本身做爲一箇中間人插入這個網絡)。

簡單來講攻擊者就是一個介入通訊的傳話員,攻擊者知道通訊雙方的全部通訊內容,並且能夠任意增長、刪除、修改雙方的通訊內容,而雙方對此並不知情。安全

而中間人攻擊不只僅侷限於針對 HTTPS,對於開放性的鏈接,中間人攻擊很是容易。好比在一個未加密的 Wi-Fi 網絡中,一個攻擊者能夠很容易地將本身插入雙方的通訊之中以截取或者修改通訊的內容。服務器

一個通俗的例子

  1. 假設 Tom 想和 Jerry 交換一些祕密信息,然而 Tom 又不想跑到 Jerry 家裏,因而 Tom 叫來了郵遞員,給了郵遞員一封信。信的內容是但願 Jerry 給 Tom 一個盒子(這個盒子有兩把鑰匙)和其中一把鑰匙(另外一把在 Jerry 手裏)。
  2. 郵遞員在拿到 Tom 給的信件之後,把 Tom 的信拆開看了一遍,瞭解到 Tom 但願 Jerry 給 Tom 一個有鎖的盒子,又用另外一個信封裝了回去,並交給了 Jerry。
  3. Jerry 在收到 Tom 的信(實際已經被郵遞員拆閱過了)以後,給了郵遞員一個有鎖的盒子和其中一把鑰匙。
  4. 郵遞員想知道他們的通訊內容,因而他把 Jerry 給 Tom 的盒子換成了他本身的盒子,並附上了本身盒子中的一把鑰匙,並在以後將本身的盒子交給了 Tom。
  5. Tom 在收到盒子以後,覺得這個盒子是 Jerry 給他的,因而就把祕密的信件放進了盒子裏,並把鑰匙留下了,以後又交給了郵遞員。
  6. 郵遞員在拿到盒子以後,用本身的另外一把鑰匙打開盒子,看了裏面的信件。以後將信件調換以後放進了 Jerry 給的盒子,交給了 Jerry。
  7. Jerry 在拿到郵遞員給他的盒子以後,並不知道這個盒子裏的信件其實已經被郵遞員調換過了,因此 Jerry 認爲盒子裏的信件是來自 Tom 且未被修改過的。以後 Jerry 把回信放進了盒子裏,又交給了郵遞員。
  8. 郵遞員再次調換盒子裏的信件,交給了 Tom。

這就是一個典型中間人攻擊的過程。在 HTTPS 中,Tom 就是客戶端,Jerry 是服務端,而郵遞員就是客戶端和服務端之間的任何實體(包括代理服務器、路由器、反向代理服務器等等),兩把鑰匙分別是公鑰和私鑰。通訊雙方並不知道(且一般很難發覺)本身其實在和中間人通訊而非直接和對方通訊。在通訊過程當中,Tom 和 Jerry 並無驗證對方的身份,這就致使了郵遞員能夠任意查看、修改或者丟棄雙方的通訊內容。網絡

HTTPS 如何防範中間人攻擊

從上面的例子看起來,彷佛任何在通訊雙方的實體均可以實施中間人攻擊,那麼 HTTPS 是如何防止中間人攻擊的呢?要防止被中間人攻擊,那麼就要確保通訊中的信息來自他聲稱的那我的,且沒有被修改過。在現實中,有多種方式能夠肯定某個實體的身份,好比我的的簽名 / 私章、組織的公章、甚至古時的信物。大部分狀況下,只須要在信件最後蓋上籤上本身的名字或者蓋上組織的公章,那麼接收者就能夠肯定這封信件就來自於他所聲稱的那我的 / 組織。在二進制的世界中,可使用數字簽名來確保某段消息 / 某份文件確實是由他所聲稱的那個實體所發出來的。網站

在以前的文章中,咱們介紹過非對稱加密,其中公鑰是公開的,而私鑰只有擁有者知道。用私鑰對某個文件 / 某段消息的散列值進行簽名就像一我的親手在信件最後簽上了本身的名字同樣,證實這份文件 / 這段消息確實來自私鑰的擁有者(由於公鑰是公開的,私鑰只有擁有者知道,因此若是能用其公開的公鑰解開數字簽名,那就證實這條消息確實來自於他私鑰的擁有者),這就能夠確保消息是來自他所聲稱的那個實體。這樣,在通訊中,雙方每次在寫完消息以後,計算消息的散列值,並用本身的私鑰加密生成數字簽名,附在信件後面,接收者在收到消息和數字簽名以後,先計算散列值,再使用對方的公鑰解密數字簽名中的散列值,進行對比,若是一致,就能夠確保該消息確實是來自於對方,而且沒有被篡改過。加密

不過有個問題,若是中間人在會話創建階段把雙方交換的真實公鑰替換成本身的公鑰了,那麼中間人仍是能夠篡改消息的內容而雙方並不知情。爲了解決這個問題,須要找一個通訊雙方都信任的第三方來爲雙方確認身份。這就像你們都相信公證處,公證處拿着本身的公章爲每一封信件都蓋上了本身的章,證實這封信確實是由本人發出的,這樣就算中間人能夠替換掉通訊雙方消息的簽名,也沒法替換掉公證處的公章。這個公章,在二進制的世界裏,就是數字證書,公證處就是 CA(數字證書認證機構)操作系統

數字證書就是申請人將一些必要信息(包括公鑰、姓名、電子郵件、有效期)等提供給 CA,CA 在經過各類手段確認申請人確實是他所聲稱的人以後,用本身的私鑰對申請人所提供信息計算散列值進行加密,造成數字簽名,附在證書最後,再將數字證書頒發給申請人,申請人就可使用 CA 的證書向別人證實他本身的身份了。對方收到數字證書以後,只須要用 CA 的公鑰解密證書最後的簽名獲得加密以前的散列值,再計算數字證書中信息的散列值,將二者進行對比,只要散列值一致,就證實這張數字證書是有效且未被篡改過的。設計

通訊過程的安全性自下而上就是這樣保證的:代理

  1. 雙方通訊內容的安全性是靠公鑰加密、私鑰解密來保證的,這一安全性由非對稱加密的特性,即由公鑰加密的信息只能使用對應的私鑰才能解開來保證。因爲私鑰不會傳遞,只有擁有者知道,因此安全性就由公鑰的正確性來保證。
  2. 公鑰由對方在通訊初始所提供,可是這時很容易被中間人替換掉,爲了保證公鑰的正確性,因此在發送公鑰的時候也會提供對應的數字證書,用於驗證這個公鑰是對方的而不是中間人的。那麼安全性就是由數字證書的正確性來保證了。
  3. 數字證書是由上級 CA 簽發給我的 / 組織的,上級 CA 用本身的私鑰給我的證書進行簽名,保證證書中的公鑰不被篡改,而接受者須要用上級 CA 證書中的公鑰來解密我的數字證書中的數字簽名來驗證證書中的公鑰是不是正確的。那麼安全性就是由上級 CA 證書的正確性保證的了。
  4. 可是,上級 CA 證書也是由其上級 CA 簽發的,這種信任關係一直到根證書。根證書沒有上級 CA 爲其簽名,而是自簽名的,也就是說,它自身爲自身簽名,保證正確性。因此根證書就是這個信任鏈最重要的部分。若是根證書泄露的話,其簽名的全部證書及使用其簽名的證書所簽名的證書的安全性將不復存在。如今,安全性就是靠系統根證書的私鑰不被泄露或者其公鑰不被篡改來保證的了。
  5. 根證書不該該經過網絡分發,由於經過網絡分發的話,可能會被中間人攻擊。通常根證書都經過操做系統或者瀏覽器分發,在操做系統中會內置不少根證書,可是最初的操做系統也不能經過網絡分發,由於中間人能夠修改操做系統中的根證書。因此要保證安全只能靠最原始的方法,當面交流。硬件廠商會和證書籤發機構合做,在電腦、手機等設備出廠的時候在其操做系統中內置簽發機構的根證書,再將這些設備分發出去,這樣,這些設備的用戶就能夠安全地進行信息交換了。因此,安全性就依賴於這些設備在分發到消費者手中以前不會被惡意修改來保證了。

至此,整個信任鏈就創建起來了,只須要有一臺設備上安裝了能夠信任的根證書,就能夠用來分發更多安全的操做系統了。以後的全部信任鏈都是安全的了。


(題外話)這些設備在到消費者手裏以前有沒有被惡意修改,誰都不知道。密碼學家想法設法想用程序而非人類(由於人類容易收到外界影響,是沒法徹底信任的)來保證安全,到最後仍是離不開人類,而人類偏偏是這些精妙設計中最容易出現問題的一環。


SSLTrip 及 HSTS

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,這意味着:

  1. 在將來的 1 年時間裏(即 31536000 秒中),只要瀏覽器向 example.com 或者其子域名發送請求,必須採用 HTTPS 來發起鏈接。即便用戶在地址欄裏寫的是 http://example.com,那也直接重寫爲 https://example.com 並直接發起 HTTPS 鏈接。
  2. 在接下去的一年中,若是服務器提供的 HTTPS 證書無效(不管是域名對不上仍是自簽名仍是不在有效期內),用戶都沒法訪問該站點。

若是站點沒有啓用 HSTS,用戶能夠忽略證書無效的警告,繼續創建鏈接,而若是站點啓用了 HSTS,那麼用戶即便想冒風險,瀏覽器也不會繼續訪問。

HSTS 能夠很大程度上防止 SSLTrip 攻擊,不過這樣仍是有個問題,那就是要啓用 HSTS,瀏覽器至少要和服務器創建一次 HTTPS 鏈接,若是中間人一直阻止瀏覽器與服務器創建 HTTPS 鏈接,那麼 HSTS 就失效了。解決這個問題有個辦法,那就是將 HSTS 站點列表內置到瀏覽器中,這樣只要瀏覽器離線判斷該站點啓用了 HSTS,就會跳過原先的 HTTP 重定向,直接發起 HTTPS 請求。

相關文章
相關標籤/搜索