SNI是什么
在使用TLS的時候,http server希望根據HTTP請求中HOST的不同,來決定使用不同的證書。
SNI細節
由於HTTP的HOST字段在HTTP GET中。而TLS的握手以及證書驗證都是在HTTP開始之前。
這個時候,TLS協議的HELLO字段中增加了一個server name字段,讓HTTP的client的可以提前
設置HOST,從而使server在tls的握手階段可以選擇證書。
然后,這個機制本身可以拋開http不關心,只要TLS client提前設置了server name,便可以實現SNI
nginx的配置
檢測nginx是否支持sni,http://nginx.org/en/docs/http/configuring_https_servers.html#Server%20Name%20Indication
$ nginx -V
...
TLS SNI support enabled
...
啟用了sni的nginx,如下變量會被賦值
$ssl_server_name
證書命令ssl_certificate,也可以通過變量進行設置,形如:
ssl_certificate $ssl_server_name.crt;
ssl_certificate_key $ssl_server_name.key;
於是我們可以通過 nginx config中的嵌入邏輯,完成sni的完整配置。
如:
stream { upstream test { server 127.0.0.1:50001; } map $ssl_server_name $sni_string { test1.www.local test1; test2.www.local test2; test3.www.local test3; default test1; } map $ssl_server_name $sni_string445 { test1.www.local test4451; test2.www.local test4452; test3.www.local test4453; default test4451; } server { listen 444 ssl; ssl_certificate /data/sni/sni_${sni_string}.cer; ssl_certificate_key /data/sni/sni_${sni_string}.key; proxy_pass test; } server { listen 445 ssl; ssl_certificate /data/sni445/sni_${sni_string445}.cer; ssl_certificate_key /data/sni445/sni_${sni_string445}.key; proxy_pass test; } }
注意,如果希望map命令支持host的最長匹配與正則,需要再添加hostnames關鍵字。
http://nginx.org/en/docs/http/ngx_http_map_module.html#map
map命令的本質,可以理解為通過舊的變量定義出了一個新的變量。
模擬tcp客戶端的方法:
openssl s_client -connect t9:5000 -CAfile ~/Keys/https/root/root.cer -servername test2.www.local
[openssl][nginx] 使用openssl模擬ssl/tls客戶端測試nginx stream
模擬http客戶端的方法:
curl --cacert ~/Keys/https/root/root.cer -vvvv https://test1.tls.local/ curl --cacert ~/Keys/https/root/root.cer -vvvv https://test2.tls.local/ curl --cacert ~/Keys/https/root/root.cer -vvvv https://test3.tls.local/ curl --cacert ~/Keys/https/root/root.cer -vvvv https://test3.www.local/