curl--doh-insecure参数详解:跳过 DoH 服务器证书校验的前因后果与源码级剖析
【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features项目地址: https://gitcode.com/GitHub_Trending/cu/curl
curl 默认会对其连接的所有 DNS-over-HTTPS(DoH)服务器执行严格的 TLS 安全校验,而--doh-insecure是 curl 专门为"DoH 解析通道单独关闭证书验证"提供的开关,它与控制普通连接和代理连接的--insecure、--proxy-insecure相互独立、各司其职。本文以 curl 官方命令行选项文档 docs/cmdline-opts/doh-insecure.md 为主线,结合仓库内参数解析、libcurl 选项映射与 DoH 底层实现源码,讲清楚它的语义、使用场景、安全代价,以及它与--doh-url、--doh-cert-status、--insecure的协作与区别,读完你将能准确判断"何时该用、何时绝不可以用"。
参数速览(来自选项文档元数据)
curl 的每个命令行选项都有对应的结构化文档头,--doh-insecure的定义如下:
| 元数据项 | 值 |
|---|---|
| 长选项名 | --doh-insecure(对应--no-doh-insecure关闭) |
| Help 摘要 | Allow insecure DoH server connections |
| Added(加入版本) | 7.76.0 |
| Category | dns tls |
| Protocols | DNS |
| Multi(多值行为) | boolean(可开关的布尔选项) |
| See-also(关联选项) | doh-url、insecure、proxy-insecure |
从元数据可以看出:它属于 DNS 与 TLS 的交界地带,作用是影响基于 TLS 传输的 DoH 解析请求,属于布尔开关,且文档明确将它与普通--insecure、代理专用--proxy-insecure并列为同一族系。
一、为什么需要单独一个"DoH 版 insecure"开关
1.1 先理解 curl 中的 DoH 工作方式
从 curl 8.x 的仓库结构可以看到,DoH 相关实现被独立维护在 lib/vdns/ 目录下(核心文件为 lib/vdns/doh.c)。当用户在命令行上指定:
curl --doh-url https://doh.example/ https://www.example.comcurl 便不再走操作系统默认解析器,而是向doh.example这个HTTPS 服务器发起一次加密的 DNS 查询,从响应中取得www.example.com的解析结果,再去连接目标网站。
因为 DoH 本质上是"跑在 HTTPS 之上的一次普通请求",所以对 DoH 服务器的连接质量、TLS 握手和证书信任同样敏感。
1.2 默认行为:全面校验,绝不跳过
选项文档开篇就明确:
By default, every connection curl makes to a DoH server is verified to be secure before the transfer takes place.
也就是说,默认情况下 curl 在向 DoH 服务器发起解析请求之前,会完整执行证书链校验与主机名校验,只有当 DoH 服务器可信时才会真正发起 DoH 传输。这是 DoH 安全模型的根基:既然信任依赖被从"运营商递归解析器"转移到了"指定 HTTPS 服务器",那么这段 TLS 信任就必须建立起来,否则整个安全前提都不成立。
1.3--doh-insecure的作用
选项文档给出的一句话语义是:
This option tells curl to skip the verification step and proceed without checking.
即:跳过"传输前的校验步骤",不做任何检查就直接与 DoH 服务器建立连接、发送解析请求。
其作用范围与另外两个兄弟选项的分工是:
| 选项 | 关闭校验的连接对象 |
|---|---|
--insecure(即-k) | 本次 curl 与目标服务器的连接 |
--proxy-insecure | 本次 curl 与代理服务器的连接 |
--doh-insecure | 本次 curl 与 DoH 服务器的连接 |
三者的关系可以用一句话概括:--doh-insecure等价于把--insecure、--proxy-insecure的语义套用到了 DoH 解析通道上,但互不继承、只作用于各自的连接段。
二、经典使用场景与实战示例
2.1 最小可复现用法
选项文档给出了标准示例:
curl --doh-insecure --doh-url https://doh.example $URL其中:
--doh-url https://doh.example指定用于域名解析的 DoH 服务器(该参数本身要求 URL 必须是 HTTPS,详见 docs/cmdline-opts/doh-url.md);--doh-insecure允许 curl 跳过对该 DoH 服务器的证书校验;$URL是本次真正要访问的目标地址。
两者必须配合使用才有意义——如果没给--doh-url,则根本没有 DoH 通道,--doh-insecure也就没有作用对象。
2.2 用--resolve显式指定 DoH 服务器 IP
一个值得注意的细节(来自 doh-url 文档):在解析"DoH 服务器自身的主机名"时,DoH 机制默认是被绕过的(否则会形成鸡生蛋的循环依赖)。若希望每次都直连固定的 DoH 服务器,可以用--resolve把它固定下来:
curl --doh-url https://doh.example --resolve doh.example:443:192.0.2.1 $URL这种写法与--doh-insecure正交:--resolve解决的是"DoH 服务器 IP 从哪来",--doh-insecure解决的是"要不要验证 DoH 服务器的证书"。在生产环境里,即使你要用自签名证书的内部 DoH 服务器并开启--doh-insecure,仍建议配合--resolve固定服务器地址,缩小被劫持的面。
2.3 典型但必须警惕的使用动机
历史上--doh-insecure最常见的用途包括:
- 访问使用自签名证书或私有 CA 的内部 DoH 解析器(如企业内网 / 测试环境);
- 排查 DoH 服务器本身的证书问题时,临时绕过校验以定位解析层故障;
- 在受控沙箱或实验室中验证 DoH 报文内容。
这些都属于"你完全信任网络路径、只是证书体系不完整"的场景。选项文档对它的警告同样直白而严厉:
WARNING: using this option makes the DoH transfer and name resolution insecure.
这意味着任何能对 DoH 连接实施中间人攻击(MITM)的人,都能替换返回给你的 DNS 应答,从而把www.example.com指向攻击者控制的地址——解析结果一旦被污染,其危害比普通连接关闭校验更大,因为它连域名到 IP 的第一步都不可信了。
三、--doh-insecure与 DoH 证书校验"三兄弟"的关系
curl 对 DoH 服务器的 TLS 校验被拆成了三个独立维度,均通过以--doh-前缀开头的选项单独控制,这一点在设计上刻意与主传输、代理传输区分开:
| 校验维度 | 命令行选项 | 底层 libcurl 选项 | 默认 |
|---|---|---|---|
| 关闭 DoH 证书链/主机名校验 | --doh-insecure | CURLOPT_DOH_SSL_VERIFYPEER、CURLOPT_DOH_SSL_VERIFYHOST | 校验开启 |
| 启用 DoH OCSP 装订(stapling)状态校验 | --doh-cert-status | CURLOPT_DOH_SSL_VERIFYSTATUS | 关闭 |
| 指定 DoH 服务器 | --doh-url <URL> | CURLOPT_DOH_URL | 未设置(走系统解析器) |
3.1 为什么不继承主连接的证书校验设置
doh-url 文档 中有一句容易被忽略、但非常关键的话:
Some SSL options that you set for your transfer also apply to DoH since the name lookups take place over SSL. The certificate verification settings are not inherited but are controlled separately via
--doh-insecureand--doh-cert-status.
翻译过来是两层意思:
- 一部分 TLS 选项会沿用到 DoH 传输上(因为解析请求也是走 SSL/TLS 的),例如 CA 文件、CA 路径、ClientHello 相关设置等;
- 但证书验证类设置不会被继承,必须显式用
--doh-insecure/--doh-cert-status单独声明。
这一点在源码里能得到直接印证。lib/vdns/doh.c 在为内部 DoH 句柄装配 SSL 参数时,特意注释说明:它会"从用户传输上继承部分 SSL 选项,作为兼容性的最佳猜测(best-guess)",具体只继承了cafile、capath、cablob等证书信任源,而校验开关则完全由doh_verifypeer/doh_verifyhost/doh_verifystatus三个独立标志决定。
因此,即使你在主命令里加了-k(--insecure),DoH 通道也不会随之关闭校验;反过来,只写--doh-insecure也不会影响目标连接与代理连接的校验策略。三者必须按需分别配置。
3.2 与--doh-cert-status的取舍
docs/cmdline-opts/doh-cert-status.md 说明:--doh-cert-status等价于普通传输的--cert-status,它通过 TLS 的 Certificate Status Request(OCSP stapling)扩展验证 DoH 服务器证书的吊销状态。如果服务器返回无效(例如过期)的装订响应、响应表明证书已被吊销,或根本没有响应,则校验失败。
显然--doh-insecure与--doh-cert-status在语义上相互对立:前者跳过全部校验,后者在完整校验之上再叠加吊销状态检查。不应同时开启。另外该文档还提示:OCSP 装订支持目前仅在 OpenSSL 与 GnuTLS 两个 TLS 后端实现。
四、源码级剖析:从命令行参数到内部校验开关
理解--doh-insecure最扎实的方式,是顺着 curl 源码看一条完整的"参数 → libcurl 选项 → 内部标志 → 实际连接"链路。
4.1 第一步:命令行参数解析
curl 的命令行选项表位于 src/tool_getparam.c,其中登记了:
{"doh-insecure", ARG_BOOL|ARG_TLS, ' ', C_DOH_INSECURE},注意ARG_BOOL|ARG_TLS两个标志的组合:ARG_BOOL表示这是可用--no-前缀取反的布尔开关,ARG_TLS表示它只有在构建启用了 TLS 功能时才有意义。对应的处理分支(src/tool_getparam.c)非常简单——只是记录开关状态:
case C_DOH_INSECURE: /* --doh-insecure */ config->doh_insecure_ok = toggle; break;这个布尔字段定义在工具侧配置结构 src/tool_cfgable.h:
BIT(doh_insecure_ok); /* set TRUE to allow insecure SSL connects */4.2 第二步:映射为 libcurl 选项
真正把开关翻译成 libcurl 长生命周期选项的地方是 src/config2setopts.c:
if(config->doh_insecure_ok) { my_setopt_long(curl, CURLOPT_DOH_SSL_VERIFYPEER, 0); my_setopt_long(curl, CURLOPT_DOH_SSL_VERIFYHOST, 0); }可以看到,一个--doh-insecure实际会同时把两个 libcurl 选项置 0:
CURLOPT_DOH_SSL_VERIFYPEER = 0:不验证对端证书链;CURLOPT_DOH_SSL_VERIFYHOST = 0:不校验证书中的主机名。
这与--insecure在下方对CURLOPT_SSL_VERIFYPEER/CURLOPT_SSL_VERIFYHOST的处理方式(同文件第 413–416 行)如出一辙,只是换成了CURLOPT_DOH_*前缀。同文件第 431–432 行还可看到--doh-cert-status对应设置CURLOPT_DOH_SSL_VERIFYSTATUS = 1,二者形成完整的 DoH 校验控制面。
这三个 DoH 专属选项连同CURLOPT_DOH_URL都公开在头文件 include/curl/curl.h 中(例如CURLOPT_DOH_URL见该文件第 2134 行,CURLOPT_DOH_SSL_VERIFYPEER/CURLOPT_DOH_SSL_VERIFYHOST见第 2204 / 2207 行),这意味着libcurl 的 C 语言用户无需命令行,也能直接通过这三个选项精确控制 DoH 校验策略。
4.3 第三步:存储在 easy handle 中的独立标志位
选项被接收后存入每个 easy handle 的set结构。libcurl 侧的处理位于 lib/setopt.c(整段被#ifndef CURL_DISABLE_DOH包裹,说明该能力可编译裁剪):
case CURLOPT_DOH_SSL_VERIFYPEER: s->doh_verifypeer = enabled; break; case CURLOPT_DOH_SSL_VERIFYHOST: s->doh_verifyhost = enabled; ok = 2; /* 只能接受 0 或 2 */ break;其中CURLOPT_DOH_SSL_VERIFYHOST返回ok = 2,表明该选项遵循与CURLOPT_SSL_VERIFYHOST相同的取值约束——只有0和2合法。三个内部标志位声明于 lib/urldata.h:
BIT(doh_verifypeer); /* DoH certificate peer verification */ BIT(doh_verifyhost); /* DoH certificate hostname verification */ BIT(doh_verifystatus); /* DoH certificate status verification */4.4 第四步:校验标志注入内部 DoH 传输
最后一步发生在真正发起 DoH 查询的地方。lib/vdns/doh.c 在为 DoH 服务器创建内部 HTTPS 传输时,依据这三个标志位向该内部句柄写入标准 SSL 校验选项:
if(maybe_https) { ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYHOST, >if(!feature_ssl || config->cacert || config->capath || (config->insecure_ok && (!config->doh_url || config->doh_insecure_ok))) return CURLE_OK;这段代码处理的是"是否自动从环境变量(如CURL_CA_BUNDLE、SSL_CERT_DIR)装载 CA 包"。其判断条件读起来是:如果用户通过--insecure完全关闭了校验,并且(没有配置 DoH,或者同时配置了--doh-insecure把 DoH 校验也关掉),那么说明所有 TLS 校验均已停用,也就无需再去寻找默认 CA 位置。换言之,当启用 DoH 时,--doh-insecure是与--insecure平级的"全局放弃校验"证据;仅开启主传输的--insecure而不开--doh-insecure时,DoH 通道仍需要 CA 来建立信任,工具也就不会跳过 CA 装载。
这一细节再次印证了设计意图:DoH 校验在工具和库两层都被当作一条独立的信任线对待,任何绕过都必须显式声明。
六、安全边界、注意事项与最佳实践
结合选项文档与源码实现,使用--doh-insecure时应遵循以下边界:
- 它只作用于 DoH 服务器连接。若你既用 DoH 解析又访问 HTTPS 站点,目标站点仍然走独立的
CURLOPT_SSL_VERIFYPEER/HOST校验,除非同时给--insecure。 - 它不等于"信任这个 DoH 服务器"。跳过校验意味着任何人都能冒充该 DoH 服务器并向你投递伪造的 DNS 应答,属于安全降级而非信任声明,仅应在网络路径完全受控的场合使用。
- 无法与
--doh-cert-status叠加取信。两者语义冲突;需要强校验时应保留默认校验并叠加--doh-cert-status(注意其仅 OpenSSL / GnuTLS 后端支持)。 --doh-url的 URL 必须是 HTTPS。--doh-insecure跳过的是该 HTTPS 连接的证书校验,而不是允许改用明文 HTTP 传输;把明文或伪造主机放在--doh-url上是另一类错误配置。- 它不会影响 DoH 服务器自身的初始解析路径(该路径默认绕过 DoH),配合
--resolve显式固定 DoH 服务器 IP 是更稳妥的组合。 - API 用户有更细粒度的替代方案:libcurl 程序可分别设置
CURLOPT_DOH_SSL_VERIFYPEER与CURLOPT_DOH_SSL_VERIFYHOST,例如只关主机名校验而保留证书链校验,比命令行开关"一刀切"更精细;选项定义与语义均可在 include/curl/curl.h 中查到。
七、延伸阅读
- 本文主体文档:docs/cmdline-opts/doh-insecure.md
- DoH 服务器指定与"证书校验不继承"说明:docs/cmdline-opts/doh-url.md
- DoH OCSP 装订校验选项:docs/cmdline-opts/doh-cert-status.md
- 普通连接版本
-k / --insecure:docs/cmdline-opts/insecure.md - 代理连接版本
--proxy-insecure:docs/cmdline-opts/proxy-insecure.md - 选项解析表与开关分支:src/tool_getparam.c
- 命令行到 libcurl 选项映射:src/config2setopts.c
- libcurl 选项接收逻辑:lib/setopt.c
- 内部标志位声明:lib/urldata.h
- DoH 底层实现与校验注入:lib/vdns/doh.c
【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features项目地址: https://gitcode.com/GitHub_Trending/cu/curl
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考