时间:2023-07-15 00:24:01 | 来源:网站运营
时间:2023-07-15 00:24:01 来源:网站运营
Nginx配置HTTPS详解:前向知识:ngx_http_ssl_module
模块,使用发现版的安装工具默认已安装,自己编译安装如下:$ ./configure --with-http_ssl_module$ make
# 源码目录创建一个tmp目录来存放nginx.conf,access.log$ mkdir tmp# 启动Nginx命令$ objs/nginx -p $(pwd) -c tmp/nginx.conf
SSLKEYLOGTFILE
和Wireshark Pre-Master-Secret log filename指向相同的日志文件$ export SSLKEYLOGFILE=/mnt/c/Users/slynxes/Desktop/sslkey.log
2. 配置Wiresharkdaemon off;pid tmp/nginx.pid;error_log stderr debug;events {}http { access_log tmp/access.log; default_type text/html; server { listen 443 ssl; # SSL 协议版本 ssl_protocols TLSv1.2; # 证书 ssl_certificate ssl/ecc.pem; # 私钥 ssl_certificate_key ssl/ecc.key; return 200 "https ok /n"; }}
ssl_ciphers
套件里面有支持ECDHE的,浏览器自动会使用False Start。# nginx.confdaemon off;pid tmp/nginx.pid;error_log stderr debug;events {}http { access_log tmp/access.log; default_type text/html; server { listen 443 ssl; # SSL 协议版本 ssl_protocols TLSv1.2; # 证书 ssl_certificate ssl/rsa.pem; # 私钥 ssl_certificate_key ssl/rsa.key; # ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384; ssl_ciphers AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256; # 与False Start没关系,默认此项开启,此处减少抓包的干扰而关闭 ssl_session_tickets off; return 200 "https ok /n"; }}
# nginx.confdaemon off;pid tmp/nginx.pid;error_log stderr debug;events {}http { access_log tmp/access.log; default_type text/html; server { listen 443 ssl; # SSL 协议版本 ssl_protocols TLSv1.2; # 证书 ssl_certificate ssl/rsa.pem; # 私钥 ssl_certificate_key ssl/rsa.key; ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384; # ssl_ciphers AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256; # 与False Start没关系,默认此项开启,此处减少抓包的干扰而关闭 ssl_session_tickets off; return 200 "https ok /n"; }}
New Session Ticket
子协议发送给客户端,后续TLS握手时,客户端Client Hello携带Session Ticke,服务端用密钥对Session Ticket进行解密,若解密成功,则直接恢复会话。不再进行后续握手过程。Nginx中Session Ticket Key
可以配置多个,或者不配置,由Nginx自行生成。# Session IDssl_session_cache off | none | [builtin[:size]] [shared:name:size]# Session Ticketssl_session_tickets on | off# 密钥文件,服务器生成Session Ticket需要进行加密,验证时候需要解密。不指定服务器自行生成随机的密钥。# 密钥文件要求80字节的AES256密钥: openssl rand 80 > current.keyssl_session_ticket_key FILE;# 可以配置多个, 保证更换密钥,但不影响以前的解密,顺序从上到下。ssl_session_ticket_key current.keyssl_session_ticket_key previous.key# 设置Nginx可以重复使用session参数时间,包括Session ID, Session Ticketssl_session_timeout time;
daemon off;pid tmp/nginx.pid;error_log stderr debug;events {}http { access_log tmp/access.log; default_type text/html; server { listen 443 ssl; ssl_protocols TLSv1.2; ssl_certificate ssl/rsa.pem; ssl_certificate_key ssl/rsa.key; ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384; # Session Ticket # 可以配置多个密钥,这样做的目的是为了定期更换密钥,保证前向安全性。 # 将更换的密钥配置在上面,Nginx会优先采用上面的密钥进行加/解密, # 若使用旧密钥加密的会话,上面的密钥解密不了,就使用后面的密钥进行解密。 ssl_session_tickets on; ssl_session_ticket_key ./current.key; ssl_session_ticket_key ./previous.key; # Session ID # ssl_session_cache shared:mysession:10m; return 200 "https ok /n"; }}
首次握手 daemon off;pid tmp/nginx.pid;error_log stderr debug;events {}http { access_log tmp/access.log; default_type text/html; server { listen 443 ssl; ssl_protocols TLSv1.2; ssl_certificate ssl/rsa.pem; ssl_certificate_key ssl/rsa.key; ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384; # Session Ticket ssl_session_tickets off; # ssl_session_ticket_key ./current.key; # ssl_session_ticket_key ./previous.key; # Session ID ssl_session_cache shared:mysession:10m; return 200 "https ok /n"; }}
首次握手 # 密码套件# 选择密码套件的顺序是从左到右ssl_ciphers ciphers;# 选择密码套件时,以客户端发送的密码套件的顺序为准,还是以服务端ssl_ciphers配置的顺序为准。# off: 以客户端优先级为准, 默认值# on: 以服务端优先级为准ssl_prefer_server_ciphers on | off# ECC椭圆曲线,不设置Nginx根据OpenSSL选择ssl_ecdh_curve X25519:P-256;# 若使用DHE密钥协商算法需要配置DHE Param, 不配会报错,DHE-Param要求2048bit# 可通过openssl dhparam -out tmp/ssl/dhparam.pem 2048 生成dhparam.pemssl_dhparam tmp/ssl/dhparam.pem;
daemon off;pid tmp/nginx.pid;error_log stderr debug;events {}http { access_log tmp/access.log; default_type text/html; server { listen 443 ssl; ssl_protocols TLSv1.2 TLSv1.3; ssl_certificate ssl/ecc.pem; ssl_certificate_key ssl/ecc.key; ssl_ciphers TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384:TLS_AES_128_CCM_SHA256:TLS_AES_128_CCM_8_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; ssl_prefer_server_ciphers on; ssl_ecdh_curve X25519:P-256; # Session Ticket ssl_session_tickets on; ssl_session_ticket_key ./current.key; ssl_session_ticket_key ./previous.key; # Session ID # ssl_session_cache shared:mysession:10m; return 200 "https ok /n"; }}
daemon off;pid tmp/nginx.pid;error_log stderr debug;events {}http { access_log tmp/access.log; default_type text/html; server { listen 443 ssl; ssl_protocols TLSv1.2 TLSv1.3; ssl_certificate ssl/ecc.pem; ssl_certificate_key ssl/ecc.key; ssl_ciphers TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305; # ssl_prefer_server_ciphers on; # Session Ticket ssl_session_tickets on; ssl_session_ticket_key ./current.key; ssl_session_ticket_key ./previous.key; # Session ID # ssl_session_cache shared:mysession:10m; return 200 "https ok /n"; }}
测试:$ openssl s_client -connect www.xlhtec.com:443 -tls1_2 -cipher 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256' 2>&1 </dev/null | grep CipherNew, TLSv1.2, Cipher is ECDHE-ECDSA-CHACHA20-POLY1305 Cipher : ECDHE-ECDSA-CHACHA20-POLY1305$ openssl s_client -connect www.xlhtec.com:443 -tls1_3 -ciphersuites 'TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256' 2>&1 </dev/null | grep CipherNew, TLSv1.3, Cipher is TLS_CHACHA20_POLY1305_SHA256
ssl_perfer_server_ciphers为on是,以服务端端的密码套件顺序为准ssl_session_tickets on;
测试$ openssl s_client -connect www.xlhtec.com:443 -tls1_2 -cipher 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256' 2>&1 </dev/null | grep CipherNew, TLSv1.2, Cipher is ECDHE-ECDSA-AES128-GCM-SHA256 Cipher : ECDHE-ECDSA-AES128-GCM-SHA256
Strict-Transport-Security
即可,浏览器除了首次访问可能是http,后续将自动转为https进行访问。若首次访问都想让HTTP自动切换为HTTPS,可以加入HSTS Preload List(一个谷歌维护的列表,现在大部分主流浏览器都支持这个列表,这个列表直接告诉浏览器要用 HTTPS 访问的站点有哪些,所以在访问站点之前,浏览器先捞一遍这个列表,如果要访问的站点在这里面,就直接用 HTTPS 进行访问,所以即使是第一次访问,也会走 HTTPS 了。)Strict-Transport-Security: max-age=<expire-time>Strict-Transport-Security: max-age=<expire-time>; includeSubDomainsStrict-Transport-Security: max-age=<expire-time>; preload
# Nginx响应报文中增加头部字段语法# always: 无论响应状态码是多少,都要增加该头部字段add_header name value [always];# 增加 Strict-Transport-Security头部字段add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
New Session Ticket
,并且携带了early_data
。客户端生成PSK$ openssl s_client -connect www.xlhtec.com:443 -tls1_3 -keylogfile=./tls13.log -sess_out=./tls13.sess 2>&1 | grep 'Early data'$ openssl s_client -connect www.xlhtec.com:443 -tls1_3 -keylogfile=./tls13.log -sess_in=./tls13.sess -early_data=./req.txt 2>&1 < /dev/null | grep 'Early data'
# 0-RTTssl_early_data on;# Session Ticketssl_session_tickets off;# ssl_session_ticket_key ./current.key;# ssl_session_ticket_key ./previous.key;# Session IDssl_session_cache shared:mysession:10m;
daemon off;pid tmp/nginx.pid;error_log stderr debug;events {}http { access_log tmp/access.log; default_type text/html; server { listen 443 ssl; ssl_protocols TLSv1.2 TLSv1.3; ssl_certificate ssl/ecc.pem; ssl_certificate_key ssl/ecc.key; ssl_ciphers TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384:TLS_AES_128_CCM_SHA256:TLS_AES_128_CCM_8_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; ssl_prefer_server_ciphers on; ssl_ecdh_curve X25519:P-256; ssl_dhparam ssl/dhparam.pem; # Session Ticket ssl_session_tickets off; # ssl_session_ticket_key ./current.key; # ssl_session_ticket_key ./previous.key; # Session ID ssl_session_cache shared:mysession:10m; # 0-RTT ssl_early_data on; location / { return 200 "https ok /n"; } }}
首次握手 Header + Body
组成,只是将每个请求/应答虚拟成一个Stream。然后将HTTP报文切割成几块,每一块封装成一个二进制帧。一个Stream中的所有二进制帧头部包含相同的Stream ID ,不同Stream中的二进制Stream ID不相同。然后一个TCP连接中多个Stream可以并发请求,服务器也可以并发应答。并且Stream之间相互独立,不存在先后顺序。从而解决了HTTP中队首阻塞的问题。但是一个Stream中的多个二进制帧必须严格按照顺序进行请求/应答。:authority
, :method
,:status
分别表示域名,请求方法,状态码。Encrypted Extensions
扩展字段ALPN中携带h2
PRI * HTTP/2.0/r/n/r/nSM/r/n/r/n
,该过程称为连接首页。后面双方就升级为HTTP/2协议进行通信。listen 443 ssl http2;
daemon off;pid tmp/nginx.pid;error_log stderr debug;events {}http { access_log tmp/access.log; default_type text/html; server { listen 443 ssl http2; ssl_protocols TLSv1.2 TLSv1.3; ssl_certificate ssl/ecc.pem; ssl_certificate_key ssl/ecc.key; ssl_ciphers TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384:TLS_AES_128_CCM_SHA256:TLS_AES_128_CCM_8_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; ssl_prefer_server_ciphers on; ssl_ecdh_curve X25519:P-256; # Session Ticket ssl_session_tickets off; # ssl_session_ticket_key ./current.key; # ssl_session_ticket_key ./previous.key; # Session ID # ssl_session_cache shared:mysession:10m; location / { index index.html; root /tmp/picture; # return 200 "https ok /n"; } }}
升级HTTP/2协议过程 # 开启OCSP stapling ssl_stapling on | off;# Nginx是否需要验证OCSP服务器的响应(比如证书吊销状态)# 若配置为on就需要使用CA的公钥对响应结果解密。# 就需要使用ssl_trusted_certificate指定证书链, # 但若ssl_cetificate中已经包含了完整的证书链,就不用指定了。ssl_stapling_verify on | off;ssl_trusted_certificate FILE;# 若Nginx无法请求到OCSP服务器的响应,比如网络不好等等,也可以自己手动跟新响应,# 然后将响应保存到一个DER格式的文件中,然后指定该文件。ssl_stapling_file DER_FILE; # 自己指定OCSP服务,默认包含在证书中,不用指定。ssl_stapling_responder http://OCSP_SERVER;
daemon off;pid tmp/nginx.pid;error_log stderr debug;events {}http { access_log tmp/access.log; default_type text/html; server { listen 443 ssl http2; ssl_protocols TLSv1.2 TLSv1.3; ssl_certificate ssl/ecc.pem; ssl_certificate_key ssl/ecc.key; ssl_ciphers TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384:TLS_AES_128_CCM_SHA256:TLS_AES_128_CCM_8_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; ssl_prefer_server_ciphers on; ssl_ecdh_curve X25519:P-256; ssl_dhparam ssl/dhparam.pem; # Session Ticket ssl_session_tickets off; # ssl_session_ticket_key ./current.key; # ssl_session_ticket_key ./previous.key; # Session ID ssl_session_cache shared:mysession:10m; # 0-RTT ssl_early_data on; # OCSP stapling ssl_stapling on; location / { return 200 "https ok /n"; } }}
验证$ openssl s_client -connect www.xlhtec.com:443 -status < /dev/null 2>&1 | grep -i "OCSP response"OCSP response:OCSP Response Data: OCSP Response Status: successful (0x0) Response Type: Basic OCSP Response
http { access_log tmp/access.log; default_type text/html; server { listen 443 ssl http2; server_name www.xlhtec.com ssl_protocols TLSv1.2 TLSv1.3; ssl_certificate ssl/www_xlhtec_com_ecc.pem; ssl_certificate_key ssl/www_xlhtec_com_ecc.key; ... } server { listen 443 ssl http2; server_name blog.xlhtec.com ssl_protocols TLSv1.2 TLSv1.3; ssl_certificate ssl/blog_xlhtec_com_ecc.pem; ssl_certificate_key ssl/blog_xlhtec_com_ecc.key; ... }}
若虚拟主机的证书都一样,就不用这么麻烦了,在http {}
块中配置即可http { access_log tmp/access.log; default_type text/html; ssl_protocols TLSv1.2 TLSv1.3; ssl_certificate ssl/ecc.pem; ssl_certificate_key ssl/ecc.key; server { listen 443 ssl http2; server_name www.xlhtec.com ... } server { listen 443 ssl http2; server_name blog.xlhtec.com ... }}
http { access_log tmp/access.log; default_type text/html; server { listen 443 ssl http2; server_name www.xlhtec.com ssl_protocols TLSv1.2 TLSv1.3; ssl_certificate ssl/ecc.pem; ssl_certificate_key ssl/ecc.key; ssl_certificate ssl/rsa.pem; ssl_certificate_key ssl/rsa.key; ... }}
http { log_format main 'ssl_protocol: $ssl_protocol/n' 'ssl_cipher: $ssl_cipher/n' 'ssl_ciphers: $ssl_ciphers/n' 'ssl_curves: $ssl_curves/n' 'ssl_server_name: $ssl_server_name/n' 'ssl_session_id: $ssl_session_id/n' 'http2: $http2/n'; access_log tmp/access.log main; ...}
日志输出$ tail -f tmp/access.logssl_protocol: TLSv1.3ssl_cipher: TLS_AES_256_GCM_SHA384ssl_ciphers: TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA:AES256-SHA:DES-CBC3-SHAssl_curves: X25519:prime256v1:secp384r1:secp521r1:0x0100:0x0101ssl_server_name: www.xlhtec.comssl_session_id: 1d54d0e1009f9a25edb60f95951987762da4e8b3f483873db55fc95a4b1774f4http2: h2
关键词:配置