SSL/TLS证书以及H2与H2C
发布于2024-11-09 19:20:07,更新于2025-06-23 01:25:45,标签:java http tls 文章会持续修订,转载请注明来源地址:https://meethigher.top/blog之前写的HTTP反向代理工具,在实际使用时,碰到反代失败的问题。跟踪了一下,才发现是由于对方使用了自签名SSL证书,导致发起HTTP请求时,验证失败。因此简单记录一下。
针对该问题的复现,从两个方面来展开
- 理解SSL/TLS
- 忽略SSL/TLS
一、理解SSL/TLS
1.1 HTTPS与SSL/TLS
SSL是用于加密传输的协议,也是最初的加密标准,目前已被TLS取代,但由于历史原因,大家还是会称为SSL。
HTTPS是HTTP上实现加密传输的协议,依赖SSL/TLS来确保安全性。
从不求甚解的角度来理解,HTTPS=HTTP+SSL/TLS
1.2 证书分类
SSL常见的证书分类有两种
- 公共CA证书
- 自签名证书
这两者的区别如下
特性 | 自签名证书 | 公共CA证书 |
---|---|---|
签发机构 | 由证书持有者自己签发 | 由受信任的证书颁发机构(CA)签发 |
信任级别 | 默认不被浏览器或操作系统信任,需手动安装信任 | 浏览器和操作系统默认信任 |
身份验证 | 无身份验证,持有者自行生成证书 | CA会对证书持有者进行身份验证 |
安全性 | 安全性较低,可能被伪造或滥用 | 高安全性,通过身份验证保障证书真实性 |
应用场景 | 适用于开发、测试和内部网络 | 适用于生产环境和面向互联网的服务 |
成本 | 免费 | 需要付费,费用根据证书类型和CA机构不同而异 |
浏览器警告 | 会弹出“不安全连接”警告 | 不会弹出警告,用户信任度高 |
管理复杂度 | 管理简单,但不适合公开环境 | 管理较复杂,需要向CA申请和续期 |
互联网服务使用的一般都是CA证书,由于操作系统已经内置了一系列根证书,当访问一个使用CA签发证书的HTTPS网站时,就不会出现“不安全连接”的警告。
而自签名证书,由于操作系统缺少对其的信任,访问就会被拦截了。此时服务提供方,需要给调用方提供自签名证书,以便调用方可以信任该连接。
1.3 OpenSSL生成自签名证书
1.3.1 扩展名说明
像我购买的CA证书,部署到Nginx时,一般都是.pem
和.key
文件。但在自己生成证书的过程中,发现还有.crt
文件。直观的感受是,这些扩展名特别的混乱。经过查阅资料,下面简单记录这些扩展名的区别。
- crt: 存储证书(公钥)。该证书可提供给第三方使用,比如HTTPS客户端
- key: 私钥。该私钥文件只应给服务提供者使用。
- csr: 向证书颁发机构申请签署密钥的请求,不包含密钥本身。
- pem: 基于Base64编码的文本格式。它可以是上述任何文件。
- der: 基于二进制编码的文本格式。它可以是上述任何文件。
参考
ssl - Difference between pem, crt, key files - Stack Overflow
Difference between .pem and .crt and how to use them - Help - Let’s Encrypt Community Support
1.3.2 自签名证书
下面使用OpenSSL生成自签名的公钥和私钥证书。
1 | # 生成一个2048位的RSA私钥,并保存到private.key文件中 |
上面这段是标准的自签名证书生成流程,但缺少 Subject Alternative Name (SAN)
字段(未指定域名),所以不能用于现代浏览器或 curl、Java 客户端。
下面放置一个可用的,也就是指定域名。
1 | # 生成一个2048位的RSA私钥,并保存到private.key文件中 |
二、忽略SSL/TLS
2.1 服务端部署证书
2.1.1 Nginx
以Nginx为例,部署证书
1 | worker_processes 1; |
2.1.2 Vertx
使用Java中的Vertx 4.5.10版本开启HTTPServer
1 | PemKeyCertOptions pemKeyCertOptions = new PemKeyCertOptions()//使用自签名证书开启ssl |
2.2 客户端忽略校验
2.2.1 CURL
curl忽略ssl校验比较简单,添加-k
参数即可。
1 | curl -k "https://10.0.0.10:443" |
2.2.2 Apache HttpPClient and OkHttpClient
设置忽略SSL的核心逻辑如下,具体的写法还需根据框架而定。
1 | /** |
三、Certbot自动更新Nginx证书
3.1 安装与配置
具体的安装步骤,可自行查阅官网,很详细。
3.1.1 snapd
安装snap软件包管理工具
1 | # 安装 Snapd(Snap 软件包管理工具) |
3.1.2 certbot
1.) 使用snpa安装certbot
1 | # 通过 Snap 安装 Certbot,并使用 --classic 选项启用传统模式 |
2.) 初次生成证书
1 | # 使用 Certbot 为域名 meethigher.top 申请 SSL 证书,并配置 Nginx |
成功时输出内容如下
另外,他会自动进行nginx.conf
的维护。
生成证书的记录可以通过crt.sh查看
3.) 模拟证书生成流程。此处我遇到报错了,不过该模拟过程的报错可以忽略,直接进行下一步。
1 | sudo certbot renew --dry-run |
该问题在官方论坛也有讨论,First Time Problem - certbot failed to auth during secondary validation - Help - Let’s Encrypt Community Support
4.) 移除自带定时任务。
1 | systemctl list-timers --all |
5.) 配置自定义定时任务。强制覆盖更新证书。
输入crontab -e
,追加一行,内容如下
1 | 0 1 1 3,6,9,12 * /usr/bin/certbot renew --force-renew |
表示在每年的 3 月、6 月、9 月和 12 月的 1 日,凌晨 1:00 运行 certbot 进行 SSL 证书的强制覆盖续期。
Certbot根据/etc/letsencrypt/renewal/*.conf
文件来确定有哪些证书是它“负责”的。
3.3 参考
Certbot Instructions | Certbot
使用CertBot自动更新Nginx的ssl证书 - pyt123456 - 博客园
Nginx配置使用certbot自动申请HTTPS证书-腾讯云开发者社区-腾讯云
四、h2与h2c
本文的示例代码meethigher/bug-test at vertx-http-alpn
4.1 理解h2与h2c
h2 与 h2c 是基于 http2 通信的两种模式。
h2 即 http/2 over tls,直观理解就是 https://xxx
形式的 http2 请求。
h2c 即 http/2 over cleartext,直观理解就是 http://xxx
形式的 http2请求。
4.2 h2与alpn协议
ALPN 的全名是 Application-Layer Protocol Negotiation,中文可以叫“应用层协议协商”。
它是用在 TLS(加密通信协议) 里的一个扩展,用来让客户端和服务器在建立加密连接之前,商量好用什么具体的应用协议,比如 HTTP/1.1、HTTP/2、HTTP/3 等。
协商的过程大致是这样:
- 客户端发起 TLS 握手时,告诉服务器:“我支持 HTTP/2、HTTP/1.1!”
- 服务器收到后选择一个协议,比如:“那就用 HTTP/2 吧!”
- TLS 握手完成后,双方就都知道接下来的通信用的是 HTTP/2。
ALPN 只能用于 HTTPS(加密通信),不能用于明文 HTTP。
4.3 h2c与prior knowledge
参考RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2)
h2c 是 HTTP/2 over cleartext TCP,即基于明文 TCP 的 HTTP/2 协议。h2c 支持两种连接方式
- 带 Upgrade 头的 h2c 升级方式
- h2c 明文直连(prior knowledge)
带 Upgrade 头的 h2c 升级方式,标准格式
1 | > GET /test HTTP/1.1 |
h2c 明文直连(prior knowledge),建立连接后立即发送的“连接前言”(connection preface)。格式如下
1 | PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n |
Vertx 的 HTTPClient 默认并不支持 prior knowledge,因此使用 okhttp 实现。
1 | private static void h2cPriorKnowledge() { |