Nginx 配置 SSL 开启 完全向前加密 PFS 、HSTS实现 https 访问
从今年 7 月份发布的 Chrome 68 开始,Chrome 将所有的 http 网站都标识成了「不安全网站」,本文介绍 Nginx 开启 PFS、HSTS 的方法。这可能是目前最详细最安全的 Nginx SSL 安全配置
因为懒,博客的 ssl 证书申请了一年,现在都过期了,还是没有配置 https
之前私以为,一个博客而已,https 什么的不重要,不过现在的地级运营商经常进行 http 劫持,也是有必要开启 https 了。
- 阮一峰对HTTPS的介绍:《SSL/TSL协议运行机制的概述》
- 关于 HSTS 的详细介绍 看这里
SSL 配置过程
1. 申请 SSL 证书
之前捞了腾讯云不少好处(1元学生机、免费域名、CDN),所以这次也在腾讯云上申请了免费的 DV SSL 证书。
腾讯云提供的 SSL 来自 「亚洲诚信 TrustAsia」
TrustAsia 是国内一家新兴的 SSL 证书提供商,赛门铁克(Symantec)亚太区的白金合作伙伴。随着 Symantec 的 CA 业务被 DigiCert 收购完成,其证书链也从 Symantec 变为 DigiCert。现在也开始提供免费 1 年期的 DV SSL 证书。
在线申请网址:https://freessl.org/
亚信的 SSL 认证可以通过腾讯云的 DNS 解析一键完成,十分方便,人工认证的速度也很快,大概需要 10 分钟左右,审核通过之后腾讯云会有短信提示。
除了 TrustAsia 之外,Let's Encrypt 也是一个很好的选择,虽然有效期只有 3 个月,但是到期可以通过脚本自动续期,无需人工干预。而且 Let's Encrypt 的证书签发不需要人工审核,签发十分快速。
官方网站:https://letsencrypt.org/ 点评:毫无疑问,Let’s Encrypt 是目前使用范围最为广泛的免费 SSL 证书,而且官方博客宣布,自 2018 年开始提供通配符 SSL 证书,也就是 wildcard certificates。这对于广大个人站长来说,无疑是个不错的利好消息。唯一的缺憾就是,Let’s Encrypt 发行的证书有效期只有 3 个月,虽然可以通过定时任务来自动续期。 如何申请?可以通过安装 LNMP 后,使用 lnmp ssl 命令来自动创建 SSL 证书。也可以通过以下在线申请网站,手动申请证书。
在线申请网址1(中文):https://freessl.org/
在线申请网址2(英文):https://www.sslforfree.com/
在线申请网址3(英文):https://gethttpsforfree.com/
通过腾讯云申请到 TrustAsia 的证书之后,直接点击下载,得到一个压缩包,压缩包里面已经有了常用的 Web 服务器的证书,包括 Apache、IIS、Nginx、Tomcat。
在这里我们配置 Nginx 的 SSL ,解压后将 Nginx 文件夹内的内容上传到服务器任意位置
2. 完全向前加密 PFS
完全向前保密(Perfect Forward Secrecy,PFS)使用 「会话密钥(Session Key)」在会话结束后就过期。「会话密钥」是一个长期密钥(Long-Term Key)的衍生出来的密钥,不会透露额外的密钥。所以,简单来说,黑客今天截取一些通讯资料,明天或者有更好更快的机器帮助他解密,就算破解到这个「会话密钥」,他也只能看到这个会话的内容,其他的通讯是不能用这个已破解的密钥来解密。如果你没有使用 PFS,一旦解密密钥被破解,网站的加密也统统给破解掉了。
加密的HTTP通信可以保护传输中的数据不被窃取和修改,这样做看似无懈可击,但其实还是有风险。 传输过程中的信息是经过加密后的密文,在没有秘钥的情况下想要破解出原始信息,要么暴力破解,要么直接针对加密算法进行分析和破解,无论采取哪种方式,其成本都是非常高的,于是就有人转变思路,先把这些加密的HTTP通信录制下来,虽然目前无法对其解密,但是5年后,10年后,甚至经过更长的时间之后,用来对这些HTTP通信数据进行加密的秘钥有可能因为各种方式泄露出来,到那个时候就可以很容易的把这些录制下来的通信解密了。这可不只是停留在理论阶段,事实上美国国家安全局(NSA)已经在这么做了。
接下来的内容需要你对TSL有所了解,虽然没必要弄清楚TSL中的每一个细节,但至少得知道建立TSL连接最开始的时候发生了,建议可以先看看这篇阮一峰对HTTPS的介绍:《SSL/TSL协议运行机制的概述》文章。如果实在懒得去看的话,也不必担心,我会尽量用简单易懂的文字来介绍这种“延时类”的攻击是如何得手的,以及为什么完全向前保密(PFS)能防止这类攻击。
详细的关于 PFS 的介绍可以看这里:http://wmaintw.github.io/2015/03/07/perfect-forward-secrecy.html
因为 PFS 使用了『迪菲-赫尔曼加密法』,所以需要一些额外的配置。
- 需要生成一个 dhparam.pem 文件。这个文件在 DH 握手时会跟传给客户端。这是「DHE加密法」需要用上的东西。
- 告诉 Nginx 使用不要使用默认的加密算法。
dhparam.pem 生成
# 生成 dhparam.pem 文件, 在[命令行]^(Command-line)执行任一方法:
# 方法1: 很慢
openssl dhparam -out dhparam.pem 2048
# 方法2: 较快
# 与方法1无明显区别. 2048位也足够用, 4096更强
openssl dhparam -dsaparam -out dhparam.pem 4096
在服务器上通过上面任一条指令,随机生成 dhparam.pem 文件
选择使用的加密算法
推荐访问:https://mozilla.github.io/server-side-tls/ssl-config-generator/
会基于不同服务器版本生成不同增强型 ssl config,看配置是禁用了SSLv3,启用完全向前加密 PFS,并加入 HSTS 特性支持。出于兼容性和安全性考虑,推荐使用 Intermediate 兼容性配置
当然,如果你的网站需要兼容 Windows XP IE6, Java 6 的话,需要选择 Old 配置
3. Nginx 的配置 以及 HSTS
编辑你得 nginx.conf 文件,在其中加入上面生成的两个 server 配置
注意: 如果你使用的是 lnmp.org 的 lnmp 一键安装包,那么 nginx.conf 的位置在
/usr/local/nginx/conf
,但是,为了方便管理,不推荐直接编辑 nginx.conf 文件如果你之前通过 lnmp 配置过 vhost,并生成了 conf 文件,你需要删除 server 配置中的 监听端口
listen 80
然后在 server 配置的其他内容前粘 https://mozilla.github.io/server-side-tls/ssl-config-generator/ 生成的配置server { listen 80; listen [::]:80; # Redirect all HTTP requests to HTTPS with a 301 Moved Permanently response. return 301 https://$host$request_uri; } server { listen 443 ssl http2; listen [::]:443 ssl http2; # certs sent to the client in SERVER HELLO are concatenated in ssl_certificate ssl_certificate /path/to/signed_cert_plus_intermediates; ssl_certificate_key /path/to/private_key; ssl_session_timeout 1d; ssl_session_cache shared:SSL:50m; ssl_session_tickets off; # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits ssl_dhparam /path/to/dhparam.pem; # intermediate configuration. tweak to your needs. ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 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_prefer_server_ciphers on; # HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months) add_header Strict-Transport-Security max-age=15768000; # OCSP Stapling --- # fetch OCSP records from URL in ssl_certificate and cache them ssl_stapling on; ssl_stapling_verify on; ## verify chain of trust of OCSP response using Root CA and Intermediate certs ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates; resolver <IP DNS resolver>; .... }
以下是对配置文件的部分内容说明
-
ssl_certificate:证书链,如果是 TrustAsia 证书,填写你的 .crt 文件路径
-
ssl_certificate_key:私钥,如果是 TrustAsia 证书,填写你的 .key 文件路径
你的私钥,一定要保密,最好chown+chmod限制只有http server可以读取!
-
ssl_dhparam: DHE 秘钥路径,填写刚才生成的 dhparam.pem 路径
- ssl_trusted_certificate:
是用来验证ocsp响应的各个ca证书+中级证书,和信任的ca根证书列表。这个文件在centos里面是/etc/ssl/certs/ca-bundle.trust.crt
注意!如果你配置了多个 vhost 请注意每一个开启了 ssl 的 vhost 的以下字段必须是相同的,否则会出现 nginx 无法启动,或者 Chrome 报错 ERR_SSL_PROTOCOL_ERROR 的情况
ssl_session_timeout 1d; ssl_session_cache shared:SSL:50m; ssl_session_tickets off;
-
add_header Strict-Transport-Security max-age=15768000;
这行配置 HSTS ,当第一次以 https 方式访问网站,nginx 则会告知客户端的浏览器,以后即便地址栏输入http,也要浏览器改成https来访问我的nginx服务器。
-
resolver :指定 dns 解析服务器,可以指定多个 DNS 并重置域名 TTL 延长 nginx 解析缓存来保障解析成功率:
resolver 223.5.5.5 223.6.6.6 1.2.4.8 114.114.114.114 valid=3600s;
4. 更多安全配置
添加以下配置到 Nginx 的 conf 文件中,可以使浏览更加安全
来源:https://gist.github.com/fotock/9cf9afc2fd0f813828992ebc4fdaad6f
# 不发送Nginx版本号
server_tokens off;
# 不允许浏览器在frame或iframe中显示页面
# 避免 点击劫持(clickjacking) http://en.wikipedia.org/wiki/Clickjacking
# 如果需要允许 [i]frames, 你可以用 SAMEORIGIN 或者用ALLOW-FROM uri 设置单个uri
# https://developer.mozilla.org/en-US/docs/HTTP/X-Frame-Options
add_header X-Frame-Options SAMEORIGIN;
# 服务用户提供的内容时, 包含 X-Content-Type-Options: nosniff 头选项,配合 Content-Type: 头选项,
# 来禁用某些浏览器的 content-type 探测.
# https://www.owasp.org/index.php/List_of_useful_HTTP_headers
# 当前支持 IE > 8 http://blogs.msdn.com/b/ie/archive/2008/09/02/ie8-security-part-vi-beta-2-update.aspx
# http://msdn.microsoft.com/en-us/library/ie/gg622941(v=vs.85).aspx
# 火狐 '不久'支持 https://bugzilla.mozilla.org/show_bug.cgi?id=471020
add_header X-Content-Type-Options nosniff;
# 启用大部分现代浏览器内置的 the Cross-site scripting (XSS) 过滤.
# 通常缺省情况下已经启用, 所以本选项为为本网站重启过滤器,以防其被用户禁用.
# https://www.owasp.org/index.php/List_of_useful_HTTP_headers
add_header X-XSS-Protection "1; mode=block";
# 启用 Content Security Policy (CSP) (和支持它的浏览器(http://caniuse.com/#feat=contentsecuritypolicy)后,
# 你可以告诉浏览器它仅能从你明确允许的域名下载内容
# http://www.html5rocks.com/en/tutorials/security/content-security-policy/
# https://www.owasp.org/index.php/Content_Security_Policy
# 修改应用代码, 通过禁用css和js的 'unsafe-inline' 'unsafe-eval' 指标提高安全性
# (对内联css和js同样适用).
# 更多: http://www.html5rocks.com/en/tutorials/security/content-security-policy/#inline-code-considered-harmful
网站安全性能检测
配置好 Nginx SSL 之后,可以通过 SSLLabs 检测网站安全情况
https://www.ssllabs.com/ssltest/index.html
按照上述方法配置之后,网站能获得 A+ 的安全评级。
还是不够安全?
缺点
HSTS并不是HTTP会话劫持的完美解决方案。用户首次访问某网站是不受HSTS保护的。这是因为首次访问时,浏览器还未收到HSTS,所以仍有可能通过明文HTTP来访问。如果他们通过HTTP访问HSTS保护的网站时:
- 以前从未访问过该网站
- 最近重新安装了其操作系统
- 最近重新安装了其浏览器
- 切换到新的浏览器
- 切换到一个新的设备如移动电话
- 删除浏览器的缓存
- 最近没访问过该站并且max-age过期了
由于HSTS会在一定时间后失效(有效期由max-age指定),所以浏览器是否强制HSTS策略取决于当前系统时间。部分操作系统经常通过网络时间协议更新系统时间,如Ubuntu每次连接网络时,OS X Lion每隔9分钟会自动连接时间服务器。攻击者可以通过伪造NTP信息,设置错误时间来绕过HSTS。
解决这个不足目前有两种方案
-
是浏览器预置HSTS域名列表,Google Chrome、Firefox、Internet Explorer和Spartan实现了这一方案。google坚持维护了一个“HSTS preload list”的站点域名和子域名,并通过https://hstspreload.appspot.com/提交其域名。该域名列表被分发和硬编码到主流的web浏览器。客户端访问此列表中的域名将主动的使用HTTPS,并拒绝使用HTTP访问该站点。
一旦设置了STS头部或者提交了你的域名到HSTS预加载列表,这是不可能将其删除的。这是一个单向的决定使你的域名通过HTTPS可用的。 - 是将HSTS信息加入到域名系统记录中。但这需要保证DNS的安全性,也就是需要部署域名系统安全扩展。截至目前这一方案没有大规模部署。
以下内容来自简书
Tips :如何加入到HSTS Preload List
根据官方说明,你的网站在具备以下几个条件后,可以提出申请加入到这个列表里。
- 具备一个有效的证书
- 在同一台主机上提供重定向响应,以及接收重定向过来的HTTPS请求
- 所有子域名均使用HTTPS
- 在根域名的HTTP响应头中,加入HSTS Header,并满足下列条件:
- 过期时间最短不得少于18周(10886400秒)
- 必须包含
includeSubDomains
参数- 必须包含
preload
参数当你准好这些之后,可以在HSTS Preload List的官网上提交申请,或者了解更多详细的内容。
Tips :如何查询域名是否加入到了Preload List
从提交申请到完成审核,成功加入到内置列表 ,中间可能需要等待几天到几周不等的时间。可通过官网 https://hstspreload.org 或在Chrome地址栏里输入
chrome://net-internals/#hsts
查询状态
_(:3 」∠)_