今年以来看到越来越多的网站启用了 HTTPS,同时在前一段时间看到 WoSign 有免费的 SSL 证书,所以就趁着这个机会,通过一早上的折腾,将服务器上面的 nginx 重新编译了下,支持 SSL 和 spdy 协议,后来又在机缘巧合下 35 块拿下一个 5 年的泛域证书(通配符证书),这样我就全站基本都启用了 HTTPS,但是利用SSL保护你的网站流量远远不止是在服务器安装一个SSL证书而已,所以在安装了 SSL 证书后需要一系列的配置,让这个 SSL 证书真正发挥作用,下面通过 SSLLabs 的测试介绍下我 SSL 现在的配置。

下面是我的博客在配置完后 SSLlabs 的 测试结果,达到了 A+ 。(分数会有浮动,和所测试的浏览器支持度相关)

测试结果

SSL 配置

编译 Nginx 和 openssl

直接给出我的配置吧,由于时间原因,可能下载的源码包不是最新的版本。

wget http://nginx.org/download/nginx-1.6.1.tar.gz
wget http://www.openssl.org/source/openssl-1.0.1i.tar.gz
tar -zxvf nginx-1.6.1.tar.gz
tar -zxvf openssl-1.0.1i.tar.gz

./configure \
    --prefix=/usr/local \
    --user=nginx \
    --group=nginx \
    --sbin-path=/usr/local/sbin/nginx \
    --conf-path=/etc/nginx/nginx.conf \
    --error-log-path=/var/log/nginx/error.log \
    --http-log-path=/var/log/nginx/access.log \
    --pid-path=/var/run/nginx.pid \
    --lock-path=/var/lock/nginx.lock \
    --with-http_ssl_module \
    --with-http_stub_status_module \
    --with-http_gzip_static_module \
    --with-http_spdy_module \
    --http-client-body-temp-path=/var/tmp/nginx/client/ \
    --http-proxy-temp-path=/var/tmp/nginx/proxy/ \
    --http-fastcgi-temp-path=/var/tmp/nginx/fcgi/ \
    --http-scgi-temp-path=/var/tmp/nginx/scgi/ \
    --http-uwsgi-temp-path=/var/tmp/nginx/uwsgi/ \
    --with-openssl=../openssl-1.0.1i

make
make install

开启 ssl 和 spdy

这里就是直接在 nginx 主机的配置相应位置添加如下配置:

# 更改之前的 80 端口
listen 443 ssl spdy;

# 开启 SSL
ssl on;

# 添加 ssl 证书和 ssl 私钥
ssl_certificate       /certificate-path/blog.alphatr.com.crt;
ssl_certificate_key   /certificate-path/blog.alphatr.com.key;

ssl 证书链

ssl 证书链就是在上一步 ssl_certificate 的文件中不仅要有你自己的证书,还要有中间的证书机构的证书。

SSL 优化

因为使用 SSL,所以服务器 CPU 这里要多一些加密计算的开销,所以需要对服务器这里进行优化;还有就是要对服务器的安全设置优化,达到最大效用。

性能优化

性能优化这里针对 SSL 会话的缓存大小和缓存过期时间进行优化;可以根据自己的实际情况来设置,我这里缓存大小设置为 20M,大概能放下 80000 个会话,缓存时间是 20 分钟;

ssl_session_cache    shared:SSL:20m;
ssl_session_timeout  20m;

SSL 协议设置

我使用的是 Nginx,在 SSL 协议这里默认支持的是 SSLv3, TLSv1, TLSv1.1, TLSv1.2(需要 OpenSSL 支持,针对近两三年的 Nginx 版本),因为 SSLv3 的一些安全问题,还有 TLSv1 的浏览器支持基本没有问题了,所以可以直接禁用掉,(当然 TLSv1 也有安全问题,但是 TLSv1.1 支持有限,所以这里暂时先保留着)。

在 Nginx 配置文件 http 区块里面使用 ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 这样来声明支持的协议版本。

加密方式设置

SSL 加密设置

加密协议这里主要是关闭一些简单的加密方式,这里比较纠结的就是 RC4 了,因为广泛的支持,所以还是保留 RC4,但是这里是 RC4-SHA 即使用 RC4 但不使用 SHA 的算法。同时开启 ssl_prefer_server_ciphers 设置服务器加密方式优先于客户端。

完整的设置如下

ssl_prefer_server_ciphers On;
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-RC4-SHA:ECDHE-RSA-RC4-SHA:ECDH-ECDSA-RC4-SHA:ECDH-RSA-RC4-SHA:ECDHE-RSA-AES256-SHA:RC4-SHA:HIGH:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!CBC:!EDH:!kEDH:!PSK:!SRP:!kECDH;

OCSP 装订(OCSP stapling)

OCSP 装订(OCSP stapling)指的是服务器向 OCSP 验证服务器请求验证,将证书保存下来,浏览器请求时候直接通过自己的服务器发送回去,防止验证服务器出问题,还能加快访问速度。

这部分折腾了好久,主要是参考资料比较少,而且大部分文章都是没有经过实践的。

下面是别的一些网站上面的配置,ssl_trusted_certificate 文件和证书链文件基本类似;

ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /certificate-path/trustchain.crt;

我参考这样配置是始终配置不好,发现好像 Nginx 不会自动将证书下载下来,需要手动下载;

所以还有要添加以下的步骤:

查看 OSCP 验证服务器地址

在 shell 中执行 openssl x509 -in /certificate-path/trustchain.crt -text 其中替换为你自己的证书链文件,在输出的文字中找到 OCSP – URI:,后面的 URL 就是 OSCP 的验证服务器地址。

请求 OSCP 证书

同样执行 openssl 命令,模拟请求,注意还是替换成自己的证书路径和验证服务器地址;

openssl ocsp -noverify \
             -issuer /certificate-path/trustchain.crt \
             -cert /certificate-path/trustchain.crt \
             -url http://ocsp2.globalsign.com/gsalphasha2g2

不出意外会收到如下的结果

trustchain.crt: good
   This Update: Oct 18 17:59:10 2014 GMT
   Next Update: Oct 18 23:59:10 2014 GMT

如果出现 403 错误,那就需要在 Header 请求头加上域名参数 -header "HOST" "ocsp2.globalsign.com",没问题后就可以直接保存下来证书文件,完整的命令如下:

openssl ocsp -noverify \
             -issuer /certificate-path/trustchain.crt \
             -cert /certificate-path/trustchain.crt \
             -url http://ocsp2.globalsign.com/gsalphasha2g2 \
             -header "HOST" "ocsp2.globalsign.com"
             -text -respout ./stapling_file.ocsp

将保存下来的 stapling_file.ocsp 证书添加到 nginx 的配置中,如下,Nginx 中配置变成了这样子:

ssl_stapling on;
ssl_stapling_verify on;
ssl_stapling_file /stapling_file.ocsp;
ssl_trusted_certificate /certificate-path/trustchain.crt;

这样子重启 Nginx 后就会生效,可以使用下面的命令测试生效结果:

echo QUIT | openssl s_client -connect blog.alphatr.com:443 -status 2> /dev/null | grep -A 17 'OCSP response:' | grep -B 17 'Next Update'

看到 OCSP Response Status: successful 这样的字样就是成功了。

最后,在参考文档中看到个问题,还待验证,但是这个问题也好解决,crontab 自己去跑就行了。

ocsp证书有效期很短,大概不到一个月,所以过段时间要更新ocsp证书,不然还是会验证失败。

HTSP

HTSP 就是添加 header 头,告诉浏览器网站使用 HTTPS 访问,这样支持的浏览器就会在后面的请求中直接切换到 HTTPS。在 Chrome 中看到浏览器自己会有个 307 Internal Redirect 的本地重定向,配置如下,max-age 是缓存时间,单位秒;另外再配置一个 301 的重定向。

server {
    listen       80;
    server_name  blog.alphatr.com;
    add_header   Strict-Transport-Security max-age=157680000;
    return       301 https://blog.alphatr.com$request_uri;
}

常见的 SSL 漏洞

最后简单介绍几个和 SSL 相关的安全问题,包括今年早些时候轰动一时的心脏出血,还有最近爆出来的 SSLv3 的 POODLE,还有就是 BEAST,具体可以看看相关文档。

BEAST

BEAST 是一个利用 SSLv3, TLSv1 上面的漏洞对 ssl 加密本身进行破解,然后篡改通信数据的攻击方式,就是上文提到的 SSLv3, TLSv1 的安全问题,解决办法就是使用 TLSv1.1 及更高的版本,但是浏览器支持都不好(SSL及 TLS 支持情况)所以这里只是暂时禁用 SSLv3,当 RC4 与 TLSv1 结合时候也不会受到攻击,但 RC4 是弱加密,所以这里还是根据自己的实际情况来配置。

心脏滴血

心脏滴血是一个 OpenSSL 的内存溢出漏洞。SSL 连接中,在客户端和服务器之间有一个心跳连接,用来保持 SSL 会话,但是这个连接没有请求长度限制,攻击着利用这样的请求构造很大的值发送给服务器,服务器会发生内存溢出后返回 64k 的内存值,因为是服务端的漏洞,和客户端没有关系,所以也好修复,直接升级 OpenSSL 就可以。

POODLE

这个漏洞是前段时间 Google 员工在 SSLv3 的版本中发现的漏洞,是 SSLv3 协议缺陷导致,具体的漏洞详情可以看参考文档的介绍。防止措施也简单,就是关闭 SSLv3 的支持。

参考文档