TLS(Transport Layer Security)協定——也常以其前身的名字 SSL(Secure Socket Layer)相稱——是網際網路安全的主力。
TLS 保護伺服器與客戶端之間的連線,無論那是網站與其訪客、電子郵件伺服器、行動應用與其伺服器,還是電玩伺服器與玩家之間的連線。
TLS 是應用無關的,它不在乎被加密的內容是哪一類。這意味著你可以把它用於依賴 HTTP 協定的網頁應用,也可以用於任何「客戶端電腦或裝置需要向遠端伺服器發起連線」的系統。例如 TLS 被廣泛用於所謂**物聯網(IoT)**應用中的機器對機器通訊。
從臃腫到重生#
多年下來,TLS 變得越來越複雜。不幸的是,複雜與臃腫帶來了多個漏洞,而其雜亂實作中發現的 bug 更登上頭條——想想 Heartbleed、BEAST、CRIME 與 POODLE,這些漏洞全都衝擊了數百萬台網頁伺服器。
2013 年,厭倦了不斷修補 TLS 中新密碼學漏洞的工程師們對它進行了徹底翻修,開始著手 TLS 1.3。
TLS 1.3 捨棄了不必要與不安全的功能,並以最先進的密碼取代舊演算法。成果是一個更簡單、更快、更安全的協定。
本章脈絡#
- 目標應用與需求——TLS 要解決的問題,以及它必須滿足的四個需求。
- TLS 協定套組——SSL/TLS 簡史、憑證與 CA、記錄協定、握手協定。
- TLS 1.3 相對 1.2 的改進——降級保護、單次往返握手、工作階段恢復。
- TLS 安全性的強項——鑑別與前向保密。
常見錯誤#
TLS 1.3 符合「通用安全通訊協定」的要求,但它並非刀槍不入。
與任何安全系統一樣,它在某些情況下會失效——例如當設計者對真實攻擊所做的假設被證明是錯的。
遺憾的是,即使是配置了最安全密碼的最新版 TLS 1.3,仍可能被攻破。
TLS 1.3 的安全性建立在「三方(客戶端、伺服器、憑證機構)都會誠實行事」這個假設上——但如果其中一方被攻陷,或 TLS 實作本身寫得很糟呢?
憑證機構被攻陷#
根憑證機構(root CA)是瀏覽器信任、用來驗證遠端主機所提供憑證的組織。
例如若你的瀏覽器接受 www.google.com 提供的憑證,前提假設是某個受信任的 CA 已驗證了憑證擁有者的合法性。瀏覽器藉由檢查 CA 簽發的簽章來驗證憑證——由於只有 CA 知道建立該簽章所需的私鑰,我們假設其他人無法代表該 CA 建立有效憑證。
很多時候,一個網站的憑證不是由根 CA 簽署,而是由中間 CA 簽署,而中間 CA 又透過憑證鏈連到根 CA。
攻擊者就能用該 CA 的私鑰,在未經 Google 同意的情況下為
google.com網域的任何 URL 建立憑證。他們可以用這些憑證假裝託管一台合法的伺服器或子網域(如mail.google.com),攔截使用者的憑證與通訊。
這正是 2011 年發生的事:攻擊者駭入荷蘭憑證機構 DigiNotar 的網路,得以建立看起來像是合法 DigiNotar 憑證的憑證,接著把這些偽造憑證用在數個 Google 服務上。
伺服器被攻陷#
若一台伺服器被攻陷並完全被攻擊者控制,一切都完了:
- 攻擊者能看到所有傳輸資料在加密之前的樣子。
- 也能看到所有接收資料在解密之後的樣子。
- 還能拿到伺服器的私鑰,用自己的惡意伺服器冒充合法伺服器。
顯然,這種情況下 TLS 救不了你。
所幸這類安全災難在 Gmail、iCloud 這類高知名度應用中很少見——它們受到良好保護,有時私鑰還存放在獨立的安全模組中。
更常見的是透過資料庫查詢注入與跨站腳本等漏洞對網頁應用發動的攻擊,因為這些攻擊大多與 TLS 的安全性無關,而且是攻擊者透過一條合法的 TLS 連線執行的。這類攻擊可能危及使用者名稱、密碼等等。
客戶端被攻陷#
當客戶端(例如瀏覽器)被遠端攻擊者攻陷時,TLS 的安全性同樣被危及。
攻陷客戶端後,攻擊者能擷取工作階段金鑰、讀取任何已解密的資料。
他們甚至能在客戶端的瀏覽器中安裝一個流氓 CA 憑證,讓瀏覽器靜默接受原本無效的憑證,從而讓攻擊者攔截 TLS 連線。
「CA 或伺服器被攻陷」與「客戶端被攻陷」之間的最大差別在於:客戶端被攻陷時,只有那個目標客戶端受影響,而非可能所有的客戶端。
實作中的 bug#
與任何密碼系統一樣,TLS 會因為實作中的 bug 而失效。
TLS bug 的代表作是 Heartbleed——OpenSSL 對一個名為 heartbeat 之次要 TLS 功能的實作中的緩衝區溢位。它於 2014 年由一位 Google 研究者與 Codenomicon 公司各自獨立發現,影響了數百萬台 TLS 伺服器與客戶端。
運作方式:客戶端先送出一個緩衝區連同緩衝區長度給伺服器,以檢查伺服器是否在線。
客戶端 伺服器記憶體
「如果你在,把 7 個字母的單字 BANANAS 送給我」 CLIENT_WANTS_7_LETTERS:
BANANAS..PRIVATE_KEY=1928
←── BANANAS 1249128319283812994851123...
「如果你在,把 200 個字母的單字 BANANAS 送給我」 CLIENT_WANTS_200_LETTERS:
BANANAS..PRIVATE_KEY=1928
←── BANANAS..PRIVATE_KEY = 1928124912... 1249128319283812994851123...
圖 13-3:OpenSSL 之 TLS 實作中的 Heartbleed bug
因此若客戶端提供一個比字串實際長度更長的長度,伺服器就會從記憶體讀出過多資料並回傳給客戶端——連同任何可能含有敏感資訊(如私鑰或工作階段 cookie)的額外資料。
Heartbleed 造成的震撼不令人意外。為了避免未來出現類似的 bug,OpenSSL 與其他主要 TLS 實作現在都執行嚴格的程式碼審查,並使用 fuzzer 這類自動化工具來找出潛在問題。
延伸閱讀#
本章不是 TLS 的完整指南,你或許會想更深入研究 TLS 1.3。
- 完整的 TLS 1.3 規格涵蓋協定的一切(儘管不必然涵蓋其背後的理由),見 TLS 工作組(TLSWG)首頁:https://tlswg.github.io/ ↗。
另外值得一提的兩個重要 TLS 倡議:
SSL Labs TLS test(https://www.ssllabs.com/ssltest/ ↗):Qualys 提供的免費服務,讓你測試瀏覽器或伺服器的 TLS 組態,給出安全評級與改進建議。
若你架設自己的 TLS 伺服器,用這個測試確保一切安全、拿到 A 級評等。
Let’s Encrypt(https://letsencrypt.org/ ↗):一個非營利組織,提供在你的 HTTP 伺服器上「自動變出」TLS 的服務。它包含自動產生憑證與設定 TLS 伺服器的功能,並支援所有常見的網頁伺服器與作業系統。