我們都知道,當打開瀏覽器,訪問某個網站,如果網址旁有個小鎖,代表訪問的網址是安全的,反之不安全。
當我們沒有看到那個小鎖的小圖標的時候,需要提高警惕,不要輕易輸入個人重要的資料。
所有的銀行和支付相關的網站都是 100% 使用 HTTPS 通道的。
為什麼需要 HTTPS?
HTTPS(全稱:Hypertext Transfer Protocol over Secure Socket Layer),是以安全為目標的HTTP通道,簡單講就是HTTP的安全版。
我們為什麼需要 HTTPS?主要有如下三個原因:
①保護隱私(Privacy ) :所有信息都是加密傳播,第三方無法竊聽數據。如果使用 HTTP 明文傳輸數據的話,很可能被第三方劫持數據,那麼所輸入的密碼或者其他個人資料都被暴露在他人面前,後果可想而知。
②數據完整性(Integraty):一旦第三方篡改了數據,接收方會知道數據經過了篡改,這樣便保證了數據在傳輸過程中不被篡改——數據的完整性。
③身份認證(Identification):第三方不可能冒充身份參與通信,因為服務器配備了由證書頒發機構(Certificate Authority,簡稱 CA)頒發的安全證書,可以證實服務器的身份信息,防止第三方冒充身份。
也有少數情況下,通信需要客户端提供證書,例如銀行系統,需要用户在登錄的時候,插入銀行提供給用户的 USB,就是需要客户端提供證書,用來驗證客户的身份信息。
HTTPS 是什麼?SSL/TLS 是什麼?
HTTP 協議(HyperText Transfer Protocol,超文本傳輸協議)是大家最熟悉的一種協議,它是一個用於傳輸超媒體文檔的協議,它位於 OSI 網絡協議模型的應用層。
但是它是明文傳輸協議,是非常不安全的,容易被人篡改和竊取數據。
SSL(Secure Socket Layer)——網景(Netscape)公司設計的主要用於 Web 的安全傳輸協議。
它位於 TCP 傳輸層協議和應用層協議之間。(它沒有被劃分在 OSI 網絡協議模型中,且認為它是應用層的子層。)
眾所周知,網景公司 20 世紀 90 年代在和微軟的競爭中最終敗下陣來,之後網景公司將 SSL 協議的管理權轉交給 IETF(Internet Engineering Task Force, www.ietf.org)。有興趣的同學,可以去百度搜下網景&微軟,瞭解詳情。
迴歸正題, IETF 將 SSL 作了標準化後,重新命名為 TLS(Transport Layer Security)。在 1999 年,TLS 1.0 誕生了(其實也就是 SSL 3.1)。
HTTPS(HyperText Transfer Protocol Secure)是建立在 SSL/TLS 協議之上,信息通信通過 SSL/TLS 進行加密,最後一個 S 就是 Secure 的縮寫,代表安全的意思,HTTPS = HTTP SSL/TLS。
SSL/TLS 發展史
SSL/TLS 發展史如上圖
實際上現代的瀏覽器已經基本不使用 SSL,使用的都是 TLS,SSL 3.0 於 2015 年已經壽終正寢,各大瀏覽器也不支持了。
但是由於 SSL 這個術語存在的時間太長,很多地方還是廣泛的使用它,但是要清楚其實它説的是 TLS。
有調查顯示現在絕大部分瀏覽器(>99.5%)都使用 TLS 1.2 或者 TLS 1.3。只有不足 1% 的瀏覽器仍然使用 TLS 1.0 或者 TLS 1.1。
TLS 1.2 仍然是主流協議(本文寫於 2020 年初),相信將來逐漸 TLS 1.3 將會作為主流協議。
很多瀏覽器將會開始不支持 TLS 1.0 和 1.1:
1、Google 將在 Chrome 72 中不推薦使用 TLS 1.0 和 1.1,而 Chrome 81 之後將會完全不支持。
2、Mozilla 的 Firefox,微軟的 Edge 和 IE 以及蘋果的 Safari 都會分別於 2020 年逐漸移除對 TLS 1.0 和 1.1 的支持。
那麼一些還在使用 TLS 1.0 和 1.1 的網站就得被迫升級到 TLS 1.2 或者 TLS 1.3。
要關閉瀏覽器對 TLS 1.0 和 1.1 的支持,可以在 Internet 選項中修改:
SSL/TLS 的工作原理
需要理解 SSL/TLS 的工作原理,我們需要掌握加密算法。
加密算法有兩種:
對稱加密:通信雙方使用相同的密鑰進行加密。特點是加密速度快,但是缺點是需要保護好密鑰,如果密鑰泄露的話,那麼加密就會被別人破解。常見的對稱加密有 AES,DES 算法。
非對稱加密:它需要生成兩個密鑰:公鑰(Public Key)和私鑰(Private Key)。
公鑰顧名思義是公開的,任何人都可以獲得,而私鑰是私人保管的,相信大多程序員已經對這種算法很熟悉了。
我們提交代碼到 Github 的時候,就可以使用 SSH key:在本地生成私鑰和公鑰,私鑰放在本地 .ssh 目錄中,公鑰放在 Github 網站上。
這樣每次提交代碼,不用麻煩的輸入用户名和密碼了,Github 會根據網站上存儲的公鑰來識別我們的身份。公鑰負責加密,私鑰負責解密;或者,私鑰負責加密,公鑰負責解密。
這種加密算法安全性更高,但是計算量相比對稱加密大很多,加密和解密都很慢。
常見的非對稱算法有 RSA。SSL/TLS 是利用了對稱加密和非對稱加密的特點。
先來看下整個 SSL/TLS 的握手過程,之後我們再分步驟詳細解讀,每一步都幹了些什麼。
①當 TCP 建立連接之後,TLS 握手的第一步由客户端發起,發送 ClientHello 的消息到服務器。
ClientHello 消息包含:
延伸閲讀:
加密套件名如:“TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA256”,這麼長的名字看着有點暈吧,不用怕,其實它的命名非常規範,格式很固定。基本的形式是“密鑰交換算法-服務身份驗證算法-對稱加密算法-握手校驗算法”。
握手過程中,證書籤名使用的 RSA 算法,如果證書驗證正確,再使用 ECDHE 算法進行密鑰交換,握手後的通信使用的是 AES256 的對稱算法分組模式是 GCM。
驗證證書籤名合法性使用 SHA256 作哈希算法檢驗。相關的算法的用處將在後文中詳解。
②然後服務器端在收到這個 ClientHello,從中選擇服務器支持的版本和套件,發送 ServerHello 消息:
隨後服務器發送服務器的安全證書(含公鑰)。如果需要客户端也提供證書的話,還會發出客户端證書請求(Client Certificate Request),只有少數金融機構才需要客户端也提供客户端證書。
此後客户端發送 Server Hello Done 消息表示 Hello 階段完成。
③客户端收到 ServerHello 後,會對收到的證書進行驗證。
我們來看一下為什麼可以通過 CA(Certificate Authority,證書頒發機構)簽發的證書來確認網站的身份?
當我們安裝操作系統或者瀏覽器的時候,會安裝一組可信任的 CA(根證書 CA 包括 GlobalSign、GeoTrust、Verisign 等)列表。
根 CA 如 GlobalSign 就在我們的可信任的 CA 列表裏,你的瀏覽器或者操作系統含有 GlobalSign 的公鑰。
先來看一下 Google 的證書,當你訪問 Google 的時候,Google 會發給你它的證書。
證書中包含頒發機構的簽名以及服務器的公鑰。
瀏覽器首先用哈希函數對明文信息的摘要做哈希得到一個哈希值(用到的就是證書中的簽名哈希算法 SHA256),然後用根 CA 的公鑰對根證書的簽名作解密得到另一個哈希值(用到的算法就是 RSA 非對稱算法)。
如果兩個哈希值相等則説明證書沒有被篡改過。當然還需校驗證書中服務器名稱是否合法以及驗證證書是否過期。
這樣就免受中間人攻擊了,因為假如有中間人修改了證書的內容(如將證書中的公鑰替換成自己的公鑰),那麼將獲得不同的哈希值,從而兩個哈希值不匹配導致驗證失敗。
如果要繞過這個機制,中間人必須要也替換籤名,使簽名也相匹配。而做到這一點就需要破解到了根證書的密鑰(而這是不可能的,中間人必然會失敗)。
瀏覽器會出現以下畫面,告訴你正在遭受中間人攻擊,因為證書被篡改了:
那聰明的你肯定也想到了,如果你開發了一個系統還在測試階段,還沒有正式申請一張證書,那麼你可以為服務器自簽名一張證書,然後將證書導入客户端的 CA 信任列表中。
信任鏈機制如下圖:
可以看到證書路徑是:
因為我們的瀏覽器信任 GlobalSign Root CA,根據信任鏈機制,你相信了根 CA 頒發的證書,也要相信它簽名的子 CA 頒發的證書,也要相信子 CA 簽名的子子 CA 的證書。
而我們通過一級級的校驗,如果從根證書到最下層的證書都沒有被篡改過,我們就相信最下層的這個服務器證書是合法的。所以在這個機制中,你就需要無條件的相信根證書的頒發機構。
如果通過驗證,客户端生成一個隨機數 pre-master,用於密鑰交換過程。
④密鑰交換過程:客户端用第三步中服務器的證書中拿到服務器的公鑰,用這個公鑰加密(算法是加密套件中的密鑰交換算法,譬如 ECDHE 算法)生成密文發送給服務器。
⑤客户端用 server-random client-random pre-master 一起計算出對稱密鑰 master secret。
⑥服務器收到第四步的信息之後,用服務器的私鑰對密文進行解密得到密鑰 pre-master。
因為只有服務器有私鑰,可以針對客户端發出的加密過的信息進行解密得到 pre-master,這樣就保證了只有服務器和客户端知道 pre-master。
服務器端也可以用 server-random client-random pre-master 一起計算出對稱密鑰 master secret。
現在客户端和服務器均有密鑰 master secret 了,後面就可以用它來進行加密和解密了。
為什麼不能只用一個 pre-master 作為之後加密的對稱密鑰?
雖然只有服務器有私鑰,能夠解密 pre-master 呀,但僅用它作為 master secret 是不夠安全的,這是因為要以防客户端的 pre-master 並不是隨機數的情況。
加上另外兩個隨機數 client-random 以及 server-random(而這兩個隨機數和時間有相關性),這樣就能保證最後生成的 master secret 一定是隨機數。
⑦客户端用 master secret 加密了一條握手完成的消息發送給服務器。
⑧服務器端也回發了一條用 master secret 加密的握手完成的消息。
⑨當兩方都收到對方發送的握手消息之後,也成功解密後,就可以用 master secret 愉快的開始數據加密和解密了。
綜上,整個握手過程主要是通過一系列步驟通過非對稱加密的算法交換得到了 master secret,這個步驟通常需要幾百毫秒,但是就是這一頓猛操作之後使得只有服務器和客户端知道 master secret。
之後的通信又利用了高效的對稱算法對所有信息進行加密和解密,雖然加密和解密也需要耗時耗流量,不過信息是完全不可能被別人篡改和破解的,這一點損耗還是值得的。