Https優化方案(服務端優化配置篇--重用Session)
HTTPS的主要缺點是需要設定連線,每次新的TLS連續都需要握手,以便建立共享的加密金鑰,這個握手過程在標準TCP的握手過程之上還需要兩個額外的來回過程,用這樣一個高延時的連線,在網站第一個位元組傳輸之前需要三個來回就讓人感覺這個網站有點慢。
TLS有幾個特徵可以用來消除額外的來回,比如重用一個會話session,兩個標準會話重用機制是 session IDs (RFC
5246) 和 session tickets (RFC
5077),使用其中一個技術,一個客戶端可以重用之前建立的會話,這個會話是之前和伺服器進行握手成功的,這樣可以減少一次來回過程。基於SessionID的會話重用適合現代所有瀏覽器,FireFox和Chrome還支援 session
tickets,伺服器端的支援也廣泛使用,nginx, Apache, HAProxy, IIS等等都支援session ID
和session ticket。
Session ID重用
重用一個加密的會話是很容易,前提是客戶端和伺服器端都儲存了會話key,通過每個連線給出的唯一標識,伺服器知道一個進來的連線是否已經在之前建立過,如果伺服器在會話中也已經有會話key,它就能重用。
Session ID需要伺服器儲存會話狀態如會話key等,這樣下次連線才能複用,這就需要伺服器儲存很多狀態資訊,耗費了大量記憶體。
Session ID共享複用在Apache中可以通過SSLSessionCache 配置,在nginx可以通過ssl_session_cache設定。
Session ticket重用
在會話ticket複用中,伺服器不用為每個session儲存狀態,它用一個blob資料儲存狀態,然後將它發給客戶端用來維護後來連線,會話ticket允許伺服器將其儲存狀態委託給客戶端,類似HTTP cookie一樣。
一個會話ticket是一個加密的資料blob,其中包含需要重用的TLS連線資訊,如會話key等,它一般是使用ticket key加密,因為ticket key伺服器端也知道,在初始握手中伺服器傳送一個會話ticket到客戶端,儲存到客戶端本地,當重用會話時,客戶端傳送會話ticket到伺服器,伺服器解密然後重用會話。
Session Ticket的安全考慮
會話ticket有潛在的安全問題,一些TLS加密元件如ECDHE-RSA-AES128-SHA256提供一個安全屬性成為向前安全forward secrecy,如果黑客獲得了伺服器的證書私鑰,他們也不能獲得會話來破解。
使用TLS 會話ticket,偷竊了ticket key1後不會允許黑客來解密先前的會話,這是的ticket key非常有價值,為了保持向前安全forward secrecy, ticket key應該經常輪換。
會話ticket重用在Apache中可以用SSLTicketKeyDefault 配置,在nginx中使用ssl_session_tickets,它們都沒有自動輪換ticket key的自動機制,只能通過重啟apache nginx來重新載入或建立新的隨機key。
負載平衡
使用負載平衡器時,這些複用技術會遇到挑戰,對於一個伺服器複用一個連線,它需要先前會話的key,如果先前會話在其他伺服器上,新的伺服器必須得到原來會話的key。
這個問題被CloudFlare 和 Twitter使用系統產生一個集中統一的key來解決,ticket key被一個集中的統一的伺服器定期建立,安全地發給所有伺服器,實現會話ticket共享需要你的架構有一個定製系統的抉擇。
總結
降低建立一個連線的來回過程使得網站載入速度提高,對於使用HTTPS的網站,會話儲存可以用於提高連線建立的速度,而正確的實現方式,才能讓頁面載入時間更漂亮的縮短,特別是在有負載平衡的場合 。
如果session ID 和session ticket都在client hello提供時以那個為準起作用?
答案: 以session ticket為準.詳細的解釋如下,
rfc5077 3.4. Interaction with TLS Session ID 做了說明如下:
If a ticket is presented by the client, the server MUST NOT attempt to use the
Session ID in the ClientHello for stateful session resumption.
openssl程式碼中利用session ticket或session ID恢復session的處理實現邏輯:
ssl3_get_client_hello(SSL *s) -->
根據sessionID或ticket查詢session的函式 ssl_get_prev_session()–>
根據ticket解密session資訊tls1_process_ticket()–>
利用全域性ctx ticket_key或應用層即nginx tlsext_ticket_key_cb回撥解密 tls_decrypt_ticket()
如果上述解ticket失敗或沒有ticket則呼叫lh_SSL_SESSION_retrieve() 根據session id取cache中的資訊恢復
如果openssl本身cache中沒找到則根據session id從應用層nginx回撥函式get_session_cb()中查詢;並SSL_CTX_add_session(s->session_ctx, ret);//將外部的cache加入到openssl中
具體操作教程https://blog.csdn.net/supertor/article/details/84849666