Nginx

帶有 ssl_verify_client = on 的 Nginx 不會使 TLS 握手失敗

  • March 18, 2021

我有ssl_verify_client = on的 Nginx 1.10 。一切正常,除了伺服器完成 TLS 握手並繼續解析標頭,即使客戶端尚未發送證書。

可以通過發送沒有客戶端證書的http請求和極大的http頭來驗證,nginx返回“ 400 Request Header Or Cookie Too Large ”。

根據我們的安全審計員的說法,伺服器應該無法通過 TLS 握手,因為解析標頭“增加了可能的攻擊面。

我的 nginx 配置:

server {
   listen 443 ssl default_server;
   listen [::]:443 ssl default_server;

   server_name myserver.com;

   ssl_certificate /etc/letsencrypt/live/myserver.com/fullchain.pem;
   ssl_certificate_key /etc/letsencrypt/live/myserver.com/privkey.pem;

   ssl_verify_client on;
   ssl_client_certificate /etc/nginx/ssl/ca.pem;

   location / {
           proxy_pass       http://127.0.0.1:8001;
           proxy_set_header Host      $host;
           proxy_set_header X-Real-IP $remote_addr;
   } }

我認為您需要要求使用 SNI 以避免標頭檢查。Nginx 必須確定伺服器塊是否與請求匹配,為此,它需要一個主機名。它可以在 TLS 握手期間從 SNI 獲取主機名,但如果不使用 SNI,則需要從 http 標頭中讀取主機資訊。

您可以通過為拒絕這些連接的非 SNI 客戶端請求設置預設伺服器塊處理程序來要求使用 SNI。為此,請default_server從主 ssl 伺服器塊中刪除該指令,並在其上方添加一個顯式預設伺服器,該伺服器 1) 偵聽 443,2) 匹配沒有主機名的請求,並且 3) 始終返回 444。範例:

server {
 listen 443 ssl default_server;
 listen [::]:443 ssl default_server;
 server_name   "";

 ssl_ciphers aNULL;
 ssl_certificate /path/to/dummy.crt;
 ssl_certificate_key /path/to/dummy.key;

 return 444;
}

server {
 listen 443 ssl;
 listen [::]:443 ssl;

 server_name myserver.com;

 ssl_certificate /etc/letsencrypt/live/myserver.com/fullchain.pem;
 ssl_certificate_key /etc/letsencrypt/live/myserver.com/privkey.pem;

 ssl_verify_client on;
 ssl_client_certificate /etc/nginx/ssl/ca.pem;

 location / {
       proxy_pass       http://127.0.0.1:8001;
       proxy_set_header Host      $host;
       proxy_set_header X-Real-IP $remote_addr;
} }

然後預設伺服器處理任何不使用 SNI 的 SSL 請求。444返回是關閉連接的nginx非標準程式碼。這種結構還關閉了一個潛在的安全漏洞,預設伺服器的證書可以以意想不到的方式暴露資源。現在 nginx 將只處理使用 SNI 並且主機名與您的其他伺服器塊之一匹配的請求。

引用自:https://serverfault.com/questions/846498