开始之前
正常来说,操作完以下步骤后是不会影响服务器的正常业务的,你的Nginx以及其他功能比如Let’s Encrypt / Certbot 或是其他ACME等功能也应该是能够不受影响正常使用的。
但我们强烈建议,在开始操作之前,针对你的服务器进行一次备份。
优化后的SSL Labs评级
优化后的MySSL评级
STEP1 – 开启HTTP/2配置
HTTP/2 是HTTP协议的的第二个主要版本,HTTP/2 的开发基于SPDY进行跃进式改进,相对于HTTP 1.1 提升了许多性能,改进了多路复用,特别是在需要并行多个请求的时候显著减少了延迟。
在Nginx中开启 HTTP/2 很容易,只需要在原有的nginx配置上增加 http2 标签即可:
# HTTP/1.x
listen 443 ssl;
# HTTP/2
listen 443 ssl http2;
STEP2 – 移除对TLSv1.0/1.1的支持以及增加TLSv1.3 的支持
不看也可以的部分
TLS 1. 0 和TLS 1. 1 是分别于 1996 年和 2006 年发布的老版协议,使用的是弱加密算法和系统。比如SHA-1和MD5,这些算法和系统十分脆弱,存在重大安全漏洞,容易受到降级攻击的严重影响。
2018年10月,苹果、谷歌、Mozilla和微软四大浏览器巨头联合宣布计划会在2020年初取消对TLS 1.0和TLS 1.1的支持。
Chrome、Firefox等浏览器在移除TLS1之前就开始在使用TLS1/1.1的网站上显示“不安全”标识,提示用户HTTPS连接并不像他们想象的那样安全。
在2008年发布了协议的新版TLS 1.2 修复了此前存在的安全性问题,目前受各大主流浏览器支持。
而在2018年新发布的 TLS 1.3 中无论是性能还是安全性都得到了极大的优化,在引入了新的密钥协商机制的同时也优化了数据传输,在建立连接时节省了往返时间。
经过2年多的时间,目前主流浏览器的较新版本已经全面支持 TLS 1.3 ,但是仍有一些浏览器可能不支持TLS 1.3。
TLS1.3浏览器支持情况
但是我们还是建议开启TLS 1.3,同时保留TLS 1.2的支持,这样使用新版本浏览器的用户能够得到更好地体验。
实际操作
首先需要我们确认nginx的版本为Nginx 1.13 以上的版本、OpenSSL为1.1.1以上版本,可以通过 nginx -V
查看。
然后在你的网站Nginx配置中 TLSv1 TLSv1.1 TLSv1.2
修改为 ssl_protocols TLSv1.2 TLSv1.3
即可。
# 原配置
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
# 修改为
ssl_protocols TLSv1.2 TLSv1.3;
完成。
如果你已经完成并生效了,可以直接跳过后面这一部分,直接看STEP3,如果改完未生效的话,
你可能还需要详细的操作指南:
1.需要修改的配置文件
首先我们需要修改nginx配置文件,因此我们需要找到它
可能位于以下位置:
#通用配置
/etc/nginx/nginx.conf
#站点配置
/etc/nginx/sites-available/example.com (或/default /vhost)
#如果你使用lnmp安装包的话可能在这个位置
/usr/local/nginx/conf/nginx.conf
/usr/local/nginx/conf/vhost
如果你使用cerbot的自动配置的话,可能还需要修改:
/etc/letsencrypt/options-ssl-nginx.conf
2.编辑网站的配置文件
在这个:
/etc/nginx/sites-available/example.com (或/default /vhost)
或是
/usr/local/nginx/conf/vhost
位置找到你网站的专属配置,在 server{ listen 443 ssl http2 .... }
下调整你的tls配置:
server
{
listen 443 ssl http2;
listen [::]:443 ssl http2;
#...
# otherconfig
#...
# 调整你的tls配置,删除TLSv1.0,TLSv1.1 增加TLSv1.3:
ssl_protocols TLSv1.2 TLSv1.3;
}
修改完我们检查下配置文件是否有效:
nginx -t
重载 nginx 配置文件:
systemctl reload nginx
或是 service nginx reload
在一些配置中,完成步骤1可能就能够生效了,我们可以在浏览器的控制台中看到它:
也有可能因为浏览器缓存的原因,依旧显示TLS 1.2,我们还可以在SSL Labs 或是MySSL中检查TLS 1.3是否生效。
如果仍未能生效,就继续往下步骤进行:
3.编辑nginx.conf的配置文件
在我们之前修改的配置文件的上一级目录中,可以找到 nginx.conf
打开配置文件,在 http {}
中 找到
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
调整为我们想要的即可:
ssl_protocols TLSv1.2 TLSv1.3;
同样的,修改完我们检查下配置文件是否有效:
nginx -t
重载 nginx 配置文件:
systemctl reload nginx
或是 service nginx reload
那如果在 nginx.conf 中未找到 ssl_protocols
的配置呢?
4.调整Certbot生成的nginx配置文件
如果你使用的是Certbot的一件生成或自动续订 Let’s Encrypt 证书,那可能是Let’s Encrypt一键生成的配置文件中影响了配置,
虽然在nginx.conf 中找不到 ssl_protocols
,但是你或许能看得在末尾几行有:
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
好的,那我们就去找/etc/letsencrypt/options-ssl-nginx.conf
这个文件,打开它:
# This file contains important security parameters. If you modify this file
# manually, Certbot will be unable to automatically provide future security
# updates. Instead, Certbot will print and log an error message with a path to
# the up-to-date file that you will need to refer to when manually updating
# this file.
ssl_session_cache shared:le_nginx_SSL:1m;
ssl_session_timeout 1440m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS";
同样的,我们将其中的
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
调整为我们想要的即可:
ssl_protocols TLSv1.2 TLSv1.3;
然后我们再检查下配置文件是否有效:
nginx -t
重载 nginx 配置文件:
systemctl reload nginx
或是 service nginx reload
还未生效?
通过刚刚我们用 include
判断 letsencrypt
位置的方法,再找找看看是哪个配置影响了?
STEP3 – HSTS支持
不看也行的部分
啥子是HSTS?
HSTS(HTTP Strict Transport Security) HTTP严格传输安全,是一套由互联网工程任务组发布的互联网安全策略机制 [wiki]。
HSTS是由网站发起的,通过强制使用浏览器HTTPS通信,以防止网站被第三方劫持的机制,当用户第一次访问网站后,浏览器可以在获得的请求头中可以得知该网站是长期支持HTTPS的,那么浏览器便可以在后续的一段时间内,将用户向此网站发送的请求全部以HTTPS的方式发送。
那我用重定向跳转的方式不就好啦?
使用301/302重定向确实能够实现功能,但是还不够,浏览器在 每一次 跳转之前会先访问未加密的源地址,这就导致了,用户很容易被劫持。
而HSTS则在用户第一次访问到HTTPS后就被浏览器识别,在之后的一段时间内(可能会是几个月,也可能会是1年)浏览器都会使用https来进行访问此域名甚至是子域名,同时也大大减少了多次重复请求的时间。
另外要注意的是,非加密传输时设置的HSTS字段是无效的,HSTS只能添加在HTTPS的请求头中,同时时间最短不得少于18周(10886400秒)。
增加HSTS支持
增加HSTS支持操作起来也非常简单,只需要在原配置中增加一行:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
就好啦~
栗:
server
{
listen 443 ssl http2;
listen [::]:443 ssl http2;
#...
# otherconfig
#...
# tls
ssl_protocols TLSv1.2 TLSv1.3;
# 增加HSTS支持
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
}
其中 max-age=31536000
指的是你希望浏览器缓存的时间,includeSubDomains
则是指包含子域名,preload
则是HSTS预加载,后面会提到。
增加HSTS预加载支持
可能有的小伙伴会发现,即使配置了HSTS,那么第一次访问依旧可能使用的是未加密的明文访问,依旧有可能会被劫持。
那咋办呢?那么取消80端口的支持吗?
肯定不行,用户在浏览器中一般都是直接输入域名的,而不会再前面加个https:// 再输入域名内容。
那如何防止第一次访问时的域名劫持呢?
答案则是:HSTS preload
HSTS preload 最早是chromium中的一个列表,目前受到各大主流浏览器Chrome, Firefox, Opera, Safari, IE 11 以及 Edge 的支持。
在HSTS preload中的站点,将会在第一次输入地址并发送请求时,就使用安全的HTTPS连接,这样一来,麻麻再也不用担心我们的网站被劫持啦,同时也节省去了一次请求的时间。
HSTS preload 配置起来也非常简单,在前面配置好HSTS的前提下,前往hstspreload提交我们的网站即可~
ps. 必须在 add_header Strict-Transport-Security
字段中含 includeSubDomains; preload
才可提交成功。
hstspreload
提交完后,将会在一段时间后生效。
STEP4 – 启用OCSP stapling 减小延迟
不看也行部分
在用户访问HTTPS站点时,浏览器在向目标站点发送请求的同时还会向数字证书认证机构(CA)进行OCSP查询以获得证书的状态,但如果查询的地址响应较慢或是未响应的情况下将会影响到用户的访问体验,特别是使用 Let’s Encrypt 的情况下,的Let’s Encrypt 的海外服务器 属性可能会导致OCSP查询影响到用户的体验。
解决方法就是 OCSP stapling。通过服务器来缓存OCSP查询的信息,然后在用户访问的时候,一并返回查询信息,这样一来浏览器就只要验证证书的有效性,而不需要再向CA发送OCSP请求了。
启用OCSP stapling
操作起来也很简单,只需要在原配置中增加以下内容即可:
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
参考资料
本文部分内容参考了以下资料
https://libre-software.net/tls-nginx
https://segmentfault.com/a/1190000039073842
https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/
https://dev.to/sonica/hsts-preloading-using-nginx-letsencrypt-and-capistrano-18l7