一 復習與目標
1 復習
- 簡單密碼學、對稱加密與非對稱加密
- 數字簽名、數字證書
- SSL/TLS
- HTTPS = HTTP + SSL/TLS,SSL/TLS為HTTP提供了保密性、完整性和鑒別性
2 目標
- TCP性能調優
- TLS性能調優
注:調優提前說明是擔心講完H2、WebSocket協議,導致前面的協議忘的差不多了,所以提前學習,提前使用上(偏重實戰)。
二 TCP性能調優
1 性能檢查清單
- 服務器內核升級到最新版本(Linux:3.7 +)
- 確保啟動窗口縮放;
- 確保cwnd大小為 10:
- 禁用空閑后的慢啟動;
- 減少傳輸冗余數據;
- 壓縮要傳輸的數據;
- 把服務器放到離用戶近的地方以減少往返時間(CDN);
- 盡最大可能重用已經建立的 TCP 連接:啟動TFO。
2 上述優化詳解
(1)服務器內核升級
-
TCP的最佳實踐以及影響其性能的底層算法一直在與時俱進,但是大多數變化都只在最新內核中才有實現。
-
希望使用TCP的最佳實踐和優化算法,則需要升級內核。
(2)啟動窗口縮放:RFC 1323
- TCP的Window Size(rwnd,Receiver Window)起初只有65535字節。
- 1992年RFC 1323添加Window Scale選項,將其提升到了1G字節。
- Window Size太小時,在帶寬延遲積很高的網絡中,TCP無法獲取最優性能。
# 檢查是否開啟,一般默認開啟
$> sysctl net.ipv4.tcp_window_scaling
# 開啟指令
$> sysctl -w net.ipv4.tcp_window_scaling=1
(3)增大初始擁塞窗口:RFC 6928
- initcwnd起初默認為1,1999年RFC 2581將其增加到4,2013年RFC 6928提高到10。
- 當cwnd=10,一次RTT就能發送10個MSS大小的TCP報文。即相比cwnd=1,發送速度翻了10倍。
注:cwnd用於控制發送速度(一次RTT能發送多少個報文段),MSS用於控制單個報文段的大小。
(4)慢啟動重啟(Slow-Start Restart)
- 連接空閑一定時間后重置連接的擁塞窗口,即設置cwnd為初始值。
# 查看
$> sysctl net.ipv4.tcp_slow_start_after_idle
# 禁用
$> sysctl -w net.ipv4.tcp_slow_start_after_idle=0
(5)TCP快速打開(Tcp Fast Open): RFC 7413
- 在某些條件下,允許在第一個SYN 分組中發送應用程序數據。TFO是一種新的優化選項,需要客戶端和服務器共同支持。
# 查看
$> sysctl net.ipv4.tcp_fastopen
# 修改
$> sysctl -w net.ipv4.tcp_fastopen=3
# nginx 編譯時添加
--with-cc-opt=-DTCP_FASTOPEN=23
# nginx.conf配置
listen 443 ssl http2 fastopen=3 reuseport default_server;
注:yum或者apt-get可以使用重新編譯替換來升級nginx
- 下載nginx源碼
- 編譯 ./configure 添加需要的模塊或者配置
- make
- 復制objs目錄下的nginx替換/usr/sbin/nginx
3 知識點補充
(1)Linux下查看socket統計信息:ss
# 顯示所有連接
$ ss | less
# TCP連接過濾出來
$ ss -at
# 打印進程名和進程號
$ ss -ltp
# 打印統計概要
$ ss -s
# 顯示目的端口是443或80的套接字
$ ss -nt '( dst :443 or dst :80 )'
# 具體請自行查詢資料
(2)帶寬延遲積
- BDP(Bandwidth-delay product,帶寬延遲積):數據鏈路的容量與其端到端延遲的乘積。這個結果就是任意時刻處於在途未確認狀態的最大數據量。
- 帶寬延遲積取決於擁塞窗口(cwnd)和接收窗口(rwnd)的最小值,帶寬延遲積(1次RTT內) = Math.min(rwnd * window scale,cwnd * MSS)
- 實驗1:帶寬不重要!
- 假設MSS = 1460,cwnd = 10,那么一次RTT內的最大數據量為1460 * 10 約16KB,RTT為100ms
- 帶寬 = 16 KB / 0.1 s= 1 310 720 bit/s = 1.31 Mbit/s
- 即當前狀態即使增加帶寬,也無法使得TCP數據交換速度提升。
- 實驗2:請開啟窗口縮放!
- 不開啟窗口縮放時,rwnd最大值為64KB
- 假設現在RTT為100ms,網絡可用帶寬為10Mbit/s,理論帶寬延遲積為100ms * 10Mbit/s = 122.1KB
- 但是實際帶寬延遲積最大值為64KB,遠遠小於122.1KB,所以需要開啟窗口縮放來提升rwnd的大小。
(3)隊首阻塞(HOL,Head of Line)
- TCP 分組都會帶着一個唯一的序列號被發出,而所有分組必須按順序傳送到接收端。
- 如果中途有一個分組沒能到達接收端,那么后續分組必須保存在接收端的TCP 緩沖區,等待丟失的分組重發並到達接收端。
- 這一切都發生在TCP 層,應用程序對TCP 重發和緩沖區中排隊的分組一無所知,必須等待分組全部到達才能訪問數據。
- 在此之前,應用程序只能在通過套接字讀數據時感覺到延遲交付。這種效應稱為TCP 的隊首阻塞。
三 SSL/TLS性能調優
1 性能檢查清單
- 要最大限制提升 TCP 性能,參考第二章;
- 把 TLS 庫升級到最新版本,在此基礎上構建(或重新構建)服務器;
- 復用Session:會話緩存和無狀態恢復;
- 在接近用戶的地方完成 TLS 會話,盡量減少往返延遲(CDN);
- 配置 TLS 記錄大小,使其恰好能封裝在一個TCP段內:超出一個段將分段發送,效率變低,使用對的算法使TLS記錄又短又安全;
- 確保證書鏈不會超過擁塞窗口的大小,從信任鏈中去掉不必要的證書,減少鏈條層次;
- 禁用服務器的 TLS 壓縮功能;
- 啟用服務器對 SNI 的支持;
- 啟用服務器的 OCSP 封套功能;
- 追加 HTTP 嚴格傳輸安全首部。
2 上述優化詳解
(1)升級TLS庫
- TLS1.3能提供更快的訪問速度,更強的安全性
# 升級openssl 1.1.0
# 查看版本
openssl version -a
# 下載編譯安裝 https://blog.csdn.net/kadwf123/article/details/80809004
# nginx升級到1.13並配置開啟即可
(2)復用Session
-
概述:復用Session能夠實現簡化握手
- 減少了CPU消耗,因為不需要進行非對稱密鑰交換的計算。
- 提升訪問速度,不需要進行完全握手階段二,節省了一個 RTT 和計算耗時。
-
Session Cache(會話緩存)
- 概述:使用 client hello 中的 session Identifier查詢服務端的 session cache, 如果服務端有對應的緩存,則直接使用已有的 session 信息(加密套件和密鑰)提前完成握手,稱為簡化握手。
- 缺點:
- 消耗服務端內存來存儲 session 內容
- nginx,apache 只支持單機多進程間共享緩存,不支持多機間分布式緩存
- 優點:
- session id 是 TLS 協議的標准字段,市面上的瀏覽器全部都支持 session cache
- 開啟:
# nginx開啟 # builtin a cache built in OpenSSL; used by one worker process only # shared a cache shared between all worker processes ssl_session_cache builtin:1000 shared:SSL:10m;
-
Session Ticket(無狀態恢復)
- 概述:server 將 session 信息加密成 ticket 發送給瀏覽器,瀏覽器后續握手請求時會發送 ticket,server 端如果能成功解密和處理 ticket,就能完成簡化握手。類似java servlet中session與token。
- 缺點:
- session ticket 只是 TLS 協議的一個擴展特性,目前的支持率不是很廣泛,只有 60% 左右。
- session ticket 需要維護一個全局的 key 來加解密,需要考慮 KEY 的安全性和部署效率。
- 開啟:
# 開啟session ticket # 具體設置請參考nginx官網 ssl_session_tickets on; ssl_session_timeout 60m;
- 抓包
Handshake Protocol: New Session Ticket Handshake Type: New Session Ticket (4) Length: 198 TLS Session Ticket Session Ticket Lifetime Hint: 3600 Session Ticket Length: 192 Session Ticket: e3ed09ee89745302e35a2d829ac825504460b4d7e7f94c9a...
-
分布式情況
- Seesion綁定:把相同的客戶端 IP 或相同的 TLS 會話 ID 路由到同一台服務器可以最好地利用會話緩存;
- 緩存共享:在不適宜使用“單一”負載均衡策略的情況下,應該為多台服務器配置共享緩存,以便最好地利用會話緩存;
(3)證書鏈優化
-
驗證信任鏈需要瀏覽器遍歷鏈條中的每個節點,從站點證書開始遞歸驗證父證書,直至信任的根證書。
-
如果證書鏈長度超過了TCP 的初始擁塞窗口,無意間就會讓握手多了一次往返:服務器停下來等待客戶端的ACK 消息。
-
盡量減少中間證書頒發機構的數量 。
-
很多站點會在證書鏈中包含根證書頒發機構的證書,這是完全沒有必要的。(瀏覽器的信任名單中可能沒有該根證書)
-
理想的證書鏈應該在2 KB 或3 KB 左右,同時還能給瀏覽器提供所有必要的信息,避免不必要的往返或者對證書本身額外的請求。
(4)禁用TLS 壓縮
- TLS 內置的小功能,就是支持對記錄協議傳輸的數據進行無損壓縮。
- 缺點:
- “CRIME”攻擊會利用 TLS 壓縮恢復加密認證 cookie,讓攻擊者實施會話劫持
- 傳輸級的 TLS 壓縮不關心內容,可能會再次壓縮已經壓縮過的數據(圖像),雙重壓縮會浪費服務器和客戶端的CPU 時間
- 大多數瀏覽器會禁用TLS 壓縮
注:抱歉這個也沒找到如何禁用...
(5)服務器名稱指示(SNI)
- 如何希望一個公有IP地址(同一端口:443)中使用多個虛擬主機(多個域名)就需要使用SNI。
- TLS 協議的拓展,允許客戶端在握手之初就指明要連接的主機名。Web 服務器可以檢查SNI 主機名,選擇適當的證書,繼續完成握手。
注:具體參考:https://blog.csdn.net/xifeijian/article/details/56012586
(6)應用層協議協商(NPN和ALPN)
-
TLS 層的擴展,用於協商應用層使用的協議。它的前身是 NPN,最初用於支持 Google SPDY 協議(現已標准化為 HTTP/2)。 TLS 客戶端和服務器版本的問題,導致 SPDY->HTTP/2 和 NPN -> ALPN 的切換。
-
NPN 是服務端發送所支持的HTTP協議列表,由客戶端選擇(Server Hello);而 ALPN 是客戶端發送所支持的 HTTP 協議列表,由服務端選擇(Client Hello);
-
NPN 的協商結果是在Change Cipher Spec之后加密發送給服務端;而ALPN的協商結果是通過Server Hello明文發給客戶端;
-
NPN
# Server Hello截取報文
Extension: next_protocol_negotiation (len=12)
Type: next_protocol_negotiation (13172)
Length: 12
Next Protocol Negotiation
Protocol string length: 2
Next Protocol: h2
Protocol string length: 8
Next Protocol: http/1.1
- ALPN
# Client Hello截取報文
Extension: application_layer_protocol_negotiation (len=14)
Type: application_layer_protocol_negotiation (16)
Length: 14
ALPN Extension Length: 12
ALPN Protocol
ALPN string length: 2
ALPN Next Protocol: h2
ALPN string length: 8
ALPN Next Protocol: http/1.1
# Server Hello截取報文
Extension: application_layer_protocol_negotiation (len=5)
Type: application_layer_protocol_negotiation (16)
Length: 5
ALPN Extension Length: 3
ALPN Protocol
ALPN string length: 2
ALPN Next Protocol: h2
(7)OCSP stapling
- CRL(Certificate Revocation List,證書撤銷名單)是RFC 5280 規定的一種檢查所有證書狀態的簡單機制:每個證書頒發機構維護並定期發布已撤銷證書的序列號名單。
- OCSP(Online Certificate Status Protocol,在線證書狀態協議),提供了一種實時檢查證書狀態的機制。
- 與CRL包含被撤銷證書的序列號不同,OCSP 支持驗證端直接查詢證書數據庫中的序列號,從而驗證證書鏈是否有效。總之,OCSP 占用帶寬更少,支持實時驗證。
- OCSP要求CA站點必須處理實時查詢,CA站點可能網絡不穩定,RTT比較大。於是OCSP stapling實現不直接向 CA 站點請求 OCSP 內容。
- 原理:瀏覽器發起 client hello 時會攜帶一個 certificate status request 的擴展,服務端看到這個擴展后將 OCSP內容直接返回給瀏覽器,完成證書狀態檢查。
# Nginx開啟OCSP stapling
ssl_stapling on;
# 具體參考:https://imququ.com/post/why-can-not-turn-on-ocsp-stapling.html
# 抓包
Certificate Status
Certificate Status Length: 471
OCSP Response
responseStatus: successful (0)
responseBytes
ResponseType Id: 1.3.6.1.5.5.7.48.1.1 (id-pkix-ocsp-basic)
BasicOCSPResponse
signature: 560a859a0126b0dc08e3f9a7431056bdf10de99e4e6a6d34...
......
(8)HTTP嚴格傳輸安全(HSTS)
- HTTP 嚴格傳輸安全(HSTS,Strict Transport Security)是一種安全策略機制,它能讓服務器通過簡單的HTTP 首部(如Strict-Transport-Security: max-age=31536000)上述對適用的瀏覽器聲明訪問規則。
- 所有對原始服務器的請求都通過 HTTPS 發送;
- 所有不安全的鏈接和客戶端請求在發送之前都應該在客戶端自動轉換為 HTTPS;
- 萬一證書有•錯誤,則顯示錯誤消息,用戶不能回避警告;
- max-age 以秒為單位指定 HSTS 規則集的生存時間(例如,max-age=31536000 等於緩存365 天);
- 用戶代理可以根據指令在指定的證書鏈中記住某主機的指紋,以便將來訪問時使用,從而有效限制證書頒發機構在特定時間(由max-age 指定)內可頒發證書的范圍。(可選的)。
# Nginx 配置
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
(9)加密套件選擇
-
非對稱密鑰交換算法。建議優先使用 ECDHE,禁用 DHE,次優先選擇 RSA。
-
證書簽名算法。由於部分瀏覽器及操作系統不支持 ECDSA 簽名,目前默認都是使用 RSA 簽名,其中 SHA1 簽名已經不再安全,chrome 及微軟 2016 年開始不再支持 SHA1 簽名的證書 。
-
對稱加解密算法。優先使用 AES-GCM 算法,針對 1.0 以上協議禁用 RC4( rfc7465)。
-
內容一致性校驗算法。Md5 和 sha1 都已經不安全,建議使用 sha2 以上的安全哈希函數。
參考: