安全的SSL/TLS配置推荐及其原理

2019-11-28 382 Words Tls Web Nginx

一、SSL/TLS 背景

如今已经是 2019 年了,大部分的 HTTP 服务器都默认配置了 SSL/TLS ,以为大家提供安全的、具有隐私性的网络服务。

但是安全的配置 TLS 往往是困难的,如果配置不当可能会导致性能低下、安全性能减弱等问题。因此这篇文章以 Nginx 服务器为例,讲解如何安全的配置 ssl 服务器。

早期的 SSL(安全套接字协议)是由网景公司发布的提供安全连接的服务,发布了 SSL1.0, SSL2.0, SSL 3.0 三个版本。后来 IETF 将其标准化,并作为 TLS 协议(传输层安全协议)发布了 TLSv1.1 和 TLSv1.2 协议。 2018年,最新的 TLSv1.3 协议发布。目前主要使用的版本是 TLSv1.2 和 TLSv1.3 两个版本,早期的版本已经不再建议使用了。

TLS 协议主要使用了如下一些密码学算法来提供安全服务:

  • 身份认证:服务器需要证明自己就是真实的服务器,防止了恶意服务器假冒真实网站提供服务。
  • 秘钥交换:服务器和浏览器需要协商出一个秘钥,用于后续消息的加密和验证。
  • 数据机密性保护:使用了上述协商出来的秘钥,来对信息进行加密,使得他人不能读取消息的内容。
  • 消息完整性保护:要保护消息没有被恶意篡改(即便是加密的信息,也可能进行篡改)

二、密码学算法简介

为了完成上面这些密码学服务,需要使用一些密码学算法,来提供这些服务。将这些密码学算法组合起来,形成一个个套餐,也就形成了密码学套件(ciphers)。

TLS 协议最初是的阶段,就是通信双方对于所使用的的密码学套件进行协商,确定算法和相关参数,之后才能提供安全性服务。

2.1 身份认证

为了验证身份,TLS 使用了一种被称为“数字签名”的算法。数字签名是一种基于非对称密码的算法,可以使得一个实体(一般来说是服务器)证明他就是所声称的人。

这里就需要大家常说的证书的概念,简单来说,证书提供了关系的证明,https 服务器需要向可信第三方(CA)申请一个 ssl 证书。客户端拿到服务器的证书之后,去CA处查询,就能够觉得服务器的身份。

数字签名根据所使用的非对称算法的不同,主要有有 RSA 和 ECDSA 两种证书。

RSA(DSA) 是最简单的一种非对称算法,可以用于签名,但是其秘钥比较长(通常有 2048 位或者 4096 位),计算的开销比较大。因此近些年搭建广泛使用 ECDSA 来取代 RSA 算法。

ECDSA 是在椭圆曲线上的签名算法,秘钥较短,计算开销也非常小。ECDSA 的缺点就是由于才推行,因此兼容性交叉,一般需要同时提供 RSA 作为备选方案。

RSA 还是 ECDSA 的选取是根据你所申请的证书的类型来决定的。

2.2 秘钥交换

秘钥交换是指服务器和客户端协商出一个秘钥,用于后续加密。

这里常用的密码学算法有:

  • psk 客户端和服务器都知道的密码,不安全,很少单独使用。
  • RSA 可以用于秘钥交换,但是由于算法本身的安全性和不具有“前向安全性”,因此在 TLSv1.3 之后被移除了。
  • DH DH 秘钥交换是一种密码学算法。
  • ECDH 一种 DH 的变种,在椭圆曲线上进行,可以减小开销。

后续出现了增强的 DH 和 ECDH 协议,被称为 DHE 和 ECDHE 协议。这两个协议具有较高的安全性能。

TLSv1.2 之前的协议中支持 RSA,DHE 和 ECDHE 这些算法。但是 RSA 已经不被推荐使用了。同时又由于 ECDHE 可以实现 DHE 类似的安全性能,但是有有较低的计算开销,因此在 TLSv1.3 之后,默认使用 ECHDE

但是在 TLSv1.2中也建议使用 ECDHE 算法。

2.3 加密算法和消息认证算法

加密算法用于对消息进行加密,常见的加密算法有如下这些:

  • RC4: 流密码,不安全,应当禁止使用
  • DES: 最早的加密算法之一,已经非常不安全,应当禁止使用。
  • 3DES: DES 不安全,就将其算三遍,因此安全性较高,但是计算开销太大了,因此除非是支持早期的 IE 浏览器,目前已经不怎么使用了。
  • AES: 目前比较主流的算法,秘钥长度是 128,192 或者 256 位。有 CBC, ECB 等模式。目前 AES-ECB 已经不安全,应当禁止使用。AES-CBC 则可以使用。

消息认证算法有消息验证码(MAC)、HMAC等。TLS协议使用的是 HMAC 算法,根据其哈希函数的不同,常见的有 SHA256, SHA384,SHA1,MD5 等算法。其中 MD5 和 SHA1 应当已经不再使用了。

2.4 AEAD 算法

后来,人们发现将加密算法和消息认证算法分开使用,会有各种安全问题,因此发明了一类同时进行加密和认证的算法,被称为 AEAD 算法。这一类算法是目前非常推荐使用的

AEAD 算法将加密和认证同时进行,简化了操作步骤,又有非常高的安全性,因此在 TLSv1.3 中只使用 AEAD 算法,而不再单独指定加密和认证算法

常见的 AEAD 算法有:AES-GCM, AES-CCM, CHACHA20 等。

2.5 密码套件(ciphers)

将上面所说的算法组合起来,形成的套餐,就是密码套件,TLS 中为套件分配了编号。在建立 TLS 连接的过程中,服务器和客户端会协商选取出一个套件来使用。

比如:

  • ECDHE-RSA-AES256-GCM-SHA384: 使用 ECDHE 秘钥交换算法,使用 RSA 身份认证算法,使用 AES256-GCM-SHA384 的256位秘钥长度的 AES-GCM AEAD 加密和消息认证算法的套餐。
  • DHE-RSA-AES256-SHA256:使用 DHE 秘钥交换算法,使用 RSA 身份认证算法,使用 AES-256 作为消息加密算法,使用 SHA256 作为消息认证算法的套餐。

选取密码学套件的矛盾在于,安全性很强的密码学算法只有现代的浏览器和服务器支持;如果想兼容较为古老的客户端,可能需要使用安全性较弱的密码学套件。当然根据优先级的配置,可以使得新的客户端使用较强的密码学算法,而老旧客户端使用相对较弱的算法。

三、TLS 其他特性

3.1 TLS 会话重用

在 TLSv1.2 之后,引入了会话重用的概念,可是使得服务器和客户端第二次建立连接之后,可以使用上次会话的参数,简化了握手流程,加快了连接建立的速度。

3.2 0RTT

传统 TLS 协议在握手完成之前,是不能发送消息内容的。在 TLSv1.3 之后,引入了 0RTT 的机制,可以使得在建立连接的过程之中,就发送了上层数据。极大的提高了用户的使用感受。

但是这种机制是有代价的,0RTT 发送的信息安全性较弱,可能带来重放攻击!

四、算法推荐

下面以 Nginx 配置为例,讲解目前(2019年)配置推荐。

4.1 TLS 版本

目前SSL1.0, SSL2.0, SSL3.0, TLSv1.1 版本都不再使用。目前最近的 TLSv1.3 应当首选使用,但是由于其支持还不足(Windows 8,Java 8等),因此为了兼容性,可以使用 TLSv1.2 版本。

4.2 TLS 证书

使用下面的指令来指定证书的公私钥文件。可以多次使用下面两个指令,分别指定 RSA 和 ECDSA 的证书。

ssl_certificate fullchain.pub; # 公钥文件
ssl_certificate_key daemon.key; 秘钥文件

4.2 TLS 会话

下面两种指令决定了会话缓存的大小和保留的时间。

    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;

4.3 TLS 密码套件

目前 TLSv1.3 的所有密码学套件都推荐使用。 TLSv1.2 中有一些密码学套件不再推荐使用。

  • 身份认证取决于证书类型,RSA 和 ECDSA 都可。
  • 秘钥交换应当首选 ECDHE(EECDH) 协议
  • 加密和消息认证应当使用 AEAD 的系列算法。
  • 有些win8 win7,等浏览器可能不支持 AEAD 算法,需要使用 AES-CBC 算法(如果不考虑兼容,则不建议使用) 配合 SHA256,SHA384 等使用。
  • RC4,MD5,不要使用

因此如下推荐:

ssl_ciphers TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+aRSA+AESGCM:EECHD+ECDSA+AESGCM:EECDH+ECDSA+AESCCM:EECHD+aRSA+AESCCM:EECDH+aRSA+AES:!aNULL:!MD5:!RC4:!EXP:!LOW;

关于 ciphers lists 的语法简要说明如下:

  • ‘+’ 类似原则套餐组合的含义,比如 EECDH+CHACHA20 表示使用 EECHD 和 CHACHA20 组合的密码学套件。
  • TLS13-AES-256-GCM-SHA384 则具体指定了某个具体的套件。
  • ‘!’ 表示不使用。比如 !MD5 表示不使用 MD5 的密码学套件。

openssl 支持的密码套件可以使用命令 openssl ciphers -V |column -t 来查看。

如果不使用 ECDSA 的证书,则可以将 EECHD+ECDSA+AESGCM 和 EECDH+ECDSA+AESCCM 去除。

如果不需要指出 AES-CBC 则将 EECDH+aRSA+AES 去除。

4.4 TLSv1.3 0-RTT

由于其有重放攻击可能性,因此 Nginx 默认不开启,如需开启:

ssl_early_data on;

其他 ssl 指令参照 Nginx 官网配置,如 ssl_stapling 指令表示是否开启 OCSP stapling,以验证其状态等。

4.5 其他指令

HSTS HTTP 严格传输安全协议。添加这个头标,要求以后浏览器自动请求 https 协议。

add_header Strict-Transport-Security "max-age=31536000";

重定向

用于将 http 重定向到 HTTPS 。

server {
    listen 80;
    listen [::]:80;
    server_name xxx.com;
    rewrite ^(.*)$ https://$host$1 permanent;
}