前几天逛L站的时候,看到有网友发了一个咨询帖子,说他有一个个人网站,想用Reqable抓包分析一下流量,但是开启代理后浏览器无法访问,关闭后可以正常访问,不确定是哪里的原因。我排查定位了下,这里给大家做个简单的分享。
1. 问题复现
问题还是很容易复现的,打开Reqable启用系统代理并抓包,使用Chrome浏览器访问网站,看到浏览器报错ERR_CONNECTION_CLOSED,Reqable中能看到此域名的流量,但是状态全是黄色警告,点开一条记录提示是服务器SSL握手失败。

我们经常会遇到的是客户端SSL握手失败,往往是客户端不信任中间人签发的证书,中断请求。这里的服务器SSL握手失败,表明是服务器拒绝了握手,导致连接失败。
服务器拒绝SSL连接的原因下面这些:
- 启用了双向验证。需要客户端内置证书才能访问,浏览器这里绝无可能,我们可以排除掉。
- 启用了SSL指纹校验。一般为了防抓包,服务器会校验客户端请求的指纹是否和预期一致。这位网友说只是Nginx部署了一个静态网页项目,没有这种可能。
- SSL/TLS版本不一致的问题。比如服务器强制使用了TLS 1.3,用到一些比较新的加密套件算法,密钥协商算法等。Reqable可能由于版本过低,或者算法不支持导致服务器SSL握手失败。
Reqable使用的是OpenSSL作为SSL支持,编译的是1.1.1n版本,OpenSSL现在主要是支持3.x版本,已经更新到3.6了。
我怀疑问题可能出现在这里,下面来验证一下。
2. 原因排查
我看了下电脑安装的OpenSSL版本恰好是最新的3.6版本。
yaml
openssl -vOpenSSL 3.6.0 1 Oct 2025 (Library: OpenSSL 3.6.0 1 Oct 2025)
下面用OpenSSL命令来测试下这个网站的域名。
bash
openssl s_client -connect xxx.top:443
控制台输出能看到SSL正常连接,没什么问题:
vbnet
Connecting to xxx.xxx.xxx.xxx
CONNECTED(00000005)
depth=2 C=US, O=Internet Security Research Group, CN=ISRG Root X1
verify return:1
depth=1 C=US, O=Let's Encrypt, CN=R12
verify return:1
depth=0 CN=xxx.top
verify return:1
下面我们开始搬出大杀器Wireshark,来分析具体的SSL/TLS层协议,看看Reqable和浏览器哪里不同。

主要是看ClientHello包,里面包含了客户端的SSL各种信息。上图左边是浏览器的数据包,右边是Reqable的数据包。重点观察的部分,我已经用红框标出来了,主要有三个部分。
- Cipher Suites,加密套件。如果服务器指定了某个加密套件,但是Reqable支持的加密套件列表里面不包含,就可能出现SSL握手失败的情况。从浏览器访问回复的ServerHello包来看,选择的是加密套件是Cipher Suite: TLS_AES_128_GCM_SHA256 (0x1301),已经在Reqable支持的列表中,故而可以排除掉。
- Extension: signature_algorithms,支持算法列表。Reqable提供了19种算法,浏览器提供了8种算法,仔细对比发现,Reqable并没有缺少的部分。
- Extension: key_share 密钥协商算法(也被称为密钥协商)。这是TLS 1.3新增的重要扩展,用于减少握手步骤和增加前向安全。浏览器支持X25519MLKEM768和X25519,Reqable只支持X25519。
我们怀疑是密钥协商算法不支持X25519MLKEM768导致的,这个算法从OpenSSL 3.5版本才开始支持的。为了验证这个问题,我们可以在OpenSSL的命令中使用-curves来指定。
arduino
openssl s_client -connect xxx.top:443 -curves X25519
我们发现SSL握手失败了。
bash
Connecting to xxx.xxx.xxx.xxx
CONNECTED(00000005)
4061CE0C02000000:error:0A000410:SSL routines:ssl3_read_bytes:ssl/tls alert handshake failure:ssl/record/rec_layer_s3.c:916:SSL alert number 40
重新用-curves来指定为X25519MLKEM768:X25519则可以正常握手(注意中间用冒号隔开)。
arduino
openssl s_client -connect xxx.top:443 -curves X25519MLKEM768:X25519
3. 修复方案
我们接下来考虑如何在Reqable中修复这个问题,首先需要更新OpenSSL版本到3.5以上。这个比较麻烦,由于我们C++库使用CMake构建并编译,OpenSSL并不支持CMake,更新比较麻烦。不过有个暂时取巧的办法,编译时直接链接到本机已安装的OpenSSL库。
作为临时测试,我们修改代码,强行设置密钥交换算法为X25519MLKEM768:X25519。如果要完整处理,我们需要还原客户端的密码交换算法。
c++
SSL_set1_groups_list(ssl, "X25519MLKEM768:X25519");
重新编译,再次运行Reqable开始抓包,看起来没有问题了。

4. 更新计划
目前的3.0版本我们还没有修复这个问题,计划在后面3.1版本处理。3.0后续还有几个小版本,预计在12月之内完成,明年正式开始3.1版本的开发。
3.1版本主要会优化抓包部分的功能和实现,包括集成最新OpenSSL库、还原SSL指纹、增强模式优化和重写依赖原始服务器响应等问题。
Reqable,最强API抓包和测试工具,欢迎访问我们的官网:reqable.com