启用 ssl_verify_client = on 的 Nginx 不会使 TLS 握手失败

启用 ssl_verify_client = on 的 Nginx 不会使 TLS 握手失败

我有 Nginx 1.10ssl_verify_client = on一切正常,只是服务器完成 TLS 握手并继续解析标头,即使客户端尚未发送证书。

可以通过发送没有客户端证书和非常大的 http 头的 http 请求来验证,nginx 返回“400 请求标头或 Cookie 太大“。

根据我们的安全审计员的说法,服务器应该无法进行 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;
    } }

答案1

我认为您需要要求使用 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 且主机名与您的其他服务器块之一匹配的请求。

相关内容