Pages

Sunday, 6 September 2015

为nginx配置更安全的SSL证书

现在是时候该升级一下服务器的TLS安全设置了。
对于使用SHA-1签名的证书的网站,唯一的方法是生成更高强度的哈希并重新签名。可以用下面的命令生成新的CSR,并提交给你的CA进行reissue操作:
openssl req -new -key theOriginPrivate.key -out example.com.csr -sha256
好吧,尽管安全要求只是至少升级到SHA-2,但干脆直接上SHA-256或者SHA-384算了,反正碰撞的可能性更低,而且现代计算机做个正向计算简直没难度。致使用CNNIC做根证书签名的用户:你们还是赶快换CA吧,CNNIC整个证书链都是SHA-1的,光升级你的CSR没用。
一般的域名验证证书只需通过电子邮件就能验证完成,和申请新证书基本一样。建议取得新的签名证书文件之后不要着急安装,等几个小时再安装。因为新的证书有效期是从重新签名当时起算的,可能有的客户的设备时钟不准,马上换装可能导致他们的设备报告证书不合法。一般新的证书签发后,旧的证书还能继续用三天,三天后负责任的CA会把你的旧证书写到已吊销列表中。
换装了新证书后,顺便找了个叫ssllabs的网站测试https的安全情况,用他们主页上的Test Your Server功能可以测试你的网站https的安全性和兼容性。测试结果里Signature algorithm一栏透露了证书的签名算法,我的已经是SHA256了。
nginx使用OpenSSL作为底层加密库,所以影响安全性的Cipher Suites设定至关重要,如果设置得安全性极高,可能失去对早期版本浏览器的兼容性而流失用户;反之如果设置的安全性过低,又会陷用户于易受攻击的状态并被新版浏览器嫌弃。在cipherli.st上提供了包括nginx在内的常用Web服务器安装设置,可惜这些设置对早期版本的浏览器兼容得不太好,几经周拆和尝试,我终于敲定使用以下设置:
ssl_certificate /etc/ssl/public.crt;
ssl_certificate_key /etc/ssl/private.key;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
ssl_ciphers EECDH+AESGCM:AES256+EECDH:EDH+AESGCM:AES256+EDH:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
其中第三行那个dhparam的设置,是因为nginx会自动使用OpenSSL默认的1024位的DH Pool,这在现在已被认为是不安全的,所以需要自己生成一个新的2048位的DH Pool。
openssl dhparam -out /etc/ssl/certs/dhparams.pem 2048
本来cipherli.st推荐的是4096位的DH Pool,这当然能更安全,但无奈Java 7并不支持超过2048位的DH Pool,所以只好退而求其次,所幸2048位的DH Pool也算阶段性安全。
上面的配置并不支持Windows XP上的IE6,考虑到IE6默认设置只能用已经被证实有重大安全问题的SSL3.0,而坚持不升级的用户多半也不知道https为何物,更不知道怎么把TLS1.0打开,所以还是放弃这些用户吧.