网站开启https优化记录

缘起

    最近blog以及fq子域遇到了各种被dns污染,connect reset这些被嫱的问题,于是,全站https提上了日程。之前呢,是把几个子域用了https,这次一部到位,直接全部blog也换成https。


折腾经过

    过程有不少东西,比如开启http2,做301跳转,申请let's encrypt通配符证书(可以参考https://yanke.info/?id=65),之后的一些优化,我参考了下面的过程,算是比较全面的了,转载自作者的这篇文章,thanks。 https://blog.csdn.net/vencent7/article/details/79190249


HSTS(HTTP Strict Transport Security,严格传输安全)

HSTS 简单说就是在一定时间内强制客户端使用 HTTPS 访问页面。原理如下:

这个过程有效避免了中间人对 80 端口的劫持。但是这里存在一个问题:如果用户在劫持状态,并且没有访问过源服务器,那么源服务器是没有办法给客户端种下 Strict-Transport-Security 响应头的(都被中间人挡下来了)。如何解决?请自行谷歌 HSTS preload。

需要注意的是,只有启用 preload 之后才是严格意义上安全的 HTTPS。否则都可能在最薄弱环节被攻破。比如:

不过,即使你启用了 preload 也不是 100% 高枕无忧了,一旦客户端被恶意软件安装了恶意的根证书,这些措施就都没有用了。所以不要轻易安装根证书,不要随意安装可疑软件(尤其在 Windows 上)。比如,Google 曾在
2015 年报告说 CNNIC (中国互联网络信息中心)签发的一个中级 CA 签发了一个伪造的 Google 证书,从而导致 Google 和 Mozilla 在其产品中取消了对 CNNIC 后继签发的证书信任。

如何解决呢?请看后文的 HPKP

开启 HSTS

add_header Strict-Transport-Security "max-age=6307200; includeSubdomains; preload";

以上语句开启了 HSTS,并设置有效期为“6307200秒”(6个月),包括子域名(根据情况可删掉),预加载到浏览器缓存(根据情况可删掉,注意加入后需要向 hstspreload.org 提交申请)。

注意如果要申请preload,所有子域名都必须使用 HTTPS,且max-age至少设置为一年。有关preload的更多信息可以前往上述网址查看。

提醒一下,只有443端口的监听需要设定 HSTS,80端口不需要增加 header。

注意:此处如果不是全部子域名都能支持443,不要设置后面的subdomain和preload,比如我这个域名下边绑了些局域网nas运行的一些网页服务,开启了严格HSTS之后这些子域都不能访问了。


HPKP(Public Key Pinning,公钥固定)

公钥固定(Public Key Pinning)是指一个证书链中必须包含一个白名单中的公钥,也就是说只有被列入白名单的证书签发机构(CA)才能为某个域名*.example.com签发证书,而不是你的浏览器中所存储的任何 CA 都可以为之签发。

用你使用的银行做个例子,它一直使用 CA 公司 A 为其签发证书。但是在当前的证书体系下,CA 公司 B、CA 公司 C 和 NSA 的 CA 都能给你的银行创建证书,而你的浏览器会毫无疑虑的接受它们,因为这些公司都是你所信任的根 CA。

如果你的银行实现了 HPKP 并固定了它们的第一个中级证书(来自 CA 公司 A),那么浏览器将不会接受来自CA 公司 B 和 CA 公司 C 的证书,即便它们也有一个有效的信任链。HPKP 也允许你的浏览器将这种违例行为报告给该银行,以便银行知道被伪造证书攻击了。

听起来很美好。不过:

基于以上种种原因,这项谷歌发起的计划在 2017 年 10 月又被谷歌自己抛弃,并计划于 2018 年 5 月在 Chrome 浏览器中移除对 HPKP 的支持。详细情况可以参见报导。因此,现在没有必要给网站添加对于 HPKP 的支持了

注意:此处建议不要折腾了,没什么作用


DNS CAA 保护

HPKP 废弃之后,是不是就没有办法了呢?好在有 DNS CAA (DNS Certification Authority Authorization,DNS证书颁发机构授权)保护。

DNS CAA 保护可以使域持有人可以指定允许为其域签发证书的 CA。它会在 DNS 下发 IP 的同时,同时下发一条资源记录,标记该域名下使用的证书必须由某证书颁发机构颁发。比如本站使用了 Let’s Encrypt 颁发的免费证书,我可以同时使用 CAA 技术标记本站使用的 SSL 证书必须由 Let’s Encrypt 颁发,这样就可以(在一定程度上)解决上面所述的问题。

并不是所有 DNS 服务器都支持 CAA 保护,支持 CAA 记录的国外 DNS 服务这里有比较详细的记录:https://sslmate.com/caa/support 。国内的话,我使用的 CloudXNS 是支持的。

开启方法

在你的 DNS 服务的后台添加一条 CAA 记录:


注意:经过验证,国内大部分dns不支持,比如dnspod就不支持这个,所以基本上也不能优化


SSL/TLS 协议版本

SSL v2 及以下已经不安全了,请使用 TLS v1 以上版本(TLS 协议是在 SSL v3 协议基础上设计的)。之所以把 SSL v3 也关了是因为 TLS 1.0 会被降级攻击,降级到 SSL v3 之后,我们之前提到的 Forward Secrecy(前向加密)就失效了。另外, SSL v3 存在 POODLE 漏洞,这是关闭它的另一个主要理由。

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

以上语句只允许使用 TLS 协议。

注意:此处强烈建议增加配置,防止加密比较弱的问题


弃用不安全的加密套件

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; # 缓解 BEAST 攻击# 在 SSLv3 or TLSv1 握手时,通常会使用客户端的cipher偏好,打开这个选项后,则会使用服务器的偏好

这里使用的是 CloudFlare’s Internet facing SSL cipher configuration。

cipher 之间用冒号分隔,cipher 前有感叹号的表示必须废弃。以下是必须废弃的:

如果不手动指定加密套件会怎样呢?有关 Nginx 默认算法的安全性,引用官网的一段文字:

Since version 1.0.5, NGINX uses ssl_protocols SSLv3 TLSv1 and ssl_ciphers HIGH:!aNULL:!MD5 by default; since versions 1.1.13 and 1.0.12, the default was updated to ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2.

Vulnerabilities are sometimes found in the design of older ciphers, and you would be wise to disable these in a modern NGINX configuration (unfortunately, the default configuration cannot easily be changed because of concerns of backward compatibility for existing NGINX deployments). Please note that CBC-mode ciphers might be vulnerable to a number of attacks, the BEAST attack in particular (see CVE-2011-3389), and SSLv3 is best avoided unless you need to support legacy clients due to the POODLE attack.


OSCP Stapling

当我们通过HTTPS访问网站的时候,客户端会通过证书颁发机构的证书吊销列表(CRL)或者数字证书在线状态协议(OCSP)记录验证网站服务器的证书是否有效。前一种验证方式是最低效的,CA会不断向CRL文件添加证书吊销记录,CRL文件就会变得越来越大,客户端在验证前就需要耗费越来越长的时间来下载CRL文件。

相比 CRL 验证方式,OCSP 就更加高效,OCSP 每次只查询并获取一条记录。然而这些默认查询 OCSP 的客户端在获得查询结果的响应前势必会一直阻塞后续的事件,在网络情况堪忧的情况下(尤其是大陆地区)会造成较长时间的页面空白。并且一旦有黑客或者组织对CA的OCSP发动DDos攻击,客户端便无法从 OCSP 服务器获取查询结果并完成证书验证, 客户端就可能会提示网站不受信任。

而 OCSP Stapling ,顾名思义,是将查询 OCSP 接口的工作交给服务器来做,服务器除了可以直接查询 OCSP 信息,还可以仅进行少数次查询并将响应缓存起来。当有客户端向服务器发起 TLS 握手请求时,服务器将证书的 OCSP 信息随证书链一同发送给客户端,从而避免了客户端验证会产生的阻塞问题。由于 OCSP 响应是无法伪造的,因此这一过程也不会产生额外的安全问题。

值得注意的是:Nginx会在客户端的HELLO握手信息中返回OCSP记录,并且只有当客户端对Nginx发出OCSP信息请求的情况下,Nginx才会发送缓存的OCSP 权威记录到客户端。

ssl_stapling on;# OCSP Stapling 开启。OCSP是用于在线查询证书吊销情况的服务,使用OCSP Stapling能将证书有效状态的信息缓存到服务器,提高 TLS 握手速度
ssl_stapling_verify on; # OCSP Stapling 验证开启
ssl_trusted_certificate /etc/nginx/cert/trustchain.crt; # OCSP Stapling 的证书位置(完整的证书链)
resolver 233.5.5.5 233.6.6.6 valid=300s; # 用于查询 OCSP 服务器的
DNSresolver_timeout 5s;#查询域名超时时间

注意上述 DNS 是阿里云的,如果不信任的话可以改成 Google 的:8.8.8.8 8.8.4.4 [2001:4860:4860::8888] [2001:4860:4860::8844]

注意:此处的配置,建议和上面保持一致就行,不要使用有的博主说的ssl_stapling_file这个配置,虽然看起来说是服务器不用去请求了,但是实际上需要手工更新ocsp文件,非常麻烦,而上面的配置,可以自动的拉取新的信息。



缓存连接凭据

缓存 SSL 连接凭据可以避免频繁握手带来的速度降低和性能损耗。

TLS 协议有两类会话缓存机制:会话标识 session ID 与会话记录 session ticket。session ID 由服务器端支持,协议中的标准字段,因此基本所有服务器都支持,服务器端保存会话ID以及协商的通信信息,Nginx 中1M 内存约可以保存4000个 session ID 机器相关信息,占用服务器资源较多;而 session ticket 属于一个 TLS 扩展字段,需要服务器和客户端都支持。

二者对比,主要是保存协商信息的位置与方式不同,类似与 HTTP 中的 session 与 cookie。都存在的情况下,Nginx 优先使用 session_ticket。

ssl_session_cache shared:SSL:20m; # SSL session 缓存区大小# 这条语句加在server段里话,在SSL Lab的测试中识别不出来,因为它假设客户端不支持SNI协议,但实际上是可以加在server段的
ssl_session_tickets on;# 开启浏览器的 Session Ticket 缓存
ssl_session_timeout 60m;# 过期时间,分钟

防止 MIME 类型混淆攻击

add_header X-Content-Type-Options nosniff;

301 跳转

跳转到HTTPS,不多说了。

server { 
    listen 80; 
    return 301 https://$host$request_uri; 
}

HTTP/2

尽管 HTTP/2 协议本身并不要求一定开启 SSL,但浏览器要求一定要启用 SSL 才能使用 HTTP/2。要使用 HTTP/2,把 listen directive 改成 listen 443 ssl http2 即可。HTTP/2 是 SPDY 的演进版本,性能上相比 HTTP 1.1 最主要的是增加了多路复用 multiplexing、header 压缩和二进制格式。

server {    listen 443 ssl http2;
    ...
}

可以在谷歌浏览器中打开 chrome://net-internals/#http2 以检查网站是否开启了 HTTP/2。


SSL 测试

最后附上一个常用的测试网站SSL配置问题的网站:SSL Server Test,你可以按照测试结果有针对性的进行优化。不过,不必追求满分。建议测试等级达到 A+、Certificate 100/100、Protocol Support 95/100、Key Exchange 90/100、Cipher Strength 90/100 即可。

不过,它的缓存测试并不假设客户端支持 SNI,所以即便你对某一个 virtual server 开启了 ssl session cache,依然会提示 Session resumption (caching)No (IDs assigned but not accepted)解决方法请看这里

提供另外一个比较好的ssl监测网站,myssl.com,其中的监测也是比较全面的。


参考文档

https://blog.csdn.net/vencent7/article/details/79190249

https://myssl.com

https://www.ssllabs.com/ssltest/index.html

https://imququ.com/post/why-can-not-turn-on-ocsp-stapling.html

https://quchao.com/entry/how-to-configure-ocsp-stapling-on-nginx-for-the-certificates-issued-by-lets-encrypt/



发表评论

必填

选填

选填

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。