Nginx Web服务应用实战
2、HTTPS安全服务器的搭建
互联网应用为我们提供了丰富的信息内容,在给我们带来方便的同时也影响着我们的生活方式。随着人们对网络的依赖不断增强,安全问题变得愈发重要,各种加密技术应运而生。SSL协议是20世纪90年代由Netscape公司提出的,后由ITEL接管并进行标准化,更名为TLS协议,TLS1.0就是SSL 3.1版本。HTTPS(HyperText TransferProtocol Secure,超文本传输安全协议)是在HTTP的基础上增加了SSL协议,为数据传输提供了身份验证和加密功能。使用HTTPS协议可验证用户客户端和服务器的身份,确保数据可以在正确的用户客户端和服务器间传输。因为HTTPS协议的数据传输是加密的,所以在传输过程中可以有效防止数据被窃取和修改,从而保障网络信息的安全。Nginx的HTTPS协议服务是通过 ngx_http_ssl_module模块实现的,在配置编译参数时需要添加--with-http_ssl_module参数启用该功能。
2.1、配置指令
Nginx HTTPS配置指令如表所示。


-
1)上述指令都可编写在http、server指令域中。
-
2)ssl_ciphers指令值的内容是OpenSSL参数ciphers的内容,可通过如下命令查看。
bashopenssl ciphers # 列出OpenSSL支持的密码套件 openssl ciphers -v 'ALL:eNULL' # 列出指定密码套件详情 -
3)密码套件格式及说明可参见OpenSSL相关文档。
-
4)ssl_session_cache指令值参数如下。
- off:禁用HTTPS会话缓存。
- none:启用伪会话缓存支持,Nginx告知客户端可进行会话重用,但服务端并未存储会话参数。
- builtin:使用内置OpenSSL缓存机制,无法在Nginx的多个工作进程中共享缓存内容。
- shared:使用Nginx的共享缓存机制,会在Nginx的多个工作进程中共享缓存内容,1MB内存可以存储4000个会话。
2.2、HTTPS基本配置
HTTPS协议数据的传输是基于SSL层加密的数据,其简单模型是服务端获得客户请求后,将用私钥加密的协商数据发送给客户端。客户端先使用服务端提供的公钥解密协商数据并读取真实的内容,再用公钥加密返回协商数据并发送给服务端,完成彼此间的密钥协商。密钥协商完毕后,服务端和客户端通过协商后的密钥进行通信数据的加解密传输。私钥只存放在服务端,公钥则由所有的客户端持有。
在实际使用过程中,为提高公钥的使用安全性、防止公钥被替换,使用第三方CA机构的证书实现对服务器身份的认证和网站公钥的安全传递。HTTPS先通过非对称加密方式交换密钥,建立连接后再通过协商后的密钥与加密算法进行对称加密数据传输。图5-3为HTTPS时序图。

- 1)服务端按照自身的域名等身份信息创建网站证书私钥和网站证书申请文件,网站管理员将证书申请文件提交给CA机构并获得网站证书,网站证书和网站证书私钥被部署到服务端。
- 2)客户端发送包含协议版本号、客户端随机数(ClientRandom)、支持加密套件列表的请求给服务端。
- 3)服务端获得客户端HTTPS请求后,将包含网站信息及网站证书公钥的证书、服务端随机数(Server Random)及随机选择的客户端支持加密套件返回给客户端,若需要验证客户端身份,也会在此时发送相关信息给客户端。
- 4)客户端通过操作系统中的CA公钥解密证书获取网站证书公钥并进行网站证书的合法性、有效期和是否被吊销的验证。
- 5)客户端用网站证书公钥将新生成的客户端随机数加密后发送给服务端,同时使用3个随机数生成会话密钥。
- 6)服务端使用网站证书私钥解密客户端数据获取客户端随机数(Pre-master),使用3个随机数生成会话密钥。
- 7)服务端与客户端使用一致的会话密钥和加密算法完成传输数据的加解密交互。
HTTPS网站证书是由CA机构颁发的,网站管理员只需按照相关流程向CA机构提交请求文件即可,操作步骤如下。
-
(1)生成请求文件
生成请求文件的脚本如下:
bash## 创建无密码网站证书私钥文件的请求文件 openssl req -out /etc/nginx/conf/ssl/www_nginxbar_org.csr -new -sha256 -newkey rsa:2048 -nodes -keyout /etc/nginx/conf/ssl/www_nginxbar_org.key -subj "/C=CN/ST=Shanghai/L=Shanghai/O=nginxbar/OU=admin/CN=nginxbar.com/emailAddress=admin@nginxbar.com" ## 创建有密码私钥文件的请求文件 openssl genrsa -aes256 -passout pass:111111 -out /etc/nginx/conf/ssl/www_nginxbar_org.key 2048 openssl req -out /etc/nginx/conf/ssl/www_nginxbar_org.csr -new -sha256 -nodes -passin pass:111111 -key /etc/nginx/conf/ssl/www_nginxbar_org.key -subj "/C=CN/ST=Shanghai/L=Shanghai/O=nginxbar/OU=admin/CN=nginxbar.com/emailAddress=admin@nginxbar.com" ## 保存私钥密码 echo "111111" >>/etc/nginx/conf/ssl/www_nginxbar_org.pass- 网站证书私钥文件是否需要密码由用户自行选择,只需选择一种方式执行即可。
-
(2)获取证书文件
将www_nginxbar_org.csr文件提交给CA机构后,即可获得Nginx支持的PEM格式证书文件。
CA机构为方便进行证书管理,通常会以证书链的方式进行网站证书的颁发与验证,证书链通常由网站证书、中间证书与根证书组成。证书链的验证是由网站证书开始、自下而上进行信任验证传递的。根证书通常存放在客户端,吊销根证书的过程非常困难;中间证书只是增加了一个中间验证环节,可以减少CA机构对根证书的管理维护工作,吊销也相对简单。除了向CA机构申请证书外,也可以自签证书在内部使用,自签证书操作如下:
bash## 创建独立站点使用的自签证书 openssl req -new -x509 -nodes -out /etc/nginx/conf/ssl/www_nginxbar_org.pem -keyout /etc/nginx/conf/ssl/www_nginxbar_org.key -days 3650 -subj "/C=CN/ST=Shanghai/L=Shanghai/O=nginxbar/OU=admin/CN=nginxbar.com/emailAddress=admin@nginxbar.com" ## 创建独立站点使用有密码的网站证书私钥文件的自签证书 openssl genrsa -aes256 -passout pass:111111 -out /etc/nginx/conf/ssl/www_nginxbar_org.key 2048 openssl req -new -x509 -nodes -out /etc/nginx/conf/ssl/www_nginxbar_org.pem -passin pass:111111 -key /etc/nginx/conf/ssl/www_nginxbar_org.key -days 3650 -subj "/C=CN/ST=Shanghai/L=Shanghai/O=nginxbar/OU=admin/CN=nginxbar.com/emailAddress=admin@nginxbar.com" ## 保存私钥密码 echo "111111" >>/etc/nginx/conf/ssl/www_nginxbar_org.pass ## 创建自签客户端证书 openssl req -new -x509 -nodes -out /etc/nginx/conf/ssl/client.pem -keyout /etc/nginx/conf/ssl/client.key -days 3650 -subj "/C=CN/ST=Shanghai/L=Shanghai/O=nginxbar/OU=admin/CN=nginxbar.com/emailAddress=admin@nginxbar.com" ## 转换客户端证书为可被浏览器导入的pkcs12格式 openssl pkcs12 -export -clcerts -in /etc/nginx/conf/ssl/client.pem -inkey /etc/nginx/conf/ssl/client.key -out /etc/nginx/conf/ssl/client.p12获得网站证书后,可以按照如下方式配置HTTPS站点。
bashserver { listen 443 ssl; # 启用HTTPS支持 server_name www.nginxbar.org; charset utf-8; root /opt/nginx-web; index index.html index.htm; ssl_certificate ssl/www_nginxbar_org.pem; # HTTPS网站证书 ssl_certificate_key ssl/www_nginxbar_org.key; # HTTPS网站证书私钥 ssl_password_file ssl/www_nginxbar_org.pass; # HTTPS网站证书私钥密码文件 }
2.3、HTTPS密钥交换算法
在HTTPS建立连接进行密钥交换阶段,可以通过多种密钥交换算法实现密钥交换。基于RSA的密钥交换过程是客户端把第3个随机数发送给服务端,但在HTTPS建立连接阶段的传输仍是明文的,会存在安全问题。DH(Diffie-Hellman)密钥交换算法可保证通信双方在明文传输的环境下安全地交换密钥。基于DH的密钥交换过程是在服务端产生服务端随机数后,将DH参数和密钥交换服务端公钥加密后传递给客户端,客户端根据DH参数和密钥交换服务端公钥计算出第3个随机数,并把自己产生的密钥更换为客户端公钥发送给服务端,服务端依据密钥交换客户端公钥计算出第3个随机数并完成后续的操作。椭圆曲线的DH(ECDH)密钥交换算法与DH交换算法相似,但使用了不同的数学模型。在使用椭圆曲线的DH密钥交换时,服务器会为密钥交换指定一条预先定义好参数的曲线,Nginx的ECDH密钥交换默认配置的是prime256v1曲线算法。配置样例如下:
bash
server {
listen 443 ssl;
server_name www.nginxbar.org;
charset utf-8;
root /opt/nginx-web;
index index.html index.htm;
ssl_certificate ssl/www_nginxbar_org.pem;
ssl_certificate_key ssl/www_nginxbar_org.key;
ssl_password_file ssl/www_nginxbar_org.pass;
ssl_dhparam ssl/dhparam.pem; # DH参数文件
ssl_ecdh_curve auto; # ECDH椭圆曲线算法为prime256v1
}
DH参数文件可通过如下命令生成。
bash
openssl dhparam -out /etc/nginx/conf/ssl/dhparam.pem 2048
基于DH的密钥交换算法也称前向加密(Forward Secrecy)或完全前向加密(Perfect Forward Secrecy),其应用场景是即便日后服务器的SSL私钥被第三方获得,后者也无法推算出会话密钥。
2.4、HTTPS会话缓存
HTTPS建立连接时传递证书及协商会话密钥会占用一定资源,为加快HTTPS建立连接的速度,提升性能,TLS协议使用了会话缓存机制。会话缓存机制可以使已经断开连接的HTTPS会话重用之前的协商会话密钥继续HTTPS数据传输。会话缓存机制有两种实现方式:会话编号(SessionID)和会话凭证(Session Ticket)。
-
(1)会话编号
服务端在与客户端进行数据传输时,会为每次会话生成一 个会话编号,并存储该会话编号与会话协商数据。HTTPS会话中断需要重新连接时,客户端将最后一次会话的会话编号发送给服务端,服务端检查存储中该编号是否存在,如果存在就与客户端使用原有的会话密钥进行数据传输。配置样例如下:
bashserver { listen 443 ssl; server_name www.nginxbar.org; charset utf-8; root /opt/nginx-web; index index.html index.htm; ssl_certificate ssl/www_nginxbar_org.pem; ssl_certificate_key ssl/www_nginxbar_org.key; ssl_password_file ssl/www_nginxbar_org.pass; ssl_session_cache shared:SSL:10m; # HTTPS会话缓存存储大小为10MB ssl_session_tickets off; # 以会话编号机制实现会话缓存 ssl_session_timeout 10m; # 会话缓存超时时间为10分钟 }这里作以下两点说明。
-
服务端会存储会话编号和会话协商数据,相对会消耗服务器资源。
-
当Nginx服务器为多台时,无法实现会话共享。
-
-
(2)会话凭证
会话凭证类似于cookie,它将协商的通信数据加密之后发送给客户端保存,服务端只保存密钥。HTTPS建立连接后,服务端发送一个会话凭证给客户端,当需要重新连接时,客户端发送会话凭证与服务端恢复会话连接。配置样例如下:
bashserver { listen 443 ssl; server_name www.nginxbar.org; charset utf-8; root /opt/nginx-web; index index.html index.htm; ssl_certificate ssl/www_nginxbar_org.pem; ssl_certificate_key ssl/www_nginxbar_org.key; ssl_password_file ssl/www_nginxbar_org.pass; ssl_session_cache shared:SSL:10m; # HTTPS会话缓存存储大小为10MB ssl_session_tickets off; # 以会话凭证机制实现会话缓存 ssl_session_timeout 10m; # 会话缓存超时时间为10分钟 ssl_session_ticket_key ssl/session_ticket.key; # 会话凭证密钥文件 }ssl_session_ticket_key可以实现多台Nginx间共用会话缓存,解决了会话缓存共享问题,可通过如下命令生成:
bashopenssl rand 80 > /etc/nginx/conf/ssl/session_ticket.key
2.5、HTTPS双向认证配置
通常网站的HTTPS访问,都是客户端通过证书验证所访问服务器的身份,而服务器对来访的客户端并不做身份验证,也称单向认证。在一些场景中,也会增加客户端身份验证以提高数据传输的安全性,这就是双向认证。配置样例如下:
bash
server {
listen 443 ssl;
server_name www.nginxbar.org;
charset utf-8;
root /opt/nginx-web;
index index.html index.htm;
ssl_certificate ssl/www_nginxbar_org.pem;
ssl_certificate_key ssl/www_nginxbar_org.key;
ssl_password_file ssl/www_nginxbar_org.pass;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_ticket_key ssl/session_ticket.key;
ssl_verify_client on; # 启用客户端证书认证
ssl_client_certificate ssl/ca.pem; # 客户端证书信任链的CA中间证书或根证书
}
2.6、HTTPS吊销证书配置
HTTPS的证书会因安全原因在正常有效期到期前进行证书变更,为了方便客户端或浏览器及时判断当前使用的网站证书是否已被吊销,通常会采用以下两种方式实现:证书吊销列表(CRL)和在线证书协议(OCSP)。
-
(1)证书吊销列表
证书吊销列表是由CA机构维护的列表,列表中包含已被吊销的证书序列号和时间,通常在CA机构证书中都会包含CRL下载地址。证书吊销列表Nginx配置如下:
bashserver { listen 443 ssl; server_name www.nginxbar.org; charset utf-8; root /opt/nginx-web; index index.html index.htm; ssl_certificate ssl/www_nginxbar_org.pem; ssl_certificate_key ssl/www_nginxbar_org.key; ssl_password_file ssl/www_nginxbar_org.pass; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; ssl_session_ticket_key ssl/session_ticket.key; ssl_crl ssl/ca.crl; # 证书吊销列表文件 }- 证书吊销列表可通过查看网站证书字段"CRL分发点"的字段值下载获得。
-
(2)在线证书协议
在线证书协议是一个吊销证书在线查询协议,虽然可以实现实时查询,但同时也会因在HTTPS建立连接时查询OCSP接口引发性能问题。为解决OCSP查询造成的性能影响,引入了OCSP Stapling机制,即由HTTPS服务器查询OCSP接口或本地OCSP缓存,并通过证书状态消息返回给客户端。在线证书协议缓存Nginx配置如下:
bashresolver 114.114.114.114 valid=300s; # DNS服务器地址 resolver_timeout 1s; # DNS解析超时时间为1s server { listen 443 ssl; server_name www.nginxbar.org; charset utf-8; root /opt/nginx-web; index index.html index.htm; ssl_certificate ssl/www_nginxbar_org.pem; ssl_certificate_key ssl/www_nginxbar_org.key; ssl_password_file ssl/www_nginxbar_org.pass; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; ssl_session_ticket_key ssl/session_ticket.key; ssl_stapling on; # 启用OCSP缓存 ssl_stapling_file ssl/ocsp.pem; # OCSP结果缓存文件 ssl_stapling_responder http://ocsp.example.com/; # 设置获取OCSP结果的URL ssl_stapling_verify on; # 设置OCSP结果缓存证书验证 ssl_trusted_certificate ssl/ca.pem; # 网站证书信任证书链的中间证书文件 }注意,OCSP结果缓存文件和获取OCSP结果的URL同时设置时,OCSP结果缓存文件的优先级最高。
OCSP响应结果可通过如下命令获得。
bashopenssl ocsp -issuer /etc/nginx/conf/ssl/ca.pem -cert /etc/nginx/conf/ssl/www_nginxbar_org.pem -no_nonce -text -url http://ocsp.example.com -text -respout /etc/nginx/conf/ssl/ocsp.pem
2.7、HTTPS配置样例
HTTPS通过加密通道保护客户端与服务端之间的数据传输,极大地降低了数据被窃取、篡改的风险,增强了网站对数据安全的保护能力,已成为当前网站建设的必选配置。根据Nginx提供的配置指令,HTTPS配置样例如下:
bash
resolver 114.114.114.114 valid=300s; # DNS服务器地址
resolver_timeout 5s; # DNS解析超时时间为5s
server {
listen 443 ssl;
server_name www.nginxbar.org;
charset utf-8;
root /opt/nginx-web;
index index.html index.htm;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # DNS服务器地址
ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
ssl_prefer_server_ciphers on; # 启用服务端密码组件优先
ssl_dhparam ssl/dhparam.pem; # 设置DH密钥交换算法参数
ssl_ecdh_curve secp384r1; # DH密钥交换椭圆曲线算法为secp384r1
ssl_certificate ssl/www_nginxbar_org.pem; # 网站证书文件
ssl_certificate_key ssl/www_nginxbar_org.key; # 网站证书密钥文件
ssl_password_file ssl/www_nginxbar_org.pass; # 网站证书密钥密码文件
ssl_session_cache shared:SSL:10m; # 会话缓存存储大小为10MB
ssl_session_timeout 10m; # 会话缓存超时时间为10分钟
ssl_session_tickets on; # 设置会话凭证为会话缓存机制
ssl_session_ticket_key ssl/session_ticket.key;# 设置会话凭证密钥文件
ssl_stapling on; # 启用OCSP缓存
ssl_stapling_file ssl/ocsp.pem; # OCSP结果缓存文件
ssl_stapling_verify on; # 设置OCSP结果缓存证书验证
ssl_trusted_certificate ssl/ca.pem; # 网站证书信任证书链的中间证书文件
# 启用HSTS
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header X-Frame-Options DENY; # 禁止被嵌入框架
add_header X-XSS-Protection "1; mode=block"; # XSS跨站防护
add_header X-Content-Type-Options nosniff; # 防止在浏览器中的MIME类型混淆攻击
}
server {
listen 80;
server_name www.nginxbar.org;
rewrite ^(.*)$ https://$host$1? permanent; # 强制HTTP访问跳转为HTTPS访问
}
可以通过网站ssllabs.com对HTTPS的配置进行安全性检测,并按照测试结果有针对性地进行优化。