增强 nginx 的 SSL 安全性
本文向你介绍如何在 nginx 服务器上设置健壮的 SSL 安全机制。我们通过禁用 SSL 压缩来降低 CRIME 攻击威胁;禁用协议上存在安全缺陷的 SSLv3 及更低版本,并设置更健壮的 加密套件 来尽可能启用 前向安全性
如果不求甚解的话,可以从 https://cipherli.st 上找到 nginx 、Apache 和 Lighttpd 的安全设置,复制粘帖即可。
本教程在 Digital Ocean 的 VPS 上测试通过。如果你喜欢这篇教程,想要支持作者的站点的话,购买 Digital Ocean 的 VPS 时请使用如下链接:https://www.digitalocean.com/?refcode=7435ae6b8212 。
本教程可以通过发布于 2014/1/21 的 SSL 实验室测试的严格要求(我之前就通过了测试,如果你按照本文操作就可以得到一个 A+ 评分)。
- 本教程也可用于 Apache
- 本教程也可用于 Lighttpd
- 本教程也可用于 FreeBSD, NetBSD 和 OpenBSD 上的 nginx ,放在 BSD Now 播客上: http://www.bsdnow.tv/tutorials/nginx
你可以从下列链接中找到这方面的进一步内容:
我们需要编辑 nginx 的配置,在 Ubuntu/Debian 上是 /etc/nginx/sited-enabled/yoursite.com
,在 RHEL/CentOS 上是 /etc/nginx/conf.d/nginx.conf
。
本文中,我们需要编辑443端口(SSL)的 server
配置中的部分。在文末你可以看到完整的配置例子。
在编辑之前切记备份一下配置文件!
野兽攻击(BEAST)和 RC4
简单的说, 野兽攻击
针对 野兽攻击
禁用 RC4 会有几个后果。其一,当用户使用老旧的浏览器时,比如 Windows XP 上的 IE 会用 3DES 来替代 RC4。3DES 要比 RC4 更安全,但是它的计算成本更高,你的服务器就需要为这些用户付出更多的处理成本。其二,RC4 算法能减轻 野兽攻击
怪物攻击(FREAK)
怪物攻击
这个漏洞可上溯到上世纪九十年代,当时美国政府禁止出口加密软件,除非其使用编码密钥长度不超过512位的出口加密套件。
这造成了一些现在的 TLS 客户端存在一个缺陷,这些客户端包括: 苹果的 SecureTransport 、OpenSSL。这个缺陷会导致它们会接受出口降级 RSA 密钥,即便客户端并没有要求使用出口降级 RSA 密钥。这个缺陷带来的影响很讨厌:在客户端存在缺陷,且服务器支持出口降级 RSA 密钥时,会发生中间人攻击,从而导致连接的强度降低。
攻击分为两个组成部分:首先是服务器必须接受“ 出口降级 RSA 密钥
中间人攻击可以按如下流程:
- 在客户端的 Hello 消息中,要求标准的 RSA 加密套件。
- 中间人攻击者修改该消息为 ‘输出级 RSA 密钥’
( 。 - 服务器回应一个512位的输出级 RSA 密钥,并以其长期密钥签名。
- 由于 OpenSSL/SecureTransport 的缺陷,客户端会接受这个弱密钥。
- 攻击者根据 RSA 模数分解因子来恢复相应的 RSA 解密密钥。
- 当客户端编码 ‘预主密码’
( 给服务器时,攻击者现在就可以解码它并恢复 TLS 的 ‘主密码’( 。 - 从这里开始,攻击者就能看到了传输的明文并注入任何东西了。
本文所提供的加密套件不启用输出降级加密,请确认你的 OpenSSL 是最新的,也强烈建议你将客户端也升级到新的版本。
心血漏洞(Heartbleed)
心血漏洞
哪个版本的 OpenSSL 受到 心血漏洞
各版本情况如下:
- OpenSSL 1.0.1 直到 1.0.1f (包括)存在该缺陷
- OpenSSL 1.0.1g 没有该缺陷
- OpenSSL 1.0.0 分支没有该缺陷
- OpenSSL 0.9.8 分支没有该缺陷
这个缺陷是2011年12月引入到 OpenSSL 中的,并随着 2012年3月14日 OpenSSL 发布的 1.0.1 而泛滥。2014年4月7日发布的 OpenSSL 1.0.1g 修复了该漏洞。
升级你的 OpenSSL 就可以避免该缺陷。
SSL 压缩(罪恶攻击 CRIME)
罪恶攻击
如果你使用一个早期版本的 nginx 或 OpenSSL,而且你的发行版没有向后移植该选项,那么你需要重新编译没有一个 ZLIB 支持的 OpenSSL。这会禁止 OpenSSL 使用 DEFLATE 压缩方式。如果你禁用了这个,你仍然可以使用常规的 HTML DEFLATE 压缩。
SSLv2 和 SSLv3
SSLv2 是不安全的,所以我们需要禁用它。我们也禁用 SSLv3,因为 TLS 1.0 在遭受到降级攻击时,会允许攻击者强制连接使用 SSLv3,从而禁用了 前向安全性
如下编辑配置文件:
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
卷毛狗攻击(POODLE)和 TLS-FALLBACK-SCSV
SSLv3 会受到卷毛狗漏洞(POODLE)的攻击。这是禁用 SSLv3 的主要原因之一。
Google 提出了一个名为 TLS_FALLBACK_SCSV 的SSL/TLS 扩展,它用于防止强制 SSL 降级。如果你升级 到下述的 OpenSSL 版本会自动启用它。
- OpenSSL 1.0.1 带有 TLS_FALLBACK_SCSV 1.0.1j 及更高。
- OpenSSL 1.0.0 带有 TLS_FALLBACK_SCSV 1.0.0o 及更高。
- OpenSSL 0.9.8 带有 TLS_FALLBACK_SCSV 0.9.8zc 及更高。
加密套件(cipher suite)
前向安全性
这就是说,泄露的私钥并不能用来解密(之前)记录下来的 SSL 通讯。
提供 完备的前向安全性
以下两个加密套件是我推荐的,之后Mozilla 基金会也推荐了。
推荐的加密套件:
ssl_ciphers 'AES128+EECDH:AES128+EDH';
向后兼容的推荐的加密套件(IE6/WinXP):
ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
如果你的 OpenSSL 版本比较旧,不可用的加密算法会自动丢弃。应该一直使用上述的完整套件,让 OpenSSL 选择一个它所支持的。
加密套件的顺序是非常重要的,因为其决定了优先选择哪个算法。上述优先推荐的算法中提供了PFS(完备的前向安全性)。
较旧版本的 OpenSSL 也许不能支持这个算法的完整列表,AES-GCM 和一些 ECDHE 算法是相当新的,在 Ubuntu 和 RHEL 中所带的绝大多数 OpenSSL 版本中不支持。
优先顺序的逻辑
- ECDHE+AESGCM 加密是首选的。它们是 TLS 1.2 加密算法,现在还没有广泛支持。当前还没有对它们的已知攻击。
- PFS 加密套件好一些,首选 ECDHE,然后是 DHE。
- AES 128 要好于 AES 256。有一个关于 AES256 带来的安全提升程度是否值回成本的讨论,结果是显而易见的。目前,AES128 要更值一些,因为它提供了不错的安全水准,确实很快,而且看起来对时序攻击更有抵抗力。
- 在向后兼容的加密套件里面,AES 要优于 3DES。在 TLS 1.1及其以上,减轻了针对 AES 的 野兽攻击
( 的威胁,而在 TLS 1.0上则难以实现该攻击。在非向后兼容的加密套件里面,不支持 3DES。 - RC4 整个不支持了。3DES 用于向后兼容。参看 #RC4_weaknesses 中的讨论。
强制丢弃的算法
- aNULL 包含了非验证的 Diffie-Hellman 密钥交换,这会受到 中间人
( 攻击 - eNULL 包含了无加密的算法(明文)
- EXPORT 是老旧的弱加密算法,是被美国法律标示为可出口的
- RC4 包含的加密算法使用了已弃用的 ARCFOUR 算法
- DES 包含的加密算法使用了弃用的数据加密标准(DES)
- SSLv2 包含了定义在旧版本 SSL 标准中的所有算法,现已弃用
- MD5 包含了使用已弃用的 MD5 作为哈希算法的所有算法
更多设置
确保你也添加了如下行:
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
在一个 SSLv3 或 TLSv1 握手过程中选择一个加密算法时,一般使用客户端的首选算法。如果设置了上述配置,则会替代地使用服务器端的首选算法。
前向安全性和 Diffie Hellman Ephemeral (DHE)参数
前向安全性
使用了前向安全性,如果一个攻击者取得了一个服务器的私钥,他是不能解码之前的通讯信息的。这个私钥仅用于 Diffie Hellman 握手签名,并不会泄露预主密钥。Diffie Hellman 算法会确保预主密钥绝不会离开客户端和服务器,而且不能被中间人攻击所拦截。
所有版本的 nginx(如1.4.4)都依赖于 OpenSSL 给 Diffie-Hellman (DH)的输入参数。不幸的是,这意味着 Diffie-Hellman Ephemeral(DHE)将使用 OpenSSL 的默认设置,包括一个用于密钥交换的1024位密钥。因为我们正在使用2048位证书,DHE 客户端就会使用一个要比非 DHE 客户端更弱的密钥交换。
我们需要生成一个更强壮的 DHE 参数:
cd /etc/ssl/certs
openssl dhparam -out dhparam.pem 4096
然后告诉 nginx 将其用作 DHE 密钥交换:
ssl_dhparam /etc/ssl/certs/dhparam.pem;
OCSP 装订(Stapling)
当连接到一个服务器时,客户端应该使用 证书吊销列表
OCSP 更轻量级一些,因为我们每次只请求一条记录。但是副作用是当连接到一个服务器时必须对第三方 OCSP 响应器发起 OCSP 请求,这就增加了延迟和带来了潜在隐患。事实上,CA 所运营的 OCSP 响应器非常不可靠,浏览器如果不能及时收到答复,就会静默失败。攻击者通过 DoS 攻击一个 OCSP 响应器可以禁用其校验功能,这样就降低了安全性。
解决方法是允许服务器在 TLS 握手中发送缓存的 OCSP 记录,以绕开 OCSP 响应器。这个机制节省了客户端和 OCSP 响应器之间的通讯,称作 OCSP 装订。
客户端会在它的 CLIENT HELLO 中告知其支持 status_request TLS 扩展,服务器仅在客户端请求它的时候才发送缓存的 OCSP 响应。
大多数服务器最多会缓存 OCSP 响应48小时。服务器会按照常规的间隔连接到 CA 的 OCSP 响应器来获取刷新的 OCSP 记录。OCSP 响应器的位置可以从签名的证书中的 授权信息访问
HTTP 严格传输安全(HSTS)
如有可能,你应该启用 HTTP 严格传输安全(HSTS),它会引导浏览器和你的站点之间的通讯仅通过 HTTPS。
HTTP 公钥固定扩展(HPKP)
你也应该启用 HTTP 公钥固定扩展(HPKP)。
公钥固定的意思是一个证书链必须包括一个白名单中的公钥。它确保仅有白名单中的 CA 才能够为某个域名签署证书,而不是你的浏览器中存储的任何 CA。
我已经写了一篇关于 HPKP 的背景理论及在 Apache、Lighttpd 和 NGINX 中配置例子的文章。
配置范例
server {
listen [::]:443 default_server;
ssl on;
ssl_certificate_key /etc/ssl/cert/raymii_org.pem;
ssl_certificate /etc/ssl/cert/ca-bundle.pem;
ssl_ciphers 'AES128+EECDH:AES128+EDH:!aNULL';
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_session_cache shared:SSL:10m;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.4.4 8.8.8.8 valid=300s;
resolver_timeout 10s;
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
add_header Strict-Transport-Security max-age=63072000;
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
root /var/www/;
index index.html index.htm;
server_name raymii.org;
}
结尾
如果你使用了上述配置,你需要重启 nginx:
# 首先检查配置文件是否正确
/etc/init.d/nginx configtest
# 然后重启
/etc/init.d/nginx restart
现在使用 SSL Labs 测试来看看你是否能得到一个漂亮的“A”。当然了,你也得到了一个安全的、强壮的、经得起考验的 SSL 配置!
via: https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
作者:Remy van Elst 译者:wxy 校对:wxy