使用 curl -vvv 简单窥探 HTTPS (TLS 通信)

10 min

language: ja bn en es hi pt ru zh-cn zh-tw

大家好,我是无能。

前言

HTTPS 本身是 TLS 通信,正如 HTTP over TLS 所述,HTTP 通信被 TLS 通信包裹。如果只关注 TLS 通信,它将与针对支持 HTTPS 通信的域的请求有所不同。因此,通过使用 curl -vvv 进行详细调试,可以从 client hello 开始确认该通信。话虽如此,这只是我偶然发现的。

查看

那么,我们来如下窥探一下。

curl -vvv -sl
-vvv # 详细调试选项
-s # 静默模式,可省略
-I # 仅将头部输出到标准输出

那么,让我们看看吧。

$ curl -vvv https://soulminingrig.com/ -sI
19:30:07.019276 [0-x] == Info: [READ] client_reset, clear readers
19:30:07.064770 [0-0] == Info: Host soulminingrig.com:443 was resolved.
19:30:07.065031 [0-0] == Info: IPv6: (none)
19:30:07.065180 [0-0] == Info: IPv4: 167.179.75.206
19:30:07.065413 [0-0] == Info: [HTTPS-CONNECT] adding wanted h2
19:30:07.065587 [0-0] == Info: [HTTPS-CONNECT] added
19:30:07.065718 [0-0] == Info: [HTTPS-CONNECT] connect, init
19:30:07.065881 [0-0] == Info:   Trying 167.179.75.206:443...
19:30:07.066065 [0-0] == Info: [HTTPS-CONNECT] connect -> 0, done=0
19:30:07.066197 [0-0] == Info: [HTTPS-CONNECT] Curl_conn_connect(block=0) -> 0, done=0
19:30:07.066400 [0-0] == Info: [HTTPS-CONNECT] adjust_pollset -> 1 socks
19:30:07.083945 [0-0] == Info: [HTTPS-CONNECT] connect -> 0, done=0
19:30:07.084308 [0-0] == Info: [HTTPS-CONNECT] Curl_conn_connect(block=0) -> 0, done=0
19:30:07.084750 [0-0] == Info: [HTTPS-CONNECT] adjust_pollset -> 1 socks
19:30:07.095330 [0-0] == Info: [SSL] cf_connect()
19:30:07.095574 [0-0] == Info: [SSL] ossl_connect, step1
19:30:07.098502 [0-0] == Info: ALPN: curl offers h2,http/1.1
19:30:07.098614 [0-0] == Info: [SSL] ossl_connect, step2
19:30:07.099069 [0-0] => Send SSL data, 5 bytes (0x5)
0000: .....
19:30:07.099205 [0-0] == Info: TLSv1.3 (OUT), TLS handshake, Client hello (1):
19:30:07.099360 [0-0] => Send SSL data, 1563 bytes (0x61b)
~省略~

结果出现了大量的字符串……

通信确认

在这里,端口 443 上的 DNS 名称解析成功了。

19:30:07.064770 [0-0] == Info: Host soulminingrig.com:443 was resolved.

在这里,我们请求并成功建立了 h2 (HTTP/2) 连接。

19:30:07.065413 [0-0] == Info: [HTTPS-CONNECT] adding wanted h2
19:30:07.065587 [0-0] == Info: [HTTPS-CONNECT] added
19:30:07.065718 [0-0] == Info: [HTTPS-CONNECT] connect, init
19:30:07.065881 [0-0] == Info:   Trying 167.179.75.206:443...
19:30:07.066065 [0-0] == Info: [HTTPS-CONNECT] connect -> 0, done=0

然后 SSL/TLS 通信终于开始了。

19:30:07.095330 [0-0] == Info: [SSL] cf_connect()
19:30:07.095574 [0-0] == Info: [SSL] ossl_connect, step1
19:30:07.098502 [0-0] == Info: ALPN: curl offers h2,http/1.1
19:30:07.098614 [0-0] == Info: [SSL] ossl_connect, step2
19:30:07.099069 [0-0] => Send SSL data, 5 bytes (0x5)

接着,TLS 1.3 上的 client hello TLS 握手终于开始了!

19:30:07.099205 [0-0] == Info: TLSv1.3 (OUT), TLS handshake, Client hello (1):

作为客户端发送,数据包传输开始。

19:30:07.099205 [0-0] == Info: TLSv1.3 (OUT), TLS handshake, Client hello (1):
19:30:07.099360 [0-0] => Send SSL data, 1563 bytes (0x61b)
0000: .........r.q.....GC...._4....k..C.P... ..?...x...HT..09..z4b....
0040: ..,9....<.......,.0.........+./...$.(.k.#.'.g.....9.....3.....=.
0080: <.5./..................soulminingrig.com........................
00c0: .............h2.http/1.1.........1.....6.4......................
0100: ...............................+........-.....3...........RIw..7

此时,请求本身会以明文形式发送域名 soulminingrig.com,如果服务器支持 SNI,则可以保持一致性。

19:30:07.105068 [0-0] == Info: [SSL] ossl_bio_cf_out_write(len=1568) -> 0, 1568
19:30:07.105244 [0-0] == Info: [SSL] ossl_bio_cf_in_read(len=5) -> 81, 0
19:30:07.105355 [0-0] == Info: [SSL] ossl_populate_x509_store, path=/etc/ssl/certs/ca-certificates.crt, blob=0
19:30:07.114557 [0-0] == Info:  CAfile: /etc/ssl/certs/ca-certificates.crt
19:30:07.114669 [0-0] == Info:  CApath: none
19:30:07.114768 [0-0] == Info: [SSL] SSL_connect() -> err=-1, detail=2
19:30:07.114903 [0-0] == Info: [SSL] SSL_connect() -> want recv
19:30:07.115050 [0-0] == Info: [SSL] cf_connect() -> 0, done=0

此时,客户端持有的根证书已准备就绪。
连接尚未建立。
对于 Let's Encrypt,这似乎对应于 ISRG Root X1
信任链 - Let’s Encrypt

$ grep -A 3 "ISRG Root X1" /etc/ssl/certs/ca-certificates.crt
# ISRG Root X1
-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh

然后 Server Hello 返回了!

19:30:07.178149 [0-0] == Info: [SSL] ossl_bio_cf_in_read(len=122) -> 0, 122
19:30:07.178363 [0-0] == Info: TLSv1.3 (IN), TLS handshake, Server hello (2):
19:30:07.178583 [0-0] <= Recv SSL data, 122 bytes (0x7a)
0000: ...v....y'...?........&.....,5O....... ..?...x...HT..09..z4b....
0040: ..,9.........+.....3.$... F........`~..l[..uhE..F.P?..V..6
19:30:07.179600 [0-0] == Info: [SSL] ossl_bio_cf_in_read(len=5) -> 0, 5
19:30:07.179730 [0-0] <= Recv SSL data, 5 bytes (0x5)

接着,服务器端返回了证书。

19:30:07.183139 [0-0] <= Recv SSL data, 2049 bytes (0x801)
0000: ...........0...0.................g...4...C..0...*.H.=...021.0...
0040: U....US1.0...U....Let's Encrypt1.0...U....E50...250714140356Z..2
0080: 51012140355Z0.1.0...U....soulminingrig.com0Y0...*.H.=....*.H.=..
00c0: ..B...V...$.....}.hN.f......n@F&...GR.....-.....?z]6d.=..<..eu..

服务器使用其私钥发送了签名。

0000: .
19:30:07.199683 [0-0] == Info: TLSv1.3 (IN), TLS handshake, CERT verify (15):
19:30:07.199941 [0-0] <= Recv SSL data, 79 bytes (0x4f)

至此,TLS 握手终于完成并建立。

19:30:07.202057 [0-0] == Info: TLSv1.3 (IN), TLS handshake, Finished (20):

不常见的 TLS 握手

起初,当我询问 ChatGPT 等工具时,它们都建议使用 Wireshark,但 Wireshark 常常会产生很多噪音,所以我一直在想有没有更简单的方法来检查。然后我突然想到并尝试了一下,结果成功了。
作为 TLS 握手失败的模式,尝试使用以下网站进行检查可能会很有趣:
badssl.com

$ curl -vvv -sl https://wrong.host.badssl.com/
19:50:53.161049 [0-x] == Info: [READ] client_reset, clear readers
19:50:53.202041 [0-0] == Info: Host wrong.host.badssl.com:443 was resolved.
19:50:53.202233 [0-0] == Info: IPv6: (none)
19:50:53.202326 [0-0] == Info: IPv4: 104.154.89.105
19:50:53.202496 [0-0] == Info: [HTTPS-CONNECT] adding wanted h2
~~~
19:50:53.759424 [0-0] == Info: SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256 / secp256r1 / rsaEncryption
19:50:53.759894 [0-0] == Info: ALPN: server accepted http/1.1
19:50:53.760124 [0-0] == Info: [SSL] ossl_connect, step3
19:50:53.760337 [0-0] == Info: Server certificate:
19:50:53.760541 [0-0] == Info:  subject: CN=*.badssl.com
19:50:53.760763 [0-0] == Info:  start date: Jul 15 20:02:58 2025 GMT
19:50:53.761029 [0-0] == Info:  expire date: Oct 13 20:02:57 2025 GMT
19:50:53.761406 [0-0] == Info:  subjectAltName does not match hostname wrong.host.badssl.com
19:50:53.761853 [0-0] == Info: SSL: no alternative certificate subject name matches target hostname 'wrong.host.badssl.com'
19:50:53.762409 [0-0] == Info: [SSL] cf_connect() -> 60, done=0

在这种情况下,证书是为 *.badssl.com 获取的,但应该为 *.host.badssl.com 获取通配符证书,所以它因为这个错误而报错了。

那么,再见。请多关照。

Related Posts