增强 nginx 的 SSL 安全性
SSL OpenSSL https nginx
[![](/data/attachment/album/201505/03/180656c9rra95g25gghdg5.png)](https://www.ssllabs.com/ssltest/analyze.html?d=raymii.org)


本文向你介绍如何在 nginx 服务器上设置健壮的 SSL 安全机制。我们通过禁用 SSL 压缩来降低 CRIME 攻击威胁；禁用协议上存在安全缺陷的 SSLv3 及更低版本，并设置更健壮的<ruby> 加密套件 <rp>  （ </rp> <rt>  cipher suite </rt> <rp>  ） </rp></ruby>来尽可能启用<ruby> 前向安全性 <rp>  （ </rp> <rt>  Forward Secrecy </rt> <rp>  ） </rp></ruby>；此外，我们还启用了 HSTS 和 HPKP。这样我们就拥有了一个健壮而可经受考验的 SSL 配置，并可以在 Qually Labs 的 SSL 测试中得到 A 级评分。


如果不求甚解的话，可以从 [https://cipherli.st](https://cipherli.st/) 上找到 nginx 、Apache 和 Lighttpd 的安全设置，复制粘帖即可。


本教程在 Digital Ocean 的 VPS 上测试通过。如果你喜欢这篇教程，想要支持作者的站点的话，购买 Digital Ocean 的 VPS 时请使用如下链接：<https://www.digitalocean.com/?refcode=7435ae6b8212> 。


本教程可以通过[发布于 2014/1/21 的](http://blog.ivanristic.com/2014/01/ssl-labs-stricter-security-requirements-for-2014.html) SSL 实验室测试的严格要求（我之前就通过了测试，如果你按照本文操作就可以得到一个 A+ 评分）。


* [本教程也可用于 Apache](https://raymii.org/s/tutorials/Strong_SSL_Security_On_Apache2.html)
* [本教程也可用于 Lighttpd](https://raymii.org/s/tutorials/Pass_the_SSL_Labs_Test_on_Lighttpd_%28Mitigate_the_CRIME_and_BEAST_attack_-_Disable_SSLv2_-_Enable_PFS%29.html)
* [本教程也可用于 FreeBSD, NetBSD 和 OpenBSD 上的 nginx ，放在 BSD Now 播客上](http://www.bsdnow.tv/episodes/2014_08_20-engineering_nginx): <http://www.bsdnow.tv/tutorials/nginx>


你可以从下列链接中找到这方面的进一步内容：


* [野兽攻击（BEAST）](https://en.wikipedia.org/wiki/Transport_Layer_Security#BEAST_attack)
* [罪恶攻击（CRIME）](https://en.wikipedia.org/wiki/CRIME_%28security_exploit%29)
* [怪物攻击（FREAK ）](http://blog.cryptographyengineering.com/2015/03/attack-of-week-freak-or-factoring-nsa.html)
* [心血漏洞（Heartbleed）](http://heartbleed.com/)
* [完备的前向安全性（Perfect Forward Secrecy）](https://en.wikipedia.org/wiki/Perfect_forward_secrecy)
* [RC4 和 BEAST 的处理](https://en.wikipedia.org/wiki/Transport_Layer_Security#Dealing_with_RC4_and_BEAST)


我们需要编辑 nginx 的配置，在 Ubuntu/Debian 上是 `/etc/nginx/sited-enabled/yoursite.com`，在 RHEL/CentOS 上是 `/etc/nginx/conf.d/nginx.conf`。


本文中，我们需要编辑443端口（SSL）的 `server` 配置中的部分。在文末你可以看到完整的配置例子。


*在编辑之前切记备份一下配置文件！*


### 野兽攻击（BEAST）和 RC4


简单的说，<ruby> 野兽攻击 <rp>  （ </rp> <rt>  BEAST </rt> <rp>  ） </rp></ruby>就是通过篡改一个加密算法的 <ruby> 密码块链 <rp>  （ </rp> <rt>  CBC，cipher block chaining </rt> <rp>  ） </rp></ruby>的模式，从而可以对部分编码流量悄悄解码。更多信息参照上面的链接。


针对<ruby> 野兽攻击 <rp>  （ </rp> <rt>  BEAST </rt> <rp>  ） </rp></ruby>，较新的浏览器已经启用了客户端缓解方案。推荐方案是禁用 TLS 1.0 的所有加密算法，仅允许 RC4 算法。然而，[针对 RC4 算法的攻击也越来越多](http://www.isg.rhul.ac.uk/tls/) ，很多已经从理论上逐步发展为实际可行的攻击方式。此外，有理由相信 NSA 已经实现了他们所谓的“大突破”——攻破 RC4 。


禁用 RC4 会有几个后果。其一，当用户使用老旧的浏览器时，比如 Windows XP 上的 IE 会用 3DES 来替代 RC4。3DES 要比 RC4 更安全，但是它的计算成本更高，你的服务器就需要为这些用户付出更多的处理成本。其二，RC4 算法能减轻<ruby> 野兽攻击 <rp>  （ </rp> <rt>  BEAST </rt> <rp>  ） </rp></ruby>的危害，如果禁用 RC4 会导致 TLS 1.0 用户会换到更容易受攻击的 AES-CBC 算法上（通常服务器端的对<ruby> 野兽攻击 <rp>  （ </rp> <rt>  BEAST </rt> <rp>  ） </rp></ruby>的“修复方法”是让 RC4 优先于其它算法）。我认为 RC4 的风险要高于<ruby> 野兽攻击 <rp>  （ </rp> <rt>  BEAST </rt> <rp>  ） </rp></ruby>的风险。事实上，有了客户端缓解方案（Chrome 和 Firefox 提供了缓解方案），<ruby> 野兽攻击 <rp>  （ </rp> <rt>  BEAST </rt> <rp>  ） </rp></ruby>就不是什么大问题了。而 RC4 的风险却在增长：随着时间推移，对加密算法的破解会越来越多。


### 怪物攻击（FREAK）


<ruby> 怪物攻击 <rp>  （ </rp> <rt>  FREAK </rt> <rp>  ） </rp></ruby>是一种中间人攻击，它是由来自 [INRIA、微软研究院和 IMDEA](https://www.smacktls.com/) 的密码学家们所发现的。<ruby> 怪物攻击 <rp>  （ </rp> <rt>  FREAK </rt> <rp>  ） </rp></ruby>的缩写来自“<ruby> RSA 出口密钥因子分解 <rp>  （ </rp> <rt>  Factoring RSA-EXPORT Keys </rt> <rp>  ） </rp></ruby>”


这个漏洞可上溯到上世纪九十年代，当时美国政府禁止出口加密软件，除非其使用编码密钥长度不超过512位的出口加密套件。


这造成了一些现在的 TLS 客户端存在一个缺陷，这些客户端包括： 苹果的 SecureTransport 、OpenSSL。这个缺陷会导致它们会接受出口降级 RSA 密钥，即便客户端并没有要求使用出口降级 RSA 密钥。这个缺陷带来的影响很讨厌：在客户端存在缺陷，且服务器支持出口降级 RSA 密钥时，会发生中间人攻击，从而导致连接的强度降低。


攻击分为两个组成部分：首先是服务器必须接受“<ruby> 出口降级 RSA 密钥 <rp>  （ </rp> <rt>  export grade RSA </rt> <rp>  ） </rp></ruby>”。


中间人攻击可以按如下流程：


* 在客户端的 Hello 消息中，要求标准的 RSA 加密套件。
* 中间人攻击者修改该消息为<ruby> ‘输出级 RSA 密钥’ <rp>  （ </rp> <rt>  export RSA </rt> <rp>  ） </rp></ruby>。
* 服务器回应一个512位的输出级 RSA 密钥，并以其长期密钥签名。
* 由于 OpenSSL/SecureTransport 的缺陷，客户端会接受这个弱密钥。
* 攻击者根据 RSA 模数分解因子来恢复相应的 RSA 解密密钥。
* 当客户端编码<ruby> ‘预主密码’ <rp>  （ </rp> <rt>  pre-master secret </rt> <rp>  ） </rp></ruby>给服务器时，攻击者现在就可以解码它并恢复 TLS 的<ruby> ‘主密码’ <rp>  （ </rp> <rt>  master secret </rt> <rp>  ） </rp></ruby>。
* 从这里开始，攻击者就能看到了传输的明文并注入任何东西了。


本文所提供的加密套件不启用输出降级加密，请确认你的 OpenSSL 是最新的，也强烈建议你将客户端也升级到新的版本。


### 心血漏洞（Heartbleed）


<ruby> 心血漏洞 <rp>  （ </rp> <rt>  Heartbleed </rt> <rp>  ） </rp></ruby> 是一个于2014年4月公布的 OpenSSL 加密库的漏洞，它是一个被广泛使用的传输层安全（TLS）协议的实现。无论是服务器端还是客户端在 TLS 中使用了有缺陷的 OpenSSL，都可以被利用该缺陷。由于它是因 DTLS 心跳扩展（RFC 6520）中的输入验证不正确（缺少了边界检查）而导致的，所以该漏洞根据“心跳”而命名。这个漏洞是一种缓存区超读漏洞，它可以读取到本不应该读取的数据。


哪个版本的 OpenSSL 受到<ruby> 心血漏洞 <rp>  （ </rp> <rt>  Heartbleed </rt> <rp>  ） </rp></ruby>的影响？


各版本情况如下：


* 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）


<ruby> 罪恶攻击 <rp>  （ </rp> <rt>  CRIME </rt> <rp>  ） </rp></ruby>使用 SSL 压缩来完成它的魔法，SSL 压缩在下述版本是默认关闭的： nginx 1.1.6及更高/1.0.9及更高（如果使用了 OpenSSL 1.0.0及更高）， nginx 1.3.2及更高/1.2.2及更高（如果使用较旧版本的 OpenSSL）。


如果你使用一个早期版本的 nginx 或 OpenSSL，而且你的发行版没有向后移植该选项，那么你需要重新编译没有一个 ZLIB 支持的 OpenSSL。这会禁止 OpenSSL 使用 DEFLATE 压缩方式。如果你禁用了这个，你仍然可以使用常规的 HTML DEFLATE 压缩。


### SSLv2 和 SSLv3


SSLv2 是不安全的，所以我们需要禁用它。我们也禁用 SSLv3，因为 TLS 1.0 在遭受到降级攻击时，会允许攻击者强制连接使用 SSLv3，从而禁用了<ruby> 前向安全性 <rp>  （ </rp> <rt>  forward secrecy </rt> <rp>  ） </rp></ruby>。


如下编辑配置文件：



```
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

```

### 卷毛狗攻击（POODLE）和 TLS-FALLBACK-SCSV


SSLv3 会受到[卷毛狗漏洞（POODLE）](https://raymii.org/s/articles/Check_servers_for_the_Poodle_bug.html)的攻击。这是禁用 SSLv3 的主要原因之一。


Google 提出了一个名为 [TLS\_FALLBACK\_SCSV](https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00) 的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 及更高。


[更多信息请参照 NGINX 文档](http://wiki.nginx.org/HttpSslModule#ssl_protocols)。


### 加密套件（cipher suite）


<ruby> 前向安全性 <rp>  （ </rp> <rt>  Forward Secrecy </rt> <rp>  ） </rp></ruby>用于在长期密钥被破解时确保会话密钥的完整性。<ruby> 完备的前向安全性 <rp>  （ </rp> <rt>  PFS，Perfect Forward Secrecy </rt> <rp>  ） </rp></ruby>是指强制在每个/每次会话中推导新的密钥。


这就是说，泄露的私钥并不能用来解密（之前）记录下来的 SSL 通讯。


提供<ruby> 完备的前向安全性 <rp>  （ </rp> <rt>  PFS，Perfect Forward Secrecy </rt> <rp>  ） </rp></ruby>功能的是那些使用了一种 Diffie-Hellman 密钥交换的短暂形式的加密套件。它们的缺点是系统开销较大，不过可以使用椭圆曲线的变体来改进。


以下两个加密套件是我推荐的，之后[Mozilla 基金会](https://wiki.mozilla.org/Security/Server_Side_TLS)也推荐了。


推荐的加密套件：



```
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 带来的安全提升程度是否值回成本的[讨论](http://www.mail-archive.com/dev-tech-crypto@lists.mozilla.org/msg11247.html)，结果是显而易见的。目前，AES128 要更值一些，因为它提供了不错的安全水准，确实很快，而且看起来对时序攻击更有抵抗力。
* 在向后兼容的加密套件里面，AES 要优于 3DES。在 TLS 1.1及其以上，减轻了针对 AES 的<ruby> 野兽攻击 <rp>  （ </rp> <rt>  BEAST </rt> <rp>  ） </rp></ruby>的威胁，而在 TLS 1.0上则难以实现该攻击。在非向后兼容的加密套件里面，不支持 3DES。
* RC4 整个不支持了。3DES 用于向后兼容。参看 [#RC4\_weaknesses](https://wiki.mozilla.org/Security/Server_Side_TLS#RC4_weaknesses) 中的讨论。


#### 强制丢弃的算法


* aNULL 包含了非验证的 Diffie-Hellman 密钥交换，这会受到<ruby> 中间人 <rp>  （ </rp> <rt>  MITM </rt> <rp>  ） </rp></ruby>攻击
* eNULL 包含了无加密的算法（明文）
* EXPORT 是老旧的弱加密算法，是被美国法律标示为可出口的
* RC4 包含的加密算法使用了已弃用的 ARCFOUR 算法
* DES 包含的加密算法使用了弃用的数据加密标准（DES）
* SSLv2 包含了定义在旧版本 SSL 标准中的所有算法，现已弃用
* MD5 包含了使用已弃用的 MD5 作为哈希算法的所有算法


### 更多设置


确保你也添加了如下行：



```
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;

```

在一个 SSLv3 或 TLSv1 握手过程中选择一个加密算法时，一般使用客户端的首选算法。如果设置了上述配置，则会替代地使用服务器端的首选算法。


* [关于 ssl\_prefer\_server\_ciphers 的更多信息](http://wiki.nginx.org/HttpSslModule#ssl_prefer_server_ciphers)
* [关于 ssl\_ciphers 的更多信息](http://wiki.nginx.org/HttpSslModule#ssl_ciphers)


### 前向安全性和 Diffie Hellman Ephemeral （DHE）参数


<ruby> 前向安全性 <rp>  （ </rp> <rt>  Forward Secrecy </rt> <rp>  ） </rp></ruby>的概念很简单：客户端和服务器协商一个永不重用的密钥，并在会话结束时销毁它。服务器上的 RSA 私钥用于客户端和服务器之间的 Diffie-Hellman 密钥交换签名。从 Diffie-Hellman 握手中获取的预主密钥会用于之后的编码。因为预主密钥是特定于客户端和服务器之间建立的某个连接，并且只用在一个限定的时间内，所以称作<ruby> 短暂模式 <rp>  （ </rp> <rt>  Ephemeral </rt> <rp>  ） </rp></ruby>。


使用了前向安全性，如果一个攻击者取得了一个服务器的私钥，他是不能解码之前的通讯信息的。这个私钥仅用于 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）


当连接到一个服务器时，客户端应该使用<ruby> 证书吊销列表 <rp>  （ </rp> <rt>  CRL，Certificate Revocation List </rt> <rp>  ） </rp></ruby>或<ruby> 在线证书状态协议 <rp>  （ </rp> <rt>  OCSP，Online Certificate Status Protocol </rt> <rp>  ） </rp></ruby>记录来校验服务器证书的有效性。CRL 的问题是它已经增长的太大了，永远也下载不完了。


OCSP 更轻量级一些，因为我们每次只请求一条记录。但是副作用是当连接到一个服务器时必须对第三方 OCSP 响应器发起 OCSP 请求，这就增加了延迟和带来了潜在隐患。事实上，CA 所运营的 OCSP 响应器非常不可靠，浏览器如果不能及时收到答复，就会静默失败。攻击者通过 DoS 攻击一个 OCSP 响应器可以禁用其校验功能，这样就降低了安全性。


解决方法是允许服务器在 TLS 握手中发送缓存的 OCSP 记录，以绕开 OCSP 响应器。这个机制节省了客户端和 OCSP 响应器之间的通讯，称作 OCSP 装订。


客户端会在它的 CLIENT HELLO 中告知其支持 status\_request TLS 扩展，服务器仅在客户端请求它的时候才发送缓存的 OCSP 响应。


大多数服务器最多会缓存 OCSP 响应48小时。服务器会按照常规的间隔连接到 CA 的 OCSP 响应器来获取刷新的 OCSP 记录。OCSP 响应器的位置可以从签名的证书中的<ruby> 授权信息访问 <rp>  （ </rp> <rt>  Authority Information Access </rt> <rp>  ） </rp></ruby>字段中获得。


* [阅读我的教程：在 NGINX 中启用 OCSP 装订](https://raymii.org/s/tutorials/OCSP_Stapling_on_nginx.html)


### HTTP 严格传输安全（HSTS）


如有可能，你应该启用 [HTTP 严格传输安全（HSTS）](https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security)，它会引导浏览器和你的站点之间的通讯仅通过 HTTPS。


* [阅读我关于 HSTS 的文章，了解如何配置它](/article-5266-1.html)


### HTTP 公钥固定扩展（HPKP）


你也应该启用 [HTTP 公钥固定扩展（HPKP）](https://wiki.mozilla.org/SecurityEngineering/Public_Key_Pinning)。


公钥固定的意思是一个证书链必须包括一个白名单中的公钥。它确保仅有白名单中的 CA 才能够为某个域名签署证书，而不是你的浏览器中存储的任何 CA。


我已经写了一篇[关于 HPKP 的背景理论及在 Apache、Lighttpd 和 NGINX 中配置例子的文章](/article-5282-1.html)。


### 配置范例



```
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 测试](https://www.ssllabs.com/ssltest/)来看看你是否能得到一个漂亮的“A”。当然了，你也得到了一个安全的、强壮的、经得起考验的 SSL 配置！


* [参考 Mozilla 关于这方面的内容](https://wiki.mozilla.org/Security/Server_Side_TLS)




---


via: <https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html>


作者：[Remy van Elst](https://raymii.org/) 译者：[wxy](https://github.com/wxy) 校对：[wxy](https://github.com/wxy)


本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创翻译，[Linux中国](http://linux.cn/) 荣誉推出


OK
[Skip to main content](#main)

#
[Raymii.org
](https://raymii.org/s/)


Quis custodiet ipsos custodes?[Home](/s/)|

[About](/s/static/About.html)|

[All pages](/s/tags/all.html)|

[Cluster Status](/s/software/Sparkling_Network.html)|

[RSS Feed](https://raymii.org/s/feed.xml)


## Strong SSL Security on nginx

Published: 14-06-2015 | Last update: 27-04-2019 | Author: Remy van Elst | [Text only version of this article](Strong_SSL_Security_On_nginx.txt)

**❗ This post is over five years old. It may no longer be up to date. Opinions may have changed.**

### Table of Contents

-
[SSL Protocols](#toc_0) -
[The Cipher Suite](#toc_1) -
[Extra settings](#toc_4) -
[Forward Secrecy & Diffie Hellman Ephemeral Parameters](#toc_5) -
[OCSP Stapling](#toc_6) -
[HTTP Strict Transport Security](#toc_7) -
[HTTP Public Key Pinning Extension](#toc_8) -
[Poodle and TLS-FALLBACK-SCSV](#toc_9) -
[The BEAST attack and RC4](#toc_10) -
[Factoring RSA-EXPORT Keys (FREAK)](#toc_11) -
[Logjam (DH EXPORT)](#toc_12) -
[Heartbleed](#toc_13) -
[SSL Compression (CRIME attack)](#toc_14) -
[Conclusion](#toc_15)

This tutorial shows you how to set up strong SSL security on the nginx webserver. We do this by updating OpenSSL to the latest version to mitigate attacks like Heartbleed, disabling SSL Compression and EXPORT ciphers to mitigate attacks like FREAK, CRIME and LogJAM, disabling SSLv3 and below because of vulnerabilities in the protocol and we will set up a strong ciphersuite that enables Forward Secrecy when possible. We also enable HSTS and HPKP. This way we have a strong and future proof ssl configuration and we get an A+ on the Qually Labs SSL Test.

I've written an Open Source [SSL server test](https://raymii.org/s/software/OpenSSL_Decoder.html). You can use it to test your
configuration, as an addition to the other SSL tests our there. It is fast,
shows you all the information so you can make your own informed decision (no
ratings), and the results are saved so you can compare different settings. You
can test your site via [https://ssldecoder.org](https://ssldecoder.org).

I've also written a handy tool which notifies you when your certificates are
about to expire. It is open source so you can host it yourself internally and
there is a hosted version available at [https://certificatemonitor.org](https://certificatemonitor.org).

I've created a website with [Copy-pastable strong cipherssuites for NGINX,
Apache, Lighttpd and other software: https://cipherli.st](https://cipherli.st/). Handy if you don't
want to read this entire tutorial. This tutorial and [https://cipherli.st](https://cipherli.st/)
are updated continuously as new vulnerabilities are discovered.

**Recently I removed all Google Ads from this site due to their invasive tracking, as well as Google Analytics. Please, if you found this content useful, consider a small donation using any of the options below:**

[I'm developing an open source monitoring app called Leaf Node Monitoring, for windows, linux & android. Go check it out!](https://leafnode.nl)

[Consider sponsoring me on Github. It means the world to me if you show your appreciation and you'll help pay the server costs.](https://github.com/sponsors/RaymiiOrg/)

[You can also sponsor me by getting a Digital Ocean VPS. With this referral link you'll get $200 credit for 60 days. Spend $25 after your credit expires and I'll get $25!](https://www.digitalocean.com/?refcode=7435ae6b8212)


This tutorial works with the stricter requirements of the SSL Labs test [announced on the 21st of January 2014](http://blog.ivanristic.com/2014/01/ssl-labs-stricter-security-requirements-for-2014.html) (It already did before that, if you follow(ed) it you get an A+)

[This tutorial is also available for Apache](https://raymii.org/s/tutorials/Strong_SSL_Security_On_Apache2.html)[This tutorial is also available for Lighttpd](https://raymii.org/s/tutorials/Strong_SSL_Security_On_lighttpd.html)[This tutorial is also available for FreeBSD, NetBSD and OpenBSD over at the BSD Now podcast](http://www.bsdnow.tv/episodes/2014_08_20-engineering_nginx)

You can find more info on the topics by following the links below:

[BEAST Attack](https://raymii.org/s/tutorials/HTTP_Strict_Transport_Security_for_Apache_NGINX_and_Lighttpd.html)[CRIME Attack](https://wiki.mozilla.org/SecurityEngineering/Public_Key_Pinning)[Heartbleed](https://raymii.org/s/articles/HTTP_Public_Key_Pinning_Extension_HPKP.html)[FREAK Attack](https://www.ssllabs.com/ssltest/)- [Perfect Forward Secrecy][27]
- [Dealing with RC4 and BEAST][28]

We are going to edit the nginx settings in the file ```
/etc/nginx/sites-
enabled/yoursite.com
```

(On Ubuntu/Debian) or in `/etc/nginx/conf.d/nginx.conf`

(On RHEL/CentOS).

For the entire tutorial, you need to edit the parts between the `server`

block
for the server config for port 443 (ssl config). At the end of the tutorial you
can find the complete config example.

*Make sure you back up the files before editing them!*

### SSL Protocols

All protocols other than TLS 1.2 and TLS 1.3 are considered unsafe.

Edit the config file:

```
ssl_protocols TLSv1.2 TLSv1.3; # Requires nginx >= 1.13.0 else use TLSv1.2
```


### The Cipher Suite

Forward Secrecy ensures the integrity of a session key in the event that a long- term key is compromised. PFS accomplishes this by enforcing the derivation of a new key for each and every session.

This means that when the private key gets compromised it cannot be used to decrypt recorded SSL traffic.

The cipher suites that provide Perfect Forward Secrecy are those that use an ephemeral form of the Diffie-Hellman key exchange. Their disadvantage is their overhead, which can be improved by using the elliptic curve variants.

The following two ciphersuites are recommended by me, and the latter by [the
Mozilla Foundation](https://wiki.mozilla.org/Security/Server_Side_TLS).

The recommended cipher suite:

```
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
```


The recommended cipher suite for backwards compatibility (IE6/WinXP):

```
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:ECDHE-RSA-AES128-GCM-SHA256:AES256+EECDH:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384: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";
```


If your version of OpenSSL is old, unavailable ciphers will be discarded automatically. Always use the full ciphersuite above and let OpenSSL pick the ones it supports.

The ordering of a ciphersuite is very important because it decides which algorithms are going to be selected in priority. The recommendation above prioritizes algorithms that provide perfect forward secrecy.

Older versions of OpenSSL may not return the full list of algorithms. AES-GCM and some ECDHE are fairly recent, and not present on most versions of OpenSSL shipped with Ubuntu or RHEL.

#### Prioritization logic

- ECDHE+AESGCM ciphers are selected first. These are TLS 1.2 ciphers. No known attack currently target these ciphers.
- PFS ciphersuites are preferred, with ECDHE first, then DHE.
- AES 128 is preferred to AES 256. There has been
[discussions](http://www.mail-archive.com/dev-tech-crypto@lists.mozilla.org/msg11247.html)on whether AES256 extra security was worth the cost , and the result is far from obvious. At the moment, AES128 is preferred, because it provides good security, is really fa st, and seems to be more resistant to timing attacks. - In the backward compatible ciphersuite, AES is preferred to 3DES. BEAST attacks on AES are mitigated in TLS 1.1 and a bove, and difficult to achieve in TLS 1.0. In the non-backward compatible ciphersuite, 3DES is not present.
- RC4 is removed entirely. 3DES is used for backward compatibility. See discussion in
[#RC4_weaknesses](https://wiki.mozilla.org/Security/Server_Side_TLS#RC4_weaknesses)

#### Mandatory discards

- aNULL contains non-authenticated Diffie-Hellman key exchanges, that are subject to Man-In-The-Middle (MITM) attacks
- eNULL contains null-encryption ciphers (cleartext)
- EXPORT are legacy weak ciphers that were marked as exportable by US law
- RC4 contains ciphers that use the deprecated ARCFOUR algorithm
- DES contains ciphers that use the deprecated Data Encryption Standard
- SSLv2 contains all ciphers that were defined in the old version of the SSL standard, now deprecated
- MD5 contains all the ciphers that use the deprecated message digest 5 as the hashing algorithm

### Extra settings

Make sure you also add these lines:

```
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
```


When choosing a cipher during an SSLv3 or TLSv1 handshake, normally the client's preference is used. If this directive is enabled, the server's preference will be used instead.

[More info on ssl prefer server_ciphers](http://wiki.nginx.org/HttpSslModule#ssl_prefer_server_ciphers)

[More info on ssl_ciphers](http://wiki.nginx.org/HttpSslModule#ssl_ciphers)

### Forward Secrecy & Diffie Hellman Ephemeral Parameters

The concept of forward secrecy is simple: client and server negotiate a key that never hits the wire, and is destroyed at the end of the session. The RSA private from the server is used to sign a Diffie- Hellman key exchange between the client and the server. The pre-master key obtained from the Diffie-Hellman handshake is then used for encryption. Since the pre-master key is specific to a connection between a client and a server, and used only for a limited amount of time, it is called Ephemeral.

With Forward Secrecy, if an attacker gets a hold of the server's private key, it will not be able to decrypt past communications. The private key is only used to sign the DH handshake, which does not reveal the pre- master key. Diffie-Hellman ensures that the pre-master keys never leave the client and the server, and cannot be intercepted by a MITM.

All versions of nginx as of 1.4.4 rely on OpenSSL for input parameters to Diffie-Hellman (DH). Unfortunately, this means that Ephemeral Diffie- Hellman (DHE) will use OpenSSL's defaults, which include a 1024-bit key for the key- exchange. Since we're using a 2048-bit certificate, DHE clients will use a weaker key-exchange than non-ephemeral DH clients.

We need generate a stronger DHE parameter:

```
openssl dhparam -out /etc/ssl/certsdhparam.pem 4096
```


And then tell nginx to use it for DHE key-exchange:

```
ssl_dhparam /etc/ssl/certs/dhparam.pem;
ssl_ecdh_curve secp384r1; # Requires nginx >= 1.1.0
```


### OCSP Stapling

When connecting to a server, clients should verify the validity of the server certificate using either a Certificate Revocation List (CRL), or an Online Certificate Status Protocol (OCSP) record. The problem with CRL is that the lists have grown huge and takes forever to download.

OCSP is much more lightweight, as only one record is retrieved at a time. But the side effect is that OCSP requests must be made to a 3rd party OCSP responder when connecting to a server, which adds latency and potential failures. In fact, the OCSP responders operated by CAs are often so unreliable that browser will fail silently if no response is received in a timely manner. This reduces security, by allowing an attacker to DoS an OCSP responder to disable the validation.

The solution is to allow the server to send its cached OCSP record during the TLS handshake, therefore bypassing the OCSP responder. This mechanism saves a roundtrip between the client and the OCSP responder, and is called OCSP Stapling.

The server will send a cached OCSP response only if the client requests it, by announcing support for the status_request TLS extension in its CLIENT HELLO.

Most servers will cache OCSP response for up to 48 hours. At regular intervals, the server will connect to the OCSP responder of the CA to retrieve a fresh OCSP record. The location of the OCSP responder is taken from the Authority Information Access field of the signed certificate.

[View my tutorial on enabling OCSP stapling on NGINX](https://raymii.org/s/tutorials/OCSP_Stapling_on_nginx.html)

### HTTP Strict Transport Security

When possible, you should enable [HTTP Strict Transport Security (HSTS)](https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security),
which instructs browsers to communicate with your site only over HTTPS.

[View my article on HTST to see how to configure it.](https://raymii.org/s/tutorials/HTTP_Strict_Transport_Security_for_Apache_NGINX_and_Lighttpd.html)

### HTTP Public Key Pinning Extension

You should also enable the [HTTP Public Key Pinning Extension](https://wiki.mozilla.org/SecurityEngineering/Public_Key_Pinning).

Public Key Pinning means that a certificate chain must include a whitelisted
public key. It ensures only whitelisted Certificate Authorities (CA) can sign
certificates for `*.example.com`

, and not any CA in your browser store.

I've written an article about it that has background theory and configuration
examples for Apache, Lighttpd and NGINX: [https://raymii.org/s/articles/HTTP
Public Key Pinning Extension_HPKP.html](https://raymii.org/s/articles/HTTP_Public_Key_Pinning_Extension_HPKP.html)

### Poodle and TLS-FALLBACK-SCSV

SSLv3 allows exploiting of the [POODLE](https://raymii.org/s/articles/Check_servers_for_the_Poodle_bug.html) bug. This is one more major reason
to disable this.

Google have proposed an extension to SSL/TLS named [TLS FALLBACK SCSV](https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00)
that seeks to prevent forced SSL downgrades. This is automatically enabled if
you upgrade OpenSSL to the following versions:

- OpenSSL 1.0.1 has TLS
*FALLBACK*SCSV in 1.0.1j and higher. - OpenSSL 1.0.0 has TLS
*FALLBACK*SCSV in 1.0.0o and higher. - OpenSSL 0.9.8 has TLS
*FALLBACK*SCSV in 0.9.8zc and higher.

[More info on the NGINX documentation](http://wiki.nginx.org/HttpSslModule#ssl_protocols)

### The BEAST attack and RC4

In short, by tampering with an encryption algorithm's CBC - cipher block chaining - mode's, portions of the encrypted traffic can be secretly decrypted. More info on the above link.

Recent browser versions have enabled client side mitigation for the beast attack. The recommendation was to disable all TLS 1.0 ciphers and only offer RC4. However, [RC4 has a growing list of attacks against it],(http://www.isg.rhul.ac.uk/tls/) many of which have crossed the line from theoretical to practical. Moreover, there is reason to believe that the NSA has broken RC4, their so-called "big breakthrough."

Disabling RC4 has several ramifications. One, users with shitty browsers such as Internet Explorer on Windows XP will use 3DES in lieu. Triple- DES is more secure than RC4, but it is significantly more expensive. Your server will pay the cost for these users. Two, RC4 mitigates BEAST. Thus, disabling RC4 makes TLS 1.0 users susceptible to that attack, by moving them to AES-CBC (the usual server-side BEAST "fix" is to prioritize RC4 above all else). I am confident that the flaws in RC4 significantly outweigh the risks from BEAST. Indeed, with client-side mitigation (which Chrome and Firefox both provide), BEAST is a nonissue. But the risk from RC4 only grows: More cryptanalysis will surface over time.

### Factoring RSA-EXPORT Keys (FREAK)

FREAK is a man-in-the-middle (MITM) vulnerability discovered by a group of
cryptographers at [INRIA, Microsoft Research and IMDEA](https://www.smacktls.com/). FREAK stands for
"Factoring RSA-EXPORT Keys."

The vulnerability dates back to the 1990s, when the US government banned selling crypto software overseas, unless it used export cipher suites which involved encryption keys no longer than 512-bits.

It turns out that some modern TLS clients - including Apple's SecureTransport and OpenSSL - have a bug in them. This bug causes them to accept RSA export- grade keys even when the client didn't ask for export-grade RSA. The impact of this bug can be quite nasty: it admits a 'man in the middle' attack whereby an active attacker can force down the quality of a connection, provided that the client is vulnerable and the server supports export RSA.

There are two parts of the attack as the server must also accept "export grade RSA."

The MITM attack works as follows:

- In the client's Hello message, it asks for a standard 'RSA' ciphersuite.
- The MITM attacker changes this message to ask for 'export RSA'.
- The server responds with a 512-bit export RSA key, signed with its long-term key.
- The client accepts this weak key due to the OpenSSL/SecureTransport bug.
- The attacker factors the RSA modulus to recover the corresponding RSA decryption key.
- When the client encrypts the 'pre-master secret' to the server, the attacker can now decrypt it to recover the TLS 'm aster secret'.
- From here on out, the attacker sees plaintext and can inject anything it wants.

The ciphersuite offered here on this page does not enable EXPORT grade ciphers. Make sure your OpenSSL is updated to the latest available version and urge your clients to also use upgraded software.

### Logjam (DH EXPORT)

[Researchers](https://weakdh.org/) from several universities and institutions conducted a study
that found an issue in the TLS protocol. In a report the researchers report two
attack methods.

Diffie-Hellman key exchange allows that depend on TLS to agree on a shared key and negotiate a secure session over a plain text connection.

With the first attack, a man-in-the-middle can downgrade a vulnerable TLS connection to 512-bit export-grade cryptography which would allow the attacker to read and change the data. The second threat is that many servers and use the same prime numbers for Diffie-Hellman key exchange instead of generating their own unique DH parameters.

The team estimates that an academic team can break 768-bit primes and that a nation-state could break a 1024-bit prime. By breaking one 1024-bit prime, one could eavesdrop on 18 percent of the top one million HTTPS domains. Breaking a second prime would open up 66 percent of VPNs and 26 percent of SSH servers.

Later on in this guide we generate our own unique DH parameters and we use a ciphersuite that does not enable EXPORT grade ciphers. Make sure your OpenSSL is updated to the latest available version and urge your clients to also use upgraded software. Updated browsers refuse DH parameters lower than 768/1024 bit as a fix to this.

[Cloudflare has a detailed guide](https://blog.cloudflare.com/logjam-the-latest-tls-vulnerability-explained/) on logjam.

### Heartbleed

Heartbleed is a security bug disclosed in April 2014 in the OpenSSL cryptography library, which is a widely used implementation of the Transport Layer Security (TLS) protocol. Heartbleed may be exploited regardless of whether the party using a vulnerable OpenSSL instance for TLS is a server or a client. It results from improper input validation (due to a missing bounds check) in the implementation of the DTLS heartbeat extension (RFC6520), thus the bug's name derives from "heartbeat". The vulnerability is classified as a buffer over-read, a situation where more data can be read than should be allowed.

What versions of the OpenSSL are affected by Heartbleed?

Status of different versions:

- OpenSSL 1.0.1 through 1.0.1f (inclusive) are vulnerable
- OpenSSL 1.0.1g is NOT vulnerable
- OpenSSL 1.0.0 branch is NOT vulnerable
- OpenSSL 0.9.8 branch is NOT vulnerable

The bug was introduced to OpenSSL in December 2011 and has been out in the wild since OpenSSL release 1.0.1 on 14th of March 2012. OpenSSL 1.0.1g released on 7th of April 2014 fixes the bug.

By updating OpenSSL you are not vulnerable to this bug.

### SSL Compression (CRIME attack)

The CRIME attack uses SSL Compression to do its magic. SSL compression is turned off by default in nginx 1.1.6+/1.0.9+ (if OpenSSL 1.0.0+ used) and nginx 1.3.2+/1.2.2+ (if older versions of OpenSSL are used).

If you are using al earlier version of nginx or OpenSSL and your distro has not backported this option then you need to recompile OpenSSL without ZLIB support. This will disable the use of OpenSSL using the DEFLATE compression method. If you do this then you can still use regular HTML DEFLATE compression.

### Conclusion

If you have applied the above config lines you need to restart nginx:

```
# Check the config first:
/etc/init.d/nginx configtest
# Then restart:
/etc/init.d/nginx restart
```


Now use the [SSL Labs test](https://www.ssllabs.com/ssltest/) to see if you get a nice A. And, of course, have
a safe, strong and future proof SSL configuration!

[Also read the Mozilla page on the subject](https://wiki.mozilla.org/Security/Server_Side_TLS)

[nginx](../tags/nginx.html),

[security](../tags/security.html),

[ssl](../tags/ssl.html),

[ssl-labs](../tags/ssl-labs.html),

[tls](../tags/tls.html),

[tutorials](../tags/tutorials.html)