建站系列之 HTTPS 优化:ECC/RSA 双证书、TLS1.3、OSCP Stapling、HTTP/2、QUIC

温馨提示:
本文所述内容具有依赖性,可能因软硬条件不同而与预期有所差异,故请以实际为准,仅供参考。

基于安全性考虑,越来越多的网站都支持了 HTTPS 访问,相较 HTTP 明文传输数据,HTTPS 加密传输更加安全,但是相对的,通过 HTTPS 访问速度会略有降低,因此我们需要考虑如何优化 HTTPS,提高连接速度。

HTTP/HTTPS 连接

HTTP(HyperText Transfer Protocol)超文本传输协议是互联网上应用最为广泛的一种网络协议。由于信息是明文传输,所以被认为是不安全的。而关于 HTTP 的三次握手,其实就是使用三次 TCP 握手确认建立一个 HTTP 连接。
HTTPS(HyperText Transfer Protocol Secure)超文本传输安全协议是一种通过计算机网络进行安全通信的传输协议。HTTPS 经由 HTTP 进行通信,但利用 SSL/TLS 来加密数据包,因此相较 HTTP,HTTPS 在三次握手基础上增加了 SSL/TLS 加密过程。

下图是 HTTP 跳转 HTTPS 连接的过程:

301.jpg

可以很清楚的看出整个连接过程。根据 TCP/IP 连接原理,我们可以从几个方面去优化:

  • 服务端发送的 SSL 证书大小(ECC/RSA 双证书);
  • 服务端与客户端 TLS 握手(TLS1.3);
  • 客户端 SSL 证书验证(OSCP Stapling);
  • 应用层优化(HTTP2);
  • 传输层优化(QUIC);

以下均以 Nginx 为例来说明。文章较长,可通过目录快速定位。

ECC/RSA 双证书

背景

随着分解大整数方法的进步及完善、计算机速度的提高以及计算机网络的发展,为了保障数据的安全,RSA 的密钥需要不断增加(1024B、2048B、3072B),虽然兼容性很好,但是,密钥长度的增加导致了其加解密的速度大为降低,硬件实现也变得越来越难以忍受,这对使用 RSA 的应用带来了很重的负担。

相比 RSA, ECC 密钥不仅更短(意味着解密速度很快),而且很难破解。举例来说:根据通用安全(Universal Security)的一项研究,计算机破解一个 228 位 RSA 密钥所消耗的能量大约足以烧开一茶匙水。破解同样大小的 228 位 ECC 密钥所需的能量将超过煮沸地球上所有水所需的能量。差距显而易见。

以下是一份 ECC 密钥大小的具体情况,以及与它们安全性对等的 RSA 密钥的大小:

ECC 密钥大小RSA密钥大小
160 位1024 位
224 位2048 位
256 位3072 位
384 位7680 位
521 位15360 位

在 RSA 密钥交换中,浏览器使用证书提供的 RSA 公钥加密相关信息,如果服务端能解密,意味着服务端拥有证书对应的私钥,同时也能算出对称加密所需密钥。密钥交换和服务端认证合并在一起。

在 ECC 密钥交换中,服务端使用证书私钥对相关信息进行签名,如果浏览器能用证书公钥验证签名,就说明服务端确实拥有对应私钥,从而完成了服务端认证。密钥交换和服务端认证是完全分开的。

ECC 支持度

以下是主流操作系统、浏览器和软件对 ECC 的具体支持情况:

系统最低版本要求
Apple OS XOS X 10.6
Microsoft WindowsWindows Vista
Red Hat Enterprise Linux6.5
IOSIOS 7.x
Android OS3.x
Microsoft Windows Phone7.x
浏览器最低版本要求
Apple Safari4
Google Chrome1.0
Microsoft Internet Explorer7
Mozilla Firefox2.0
Web 服务器最低版本要求
Apache HTTP Server2.2.26+
Apache Tomcat1.1.30+
Dovecot2.2.5+
IBM HTTP Server8.0+
NGINX1.1.0+
Windows Server2008+
软件、开发语言最低版本要求
Bouncy Castle1.04+
GnuTLS2.99.2
Java JDK5+
NSS3.8+
OpenSSL0.9.8+
OpenSSL FIPS Object Module2.0 (OpenSSL 1.0.1)

配置 ECC/RSA 双证书

由上节中可以看出,除了古董级别的系统和软件(如 Windows XP),更新到现在其实没有不支持 ECC 算法的,SSL 证书只要配置 ECC 完全足够。不过像银行、政企单位等需要面向的是广泛客户,还是需要考虑保留 RSA 证书。

签发证书

在线申请的证书一般在选择证书类型时指定 ECC 即可,下面是利用 ACME 申请的例子:

ACME 签发 RSA 证书:

./acme.sh --server https://api.buypass.com/acme/directory --issue -d vircloud.net -d www.vircloud.net -d armx.vircloud.net -d blog.vircloud.net --dns --yes-I-know-dns-manual-mode-enough-go-ahead-please

ACME 签发 ECC 证书:

./acme.sh --server https://api.buypass.com/acme/directory --keylength ec-256 --issue -d vircloud.net -d www.vircloud.net -d armx.vircloud.net -d blog.vircloud.net --dns --yes-I-know-dns-manual-mode-enough-go-ahead-please

区别在于指定密钥类型为 --keylength ec-256,具体可参考《BuyPass 免费多域名 SSL 证书申请方法》。

服务器配置

配置 ECC/RSA 双证书与只配置 RSA 证书并无本质区别,只要把 ECC 证书路径和加密算法加上即可:

                ssl_certificate vircloud.net.crt; # 指定 RSA 证书路径
                ssl_certificate_key vircloud.net.key;

                ssl_certificate ecc/vircloud.net.crt; # 指定 ECC 证书路径
                ssl_certificate_key ecc/vircloud.net.key;

                ssl_ciphers 'TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-128-CCM-8-SHA256:TLS13-AES-128-CCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS'; # 指定加密算法,主要是 ECDHE 类

测试

我们知道,RSA 证书使用的是 RSA 算法,ECC 证书使用的是 ECDHE 算法,所以我们使用 curl 命令指定加密算法来验证双证书是否生效:

[root@ct ttfb]# curl -vso /dev/null  https://www.vircloud.net/ --ciphers rsa_aes_128_sha --resolve www.vircloud.net:443:1.1.1.1
......
* SSL connection using TLS_RSA_WITH_AES_128_CBC_SHA
* Server certificate:
*     subject: CN=vircloud.net
*     start date: Jan 22 00:27:13 2021 GMT
*     expire date: Jul 21 21:59:00 2021 GMT
*     common name: vircloud.net
*     issuer: CN=Buypass Class 2 CA 5,O=Buypass AS-983163327,C=NO
......
[root@ct ttfb]# curl -vso /dev/null  https://www.vircloud.net/ --ciphers ecdhe_ecdsa_aes_128_sha --resolve www.vircloud.net:443:1.1.1.1
......
* SSL connection using TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
* Server certificate:
*     subject: CN=vircloud.net
*     start date: Jan 26 01:56:35 2021 GMT
*     expire date: Jul 25 21:59:00 2021 GMT
*     common name: vircloud.net
*     issuer: CN=Buypass Class 2 CA 5,O=Buypass AS-983163327,C=NO
......

可以看到双证书已经生效[注1],但是无法确认证书类型是什么[注2],所以我们再用 openssl 命令直接查看证书[注3]

[root@ct ttfb]# openssl s_client -connect 1.1.1.1:443 -servername www.vircloud.net -cipher ECDHE-RSA-AES128-SHA256 2>&1 < /dev/null | sed -n '/-----BEGIN/,/-----END/p' | openssl x509 -noout -text
......
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:d2:d3:18:17:81:77:f6:b3:9d:35:1f:92:48:5f:
                    14:e1:f3:7b:08:79:3c:dc:57:1f:c8:54:74:eb:1a:
                    28:e2:b5:6c:d6:c1:a4:91:4b:a8:01:86:e6:5b:6a:
                    1a:21:ce:53:01:32:cf:79:ce:18:e3:bc:98:fa:2d:
                    b7:1d:cb:1a:2d:57:2d:0e:52:a9:45:75:eb:a2:d7:
                    6c:34:41:f6:c8:f8:da:60:25:e5:53:23:eb:68:e4:
                    3c:df:a7:76:2a:52:8f:57:08:66:e5:11:a3:b1:da:
                    93:78:e7:a7:8a:19:04:39:8f:ea:99:c7:66:2a:dc:
                    57:5b:87:8b:9e:2d:2a:d7:ff:ac:35:f4:8a:21:64:
                    18:89:30:6d:05:e7:65:fd:3e:d4:d6:bd:47:db:d5:
                    4d:4f:e3:d8:25:2b:8a:b2:d9:38:d8:b1:a8:2a:f5:
                    c2:32:b5:25:38:fb:c9:ec:02:35:6a:e5:07:8f:00:
                    4a:8a:88:1b:f1:09:91:76:2e:62:3d:12:a2:3c:18:
                    7e:d3:96:95:1d:de:74:2c:e3:9e:10:ef:0a:a1:ab:
                    f5:28:ea:f3:91:f5:f5:1c:5c:07:b7:99:72:15:63:
                    28:28:9e:33:c0:af:7e:58:c7:85:8f:57:86:d6:e2:
                    73:ac:b4:1f:c5:be:49:2b:ae:f7:d9:c0:94:a6:ac:
                    88:0d
                Exponent: 65537 (0x10001)
......
[root@ct ttfb]# openssl s_client -connect 1.1.1.1:443 -servername www.vircloud.net -cipher ECDHE-ECDSA-AES128-GCM-SHA256 2>&1 < /dev/null | sed -n '/-----BEGIN/,/-----END/p' | openssl x509 -noout -text
......
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub: 
                    04:ef:ee:3f:cd:45:87:1c:3a:b2:31:c2:b3:58:7c:
                    2c:0b:a8:c6:89:fb:a3:9e:27:2b:7b:98:d5:95:2b:
                    41:31:39:06:89:8b:ca:75:40:55:9b:0b:72:fa:52:
                    f6:9d:f4:1b:fe:ff:6b:4f:48:de:a3:18:34:ab:6a:
                    7f:0f:54:c6:99
                ASN1 OID: prime256v1
                NIST CURVE: P-256
......

可以看到根据客户端支持加密方法的不同,服务端响应了对应的 ECC 或 RSA 证书,从截取的部分也可以明显发现 ECC 长度远小于 RSA。

TLS 1.3

背景

SSL 协议本意是保证数据传输的保密,但在实际应用中不断发现漏洞和使用问题,故而从发布到现在历经 SSL 1.0、SSL 2.0、SSL 3.0、TLS 1.0、TLS 1.1、TLS 1.2、TLS 1.3 等多个版本,在新版本发布后逐渐淘汰旧版本,目前 TLS1.0 及以前的版本已被公认为不安全协议。

TLS 1.3 是迄今为止改动最大的一次。针对目前已知的安全威胁,TLS 1.3 有望成为有史以来最安全,但也最复杂的 TLS 协议。TLS 1.3 与之前的协议有较大差异,主要在于:

  • 相比过去的的版本,引入了新的密钥协商机制 PSK;
  • 支持 0-RTT 数据传输,在建立连接时大大节省往返时间
  • 废弃了 3DES、RC4、AES-CBC 等加密组件,废弃了 SHA1、MD5 等哈希算法;
  • ServerHello 之后的所有握手消息采取了加密操作,可见明文大大减少
  • 不再允许对加密报文进行压缩、不再允许双方发起重协商,安全性大大提升
  • DSA 不再允许在 TLS 1.3 中使用;

TLS 1.3 支持度

tls1.3.jpg

可见除 IE 外,现在主流浏览器均已支持 TLS 1.3。

启用 TLS1.3

参考《建站系列之 Nginx 开启 TLSv1.3 支持》。

OSCP Stapling

背景

OCSP Stapling(OCSP 装订),正式名称为 TLS 证书状态查询扩展,可代替在线证书状态协议(Online Certificate Status Protocol,OCSP)来查询 X.509 证书的状态。

数字证书认证机构(CA)给网站颁发证书之后,网站的每个访问者都会进行 OCSP 查询。因此使用在线证书协议时,高并发的请求会给 CA 的服务器带来很大的压力。同时由于必须和 CA 建立连接,OCSP 查询还会影响浏览器打开页面的速度并泄漏用户隐私。此外,当 OCSP 查询无法得到响应时,浏览器必须选择是否在无法确认证书状态的情况下继续连接,造成安全性和可用性二选一的困局。

OCSP 装订解决了在线证书协议中的大多数问题,服务器在 TLS 握手时发送事先缓存的 OCSP 响应,用户只需验证该响应的有效性而不用再向 CA 发送请求,从而提升安全性和连接速度。

启用 OSCP Stapling

参考《利用 OpenSSL 搭建自签 SSL 证书的 OCSP 状态在线验证服务及 OCSP Stapling 说明》。

HTTP/2

背景

HTTP/2(超文本传输协议第 2 版,最初命名为 HTTP 2.0),简称为 h2(基于 TLS/1.2 或以上版本的加密连接)或 h2c(非加密连接),是 HTTP 协议的的第二个主要版本。在实际应用中,h2c 不被主流浏览器支持,但几乎都已支持 h2,不过超过半数的网站也还支持 HTTP/1.1。

相比上一版本 HTTP/1.1,HTTP/2 保留了 HTTP/1.1 的大部分语义,例如请求方法、状态码乃至 URI 和绝大多数 HTTP 头部字段一致,主要区别在于采用了新的方法来编码、传输客户端与服务器之间的数据:

  • 二进制传输:将请求和响应数据分割为更小的帧,并且它们采用二进制编码,解析起来更高效;
  • 多路复用:同域名下所有通信都在单个连接上完成,单个连接可以承载任意数量的双向数据流,数据流以消息的形式发送,而消息又由一个或多个帧组成,多个帧之间可以乱序发送,因为根据帧首部的流标识可以重新组装;
  • Header 压缩:在客户端和服务器端使用“首部表”来跟踪和存储之前发送的“键-值”对,对于相同的数据,不再通过每次请求和响应发送;
  • Server Push:即服务端能通过 push 的方式将客户端需要的内容预先推送过去,也叫“cache push”。

启用 HTTP/2

在 Nginx 中,HTTP/2 支持由 ngx_http_v2_module 模块提供,Nginx 1.9.5 及之后版本均已支持,但需要在编译时加入 --with-http_v2_module 参数,示例:

[root@ct src]# ./configure -user=www --group=www --prefix=/usr/local/nginx --with-http_ssl_module --with-http_v2_module

注意,前面提到主流浏览器仅支持基于 TLS/1.2 或以上版本的加密连接(h2),所以启用 HTTP/2 时,也需要启用 SSL。

编译后(如果是通过 yum 或着 apt 等命令直接装的 Nginx,默认已经集成 h2),将 h2 添加到网站配置中:

[root@ct src]# cat vircloud.net.conf
......
server
        {
                listen 443  ssl http2;
                listen [::]:443 ssl http2;

                server_name vircloud.net;

                ssl_certificate vircloud.net.crt;
                ssl_certificate_key vircloud.net.key;
                ssl_protocols TLSv1.2 TLSv1.3
......

QUIC

背景

上文提到 HTTP/2 使用了多路复用,一般来说同一域名下只需要使用一个 TCP 连接。但当这个连接中出现了丢包的情况,那就会导致 HTTP/2 的表现情况反倒不如 HTTP/1 了。因为在出现丢包的情况下,整个 TCP 都要开始等待重传,也就导致了后面的所有数据都被阻塞了。但是对于 HTTP/1.1 来说,可以开启多个 TCP 连接,出现这种情况反到只会影响其中一个连接,剩余的 TCP 连接还可以正常传输数据。

那么可能就会有人考虑到去修改 TCP 协议,其实这已经是一件不可能完成的任务了。因为 TCP 存在的时间实在太长,已经充斥在各种设备中,并且这个协议是由操作系统实现的,更新起来不大现实。

基于这个原因,Google 就更起炉灶搞了一个基于 UDP 协议的 QUIC 协议,并且使用在了 HTTP/3 上,HTTP/3 之前名为 HTTP-over-QUIC,从这个名字中我们也可以发现,HTTP/3 最大的改造就是使用了 QUIC。QUIC 虽然基于 UDP,但是在原本的基础上新增了很多功能:

  • 0-RTT:通过使用类似 TCP 快速打开的技术,传输层 0RTT 就能建立连接,加密层 0RTT 就能建立加密连接,而以往版本至少要 3 个 RTT;
  • 多路复用:相较 HTTP/2(TCP),QUIC 在协议层上就原生支持多路复用(UDP),解决了 TCP 存在的阻塞等问题;
  • 加密认证的报文:除了个别报文比如 PUBLIC_RESET 和 CHLO,所有报文头部都是经过认证的,报文 Body 都是经过加密的,只要对 QUIC 报文任何修改,接收端都能够及时发现,有效地降低了安全风险;
  • 向前纠错机制:个数据包除了它本身的内容之外,还包括了部分其他数据包的数据,因此少量的丢包可以通过其他包的冗余数据直接组装而无需重传。

QUIC 支持度

quic.jpg

看以看到,其实现在绝大部分主流浏览器默认并不支持 QUIC,而是需要我们手动开启。

启用 QUIC

参考《利用 Docker + Caddy 开启谷歌 QUIC 快速网络连接协议支持》。


参考文章:

1、《网络分层 TCP/IP 与 HTTP
2、《HTTP与HTTPS握手的那些事
3、《HTTP与HTTPS的区别
4、《您的SSL/TLS证书应该采用ECC加密算法了
5、《SSL Ciphers
6、《s_client
7、《How to convert ssl ciphers to curl format?
8、《ECC SSL证书兼容列表(操作系统、浏览器、Web 服务器等)
9、《开始使用 ECC 证书
10、《一篇文章为你深度解析HTTPS 协议
11、《升级支持ECC证书指南
11、《阿里云环境中TLS/SSL握手失败的场景分析
12、《RSA and ECDSA hybrid Nginx setup with LetsEncrypt certificates generated through Docker image
13、《Transport Layer Security:传输层安全性协议
14、《TLS1.3 VS TLS1.2,让你明白TLS1.3的强大
15、《TLS 1.3 - Can I use... Support tables for HTML5, CSS3, etc
16、《HTTP/2
17、《Module ngx_http_v2_module
18、《一文读懂 HTTP/2 及 HTTP/3 特性
19、《HTTP/3 protocol - Can I use... Support tables for HTML5, CSS3, etc


参考资料:

  1. 博主配置的两个证书签发时间刚好不一样
  2. 实际测试中发现,不同系统不同版本的 CURL 获取到的证书可能不一样,如 CentOS 1.0 版本的 curl 可以正确获得 RSA 证书,但是 Ubuntu 1.1 版本的 curl 获得的证书仍然是 ECC
  3. 实际测试中发现,相同命令不同系统获取到的证书仍然会有差异,所以自测用哪个命令

ArmxMod for Typecho
个性化、自适应、功能强大的响应式主题

推广

 继续浏览关于 nginx教程安全SSL证书优化apache建站系列httpshttp2 的文章

 本文最后更新于 2021/07/28 20:04:14,可能因经年累月而与现状有所差异

 引用转载请注明: VirCloud's Blog > 运维 > 建站系列之 HTTPS 优化:ECC/RSA 双证书、TLS1.3、OSCP Stapling、HTTP/2、QUIC

精选评论

  1. 小杰
    小杰 回复

    Windows 10Chrome 88.0.4324.104来自 福建 的大神

    很有用,感谢