题外话
也算是一波三折,这个博客迁移到了阿里云ECS上。从虚机到“弹性Web托管”再到云服务器,估计这个博客也就安稳下来了,魔改还在继续,但服务器恐怕不会再迁移了。
在服务器上装了Nginx,配置了HTTPS和HTTP2,也是碰到了许多坑,这篇文章也算是一个简单的记录,目标是拿到SSL Lab的A+评分。
我有懒癌,小白速退。
在最最最前面
如果你有一台全新的云服务器,并且准备安装Nginx,不管有没有打算开HTTPS和HTTP2,尽可能安装Nginx 1.10.2+,也可以安装1.11.x的主线版本,并在编译Nginx的时候加入HTTP2模块,同时在编译 Nginx 时指定 OpenSSL 源码目录(1.0.2+),而不是使用系统自带的版本,这样可以开启ALPN,保证在新的浏览器上也能使用HTTP2。就算暂时不打算开启,谁知道你以后需不需要呢...
这样编译Nginx就能加入HTTP2模块和SSL模块:
./configure --with-http_v2_module --with-http_ssl_module
也可以加入其他模块,看你的需求了。
开始
其实非常简单,搞到你的证书,然后在Nginx配置server块里加上SSL就好了。
listen 443 ssl; ssl_certificate key.csr; ssl_certificate_key key.key;
但是现在访问HTTP还是未加密,除非手动输入HTTPS。于是加入跳转解决来问题:
if ($server_port !~ 443){ rewrite ^/.*$ https://$host$uri; }
同样放在server块里,不过从评论了解到 Nginx 官方更推荐另开一个 server 块来解决跳转。
这样就搞定了HTTPS的配置,先去SSL Lab里面溜溜。
???居然只有B?忍不了,于是准备优化。
进一步优化
首先我们要开启HSTS。
科普一下,一般情况下我们输入域名访问网站,若是不指定协议,浏览器会默认使用HTTP协议,然后才因为我们上一节的设置转到HTTPS协议。这就给了中间人攻击可乘之机。
使用HSTS(HTTP严格传输安全),在第一次访问后浏览器就会知道你的站点长时间开启HTTPS。这样,在你指定的过期时间之前浏览器就会在内部强制307到HTTPS,这样就避免了HTTP跳转的问题。
开启HSTS:
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload" always;
max-age
参数规定了这一设定的过期时间, includeSubdomains
参数表明所有子域名也需要开启HSTS,always
参数表明Nginx在任何情况下都会输出这一头部。加入server块即可。
当然需要注意,开启HSTS之后,设置过期之前你站点的证书不能失效,不能试图在服务器端强制走HTTP,这都会导致站点无法访问。
而且开启HSTS后,第一次访问站点仍然会走HTTP转HTTPS,毕竟浏览器不知道嘛。HSTS Preload可以解决这个问题。
谷歌维护了一份HSTS Preload List,且这一列表各大浏览器都承认。在这一列表里的域名浏览器会知道直接使用HTTPS,这样就完全避免了走HTTP。
任何人都可以申请将自己的域名加入这一列表。但如果要想把自己的域名 加进 这个列表,需要满足以下条件:
- 有效的证书
- 将所有 HTTP 流量重定向到 HTTPS
- 确保所有子域名都启用了 HTTPS
- 输出 HSTS 响应头,且
- max-age 至少需要 18 周(10886400 秒)
- 必须指定 includeSubdomains 参数
- 必须指定 preload 参数
而且貌似满足了这些条件申请也不一定通过。Anyway,申请地址(科学上网):https://hstspreload.appspot.com
注意一旦加入这一列表,撤销据说异常困难,只有在你保证可以长时间提供HTTPS服务的情况下才应该申请加入。
至少我是不打算申请了...比较咱小站没必要,何况我的子域名解析到了好几台服务器上,恐怕一时半会儿也不能保证全部HTTPS,慢慢来吧。
下一步是使用更安全的加密算法。
很简单,把这些配置加入server块:
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5; ssl_prefer_server_ciphers on;
这会让服务器使用更强的加密算法(如果客户端支持)。另外建议,直接让服务器关闭对IE 6的连接好了。IE 6只支持部分弱加密算法,应该被淘汰了。
然后开启SSL缓存。
开启SSL缓存可以让浏览器在一定时间里缓存SSL加密。这样,在这段时间里发起的SSL连接就可以减少相当的加密时间,这对减轻服务器和客户端计算压力都有不小的好处。
同样放进server块:
ssl_session_timeout 1d; ssl_session_cache builtin:1000 shared:SSL:10m; ssl_buffer_size 1400;
这样就好了。做到目前这一步,SSL就已经配置好了。最后一步,加入HTTP2。
也是非常简单。更改listen:
listen 443 ssl http2;
这样就开启了HTTP2。注意,Ngnix 1.10.1及以下版本还是不要开启了,会有POST Bug,详见https://imququ.com/post/nginx-http2-post-bug.html
最后重启Ngnix,到SSL Lab里面清除缓存再跑一次:
完美!
当然到了这一步也还是有优化的地方的,比如说加入HTTP Public Key Pinning(HPKP)。然而有些设置实在太麻烦,何况没必要,还会牺牲兼容性,得不偿失...
发表回复