修復正向保密
對於 TLS(保障網路通信提供安全及數據完整性的一種安全協議),可能最大的抱怨是, TLS 握手動作緩慢,傳輸加密會造成很多 CPU 開銷。當然,如果配置正確這些都不是問題。
最重要的通過 TLS 提高訪客訪問你網站的用戶體驗的一個特徵是會話恢復。會話恢復是指當再一次連接到那些主機時,通過存儲和重用以前的秘密信息。這大大減少了網路延遲和 CPU 的使用量。
我們可以在網路伺服器和代理中啟用會話恢復,但是很容易違背正向保密。為了找出為什麼有實際標準的 TLS 庫(即 OpenSSL )會是一件壞事和如何避免搞砸 PFS ,讓我們仔細看看正向保密性和安裝啟用會話恢復功能的伺服器端當前狀態。
什麼是(完美)正向保密?
(完美)的正向保密性是現代 TLS 設置的一個重要組成部分。它的核心是使用臨時(短期)密鑰來交換密鑰,所以獲得伺服器連接的攻擊者將不能使用任何的鑰匙找到並破譯過去可能被他們記錄的 TLS 會話。
如果我們想要實現完全正向加密( PFS )的密鑰交換,那麼我們絕對不能讓伺服器的證書中含有公鑰的RSA密鑰對。因為這個密鑰是長期存活的,很有可能比證書的有效日期還長。這意味著你有可能會在證書到期後仍然使用相同的密鑰生成新的證書。如果伺服器被攻破,那就太容易確定在磁碟或內存中的私鑰的位置並用它來破譯以前的 TLS 會話記錄了。
使用更廉價產生密鑰的Diffie-Hellman 交換密鑰法,也就是我們可以使用一個密鑰對,使用一次之後馬上丟棄它。這樣,雖然訪問伺服器的攻擊者仍然可以攻破上面所說的認證部分並且可以拿到證書的私鑰,但過去的 TLS 會卻得到了保護。
如何恢復完美正向保密( PFS )會話?
TLS 提供兩個會話恢復功能:會話 ID 和會話標籤。為了更好地理解那些程序是為什麼可以被攻擊的,花點時間仔細研究細節是值得的。
會話 IDs
在一個完整的握手協議過程中,伺服器發送一個會話標識 ID 作為「你好」消息的一部分。在隨後的連接上,在保持連接的狀態下,客戶端可以使用該會話標識 ID ,並將其傳遞給伺服器。由於伺服器和客戶端在會話 ID 的協助下都保存了上一次會話的「機密信息」,它們可以簡單地恢復 TLS 會話到之前中斷的地方。
為了能支持通過會話標識 ID 恢復會話,伺服器必須維護一個映射之前會話標識 ID 到會話機密狀態的緩存列表。這塊緩存本身是主要的弱點,竊取緩存內容就可以破譯其中所有會話標識 ID 對應的會話內容。
一個連接的前正向保密性是通過在伺服器上保留會話信息的時間來限制實現的。理想情況下,您的伺服器將使用一個平均大小的緩存,每天清除一次這塊緩存。清除您的緩存可能不幫助,如果緩存本身生存在一個持久性存儲周期,因為它可能是用來恢復被刪除的數據的。如果它變成了一天一次,內存應該預備有足夠能力抵抗這種攻擊,確保舊數據重寫正確。
會話標籤
第二個恢復 TLS 會話的機制是會話標籤。這個擴展將伺服器的狀態加密傳送給客戶端,用一個只有伺服器知道的密鑰進行加密。這個會話標籤的密鑰會一直保護 TLS 連接,它也將成為攻擊者攻擊的有力點。
客戶將把從伺服器發送的會話標籤和一個 TLS 會話的加密信息一起存儲。通過下一次 TLS 連接開始的時候再把會話標籤發送回伺服器,就可以實現它們以前會話的恢復。因為伺服器仍然可以訪問之前用以加密的密鑰。
我們理想的情況是,讓會話標籤和會話標識 ID 有一樣的保密限制。為了實現這一點,我們需要確保用於加密標籤的密鑰是每天變換的。它應該只作為會話緩存,不應該在持久存儲中勝春,這樣就不留任何可被追蹤的痕迹。
Apache 配置
現在,我們來決定一下應該通過何種方式配置實現我們理想的會話恢復功能。讓我們一起看一下在流行的 Web 伺服器軟體和負載均衡里是否依然支持,首先從 Apache 開始。
配置會話緩存
Apache 網路伺服器提供了配置緩存的 SSLSessionCache 的指令,這塊緩存包含了所有已經發生的 TLS 會話標識 ID 和其狀態。你可以使用 shmcb 作為存儲類型,這是一塊共享內存分區的高性能周期緩衝區。它在所有的線程或進程中是可以被共享的,而且無論哪個線程或進程掌握用戶的請求都可以恢復會話。
SSLSessionCache shmcb:/path/to/ssl_gcache_data(512000)
上面的例子通過路徑 /path/to/ssl_gcache_data 建立一個大小為 512 Kib 的內存緩存區。取決於每天的訪客量,緩存佔用空間可能會很小(即有一個高的周轉率)或很大(即有一個低的周轉率)。
理想情況下,我們希望有一個緩存,每天更新,並沒有好的辦法可以確定正確的會話緩存大小。我們真正需要的是一種機制,這種機制負責告訴 Apache 在緩存中的一條記錄被重寫之前被允許的最長生存時間。無論循環緩衝區實際上是否已經循環過,這種機制都需要被執行。它還必須是一種周期性後台工作,確保即使沒有在任何請求的情況下緩存也會被清除。
你可能想知道 SSLSessionCacheTimeout 指令是否可以在這種情況中有幫助,不幸的是沒有。這種超時只檢查會話 ID 在 TLS 連接開始的情況。它並不能從 session 緩存中清除條目記錄。
配置會話標籤
而Apache提供的 SSLSessionTicketKeyFile 指令指定密鑰文件應該包含48位元組,建議不要指定單個。Apache會對啟動和使用加密會話標籤會簡單地生成一個隨機的密鑰,只要會話在運行。
關於這一點的好處是,會話密鑰不會持久存儲,壞處是它永遠不會被更換。也就是說當Apache啟動的時候一次生成,除非當Apache重新啟動才被丟棄。對於大多數的伺服器而言,這意味著他們在數月或幾年的時間裡使用相同的密鑰。為了實現正向保密特性,我們需要每天動態更換會話標籤密鑰。但當前的Apache版本沒有提供這樣的方法。唯一的辦法是使用固定時間作業來優雅地重啟Apache,以確保每天產生一個新的關鍵。這聽起來不像一個真正的解決方案而且並沒有保證完全覆蓋舊密鑰。
在Apache正在運行的時候修改關鍵文件,你仍然需要重啟服務以產生新的密鑰。而且不要忘記,如果你使用一個密鑰文件,應該把它存放在一個類似 tmpfs 的臨時文件系統。
禁用會話標籤
雖然禁用會話門票必定會帶來負面的性能影響,但是為了正向加密需要,這正是你目前需要做的:
SSLOpenSSLConfCmd Options -SessionTicket
Ivan Ristic 補充說,如果想對 Apache 使用 SSLOpenSSLConfCmd 來禁用會話的標籤功能,你必須運行尚未發布的 OpenSSL 1.0.2 。如果你想禁用裝有早期 OpenSSL 版本 Apache 的會話標籤功能, Ivan 有 Apache 2.2.x 的幾個補丁和 Apache 2.4.x 的分支版本。
通過會話標籤支持安全的會話恢復, Apache 應該為指定會話標籤密鑰最有效時間提供一個配置指令,至少在啟動時自動生成。這將使我們能夠每天簡單地生成一個新的隨機密鑰,並覆蓋舊的密鑰。
Nginx的配置
另一種非常流行的 Web 伺服器是 Nginx 。讓我們把它在建立會話恢復方面和 Apache 比較一下。
配置會話緩存
Nginx 提供 ssl_session_cache 指令配置 TLS 會話緩存。緩存的類型應該被共享給多個 worker 之間共享:
ssl_session_cache shared:SSL:10m;
上述行建立了一個 10MB 大小的內存緩存區。對於將會每天更新數據的 10MB 緩存,我們沒有真正去考慮這個大小是否合適。和 Apache 類似, Nginx 應該提供一個配置指令允許緩存條目記錄可以在某個時間被自動清除。任何一項沒有被正確清洗的條目記錄都可能會被擁有完全許可權的伺服器攻擊者從存儲器中讀取。
你猜對了, ssl_session_timeout 指令只適用於當試圖在連接開始時恢復會話。過時的條目在生存周期結束後將不會被自動刪除。
配置會話標籤
Nginx 可以使用 ssl_session_ticket_key 指令指定會話標籤文件。而且下一次你可能通過不指定單個和在服務啟動時產生隨機密鑰做的更好。會議標籤密鑰將永遠不會被更換,並可能在數月或幾年的時間裡被用來加密會話標籤。
Nginx 中一樣也沒有提供任何方法去自動更換密鑰。使用周期作業方法載入配置日常可能有效,但並不是一個真正的解決辦法。
禁用會話標籤
為了給訪客提供正向加密的會話服務,你最好的做法就是因此關閉會議標籤功能支持,直到一個合適的解決方案出現。
ssl_session_tickets off;
HAProxy 配置
HAProxy ,流行的負載均衡器,和 Apache 和 Nginx 有著同樣的問題。他們都是依賴於 OpenSSL ,TLS 實現的。
配置會話緩存
該會話緩存的大小可以用 tune.ssl.cachesize 指令設置,接受一些「塊」。 HAProxy 的文檔試圖幫助和解釋每個存儲會話需要多少「塊」。但我們又不能保證至少每天需要多少。我們需要一個指令自動清除條目,就像在 Apache 和 Nginx 里一樣。
是的,這 tune.ssl.lifetime 指令不影響條目在緩存中的生存時間。
配置會話標籤
HAProxy 不允許配置會話標籤參數。它默認支持這個特性因為 OpenSSL 默認啟用。因此, HAProxy 將總是在啟動時產生會話標籤密鑰和使用它加密進程的整個生命周期。
每天正常重啟 HAProxy 可能更新密鑰的唯一途徑。這是一個純粹的假設,請在使用該產品之前做一下測試。
禁用會話標籤
你可以使用 no-tls-tickets 指令禁用 HAProxy 里支持的會話標籤功能:
ssl-default-bind-options no-sslv3 no-tls-tickets
這個軟體以前的一個版本表示關閉會議標籤功能是不可能的。感謝 HAProxy 團隊糾正了自己的錯誤!
多伺服器的會話恢復
如果你有多個 Web 伺服器作為後端伺服器,不幸的你就必須指定會話標籤密鑰文件和像個邪惡的黑客在午夜時重新載入服務配置。
雖然在多台使用 memcached (一個高性能的分散式內存對象緩存系統)的伺服器中共享會話緩存是可能的,但使用會話標籤的話你「只」共享一個或多個會話票證的鑰匙,而不是整塊緩存。客戶端將會小心儲存和丟棄你的會話標籤。
推特上有一篇關於他們如何管理多個網路前端到後端的帖子,並對他們的每一台機器會話標籤密鑰都妥善分類。如果你有一個類似的設置和通過支持會話標籤功能來提高響應速度,我建議閱讀一下。
請記住,為了使正向加密與會話標籤正確地實現統一,推特不得不寫自己的網路伺服器,這可能不是你想做的事情。
如果 OpenSSL 或所有流行的 Web 伺服器和負載平衡器將開始致力於幫助在默認情況下實現正向加密,伺服器管理員提供保密性就可以擺脫定製前後端的辛苦或黑客了,只需要更換密鑰就行。
[…] 修復正向保密 […]
不錯,不錯,看看了!
謝謝!也歡迎繼續關注LinuxStory其他文章!