IP直连接入HTTPDNS的原理

1. 前言

在移动端或跨平台应用中,HTTPDNS 常用于规避本地 DNS 劫持与缓存污染等问题。然而在实际接入过程中,并非所有网络库都提供 DNS Hook 接口。IP 直连正是针对这类“只能改写请求细节”的场景所提出的一种折中方案:先通过 HTTPDNS 获取解析结果,再将 URL 改写为直连 IP,同时确保 TLS 握手与路由仍基于原始域名。

示例:https://www.example.comhttps://1.2.3.4,并在请求头中保留 Host: www.example.com

本文聚焦于 需要 IP 直连 的典型场景,概述适用条件、常见问题及应对策略,帮助您理解该方案的基本原理。

2. 何时需要 IP 直连

判断网络库的可控程度,再决定是否启用 IP 直连

  • 具备 DNS Hook 或 Host-IP 映射接口:如 OkHttp、libcurl、HarmonyOS Network Kit 等,可直接将 HTTPDNS 结果注入 DNS 接口,以域名方式发起请求。该模式下可兼容 HTTPS、SNI、Cookie 与连接复用,无需额外改造。

  • 无 DNS Hook,但具备 API 请求控制能力:当网络库无法替换 DNS,但允许改写 URL、请求头、证书策略或重定向等细节时,可采用 IP 直连。其流程为:通过 HTTPDNS 获取 IP → 使用 IP 重写 URL → 补充 Host、证书、代理、Cookie 等必要处理。

  • 完全封闭:若网络库既无 DNS Hook,也缺少 API 控制入口(如部分 WebView 内核),则可考虑通过 SDK、DoH、本地代理或厂商专用能力实现,IP 直连本身不可行。

综上,对于“半开放”但不支持 DNS Hook 的网络库,可以通过 IP 直连 方式接入 HTTPDNS。

重要
  • H5接入HTTPDNS的方式:当 JavaScript 运行在浏览器环境时,会遵循 Fetch 标准(Fetch Standard),其中明确规定 Host 属于forbidden header name。因此,通过 XMLHttpRequest、fetch() 等 API 发起的请求,脚本均无法主动改写 Host,也就无法通过 IP 直连 方式接入 HTTPDNS。此类场景只能依赖运行环境(如 WebView、CEF、Electron 等)在宿主层处理,或改用 本地代理 / DoH 方案。

3. 问题及解决方案

本文会先介绍客户端与目标服务器交互过程中的网络相关概念,然后介绍对比采用IP直连的问题以及应解决方案。

3.1 域名语义相关概念

  • SNI(Server Name Indication): SNI 是 TLS 的扩展字段,客户端在握手时会告知服务端目标域名,以便服务端选择正确的证书和虚拟主机。在共享 IP 或多租户场景下尤为重要,例如 CDN 节点同时为多个域名提供服务时,SNI 可确保返回对应的 HTTPS 证书,从而确保连接的合法性与安全性。

  • CN/SAN 证书校验:在 TLS 握手阶段,客户端会对服务端返回的 HTTPS 证书进行严格校验。网络库通常会先从 URL 中提取目标域名,并将其作为预期的 CN(Common Name)或 SAN(Subject Alternative Name);随后,从证书中解析出实际的 CN/SAN 进行比对。若二者不一致,连接将被拒绝,或被视为不受信任的非安全连接。

  • Host头: 自 HTTP/1.1 起,Host 为强制字段,用于在同一监听 IP/端口下区分目标站点。对服务端而言,它是虚拟主机或反向代理准确路由请求的关键依据;对中间层而言,缓存键、鉴权策略及限流规则通常以 Host 为粒度进行划分。客户端侧的 Cookie 管理也依赖 Host 实现域名隔离,若 Host 配置错误,可能导致登录态被写入 IP 域或复用失败。

3.2 IP直连引入的问题

如下图所示,客户端原始的请求URLhttps://www.example.com,由于网络库未提供DNS Hook的能力,为了使用HTTPDNSDNS解析结果,此时只能把URL改写成https://1.2.3.4的形式。当 URL 被改写成 IP 直连时,客户端与目标服务交互过程中会遇到以下问题:

image

  • 服务器返回HTTPS证书异常:当网络库从 URL 中提取的 SNI 值由 www.example.com 变为 1.2.3.4 时,目标服务器无法匹配对应的证书,只能返回默认的 HTTPS 证书,从而导致握手异常。

  • 客户端HTTPS证书校验失败:网络库会将预期的 CN/SAN 从 www.example.com 解析为 1.2.3.4。由于证书中的 CN/SAN(例如 www.example.com*.example.com)与 IP 不匹配,TLS 校验会失败,握手无法完成。

  • 服务器无法路由到目标服务:现在NginxApacheWeb Server软件支持虚拟主机功能,允许同一个物理服务器上在同一个端口上部署不同的站点,并根据Host头路由到对应的站点。客户端从从URL提取预期的Hostwww.example.com变为1.2.3.4后,会导致服务端找不到对应的服务而返回404状态码。

  • 客户端cookie管理失败:客户端网络库通常是根据Host头进行Cookie缓存,会将 Cookie 绑定到具体 IP 1.2.3.4而非域名www.example.com,导致原有域名下的 Cookie 无法复用。由于同一域名的解析结果在缓存失效后往往会切换到不同 IP,Cookie 只能绑定在各自的 IP 上,从而出现 登录态丢失、会话无法共享,并可能引发安全策略失效的风险。

  • 客户端连接无法复用:现代网络库普遍支持基于 Host 的 HTTP 连接复用,以减少 TCP 握手开销、提升响应效率。一旦改为 IP 直连,由于复用粒度从域名www.example.com变成了1.2.3.4,不同IP之间无法共享已有连接,这造成额外的握手开销。

3.3 IP直连问题的解决方案

通过IP 直连方式使用HTTPDNS解析出的IP时,会带来以上诸多问题,要解决这些问题必须手动恢复SNI、证书校验、HTTP Host头这些域名信息,确保网络栈仍按域名语义工作。

  • 手动设置 SNI:调用网络库暴露的 TLS/SNI 配置或 SocketFactory API,将原始域名写入 SNI 扩展。

  • 手动设置校验CN/SAN:通过网络库提供的证书校验HostnameVerifier 等 API,在 TLS 校验阶段显式传入原始域名,确保 CN/SAN 比对正确。

  • 手动设置 Host 头:通过网络库提供的 API 显式设置 Host: 原始域名,避免默认将 IP 写入 Host。

    说明

    HTTP 代理遵循 HTTP/1.1 的 absolute-form(详见 origin-form),请求行会携带完整 URL。当 URL改写成 IP 后,代理往往把该 IP 视为真实主机,甚至在向源站发起请求时丢弃客户端设置的域名Host头,最终导致源站返回 404、证书错误或直接拒绝。绝大多数情况下,建议代理环境下关闭HTTPDNS。

不同网络库从URL中提取SNI、证书校验域名、Host头的方式存在差异,提供恢复SNI、证书校验、HTTP Host头这些域名信息的API也不同,需要根据具体网络库确定IP直连的方案,以下是HTTPDNS已经提供的IP直连适配方案:

  • Android HttpURLConnection:依赖 HostnameVerifier/SSLSocketFactory 覆盖 TLS 校验逻辑,并通过 setRequestProperty 显式设置 Host,参考AndroidHTTPDNS+HttpURLConnection最佳实践

  • iOS NSURLSession:在 URLSession:task:didReceiveChallenge: 中绑定证书校验域名,并在构造请求时设置 Host 头,参考iOSNative场景使用HTTPDNS

  • Unity HttpWebRequest:使用 ServicePointManager.ServerCertificateValidationCallback 指定域名验证,结合 request.Host = 原始域名 完成 Host 改写, 参考Unity框架最佳实践

说明

其他网络栈或者网络的IP直连接入方案,请联系技术支持咨询。

4. 总结

IP 直连是一套针对“无法自定义 DNS”场景的补救方案。关键在于:清楚记录原始域名,并在证书校验、SNI、Host 三个关键点确保沿用域名语义。借助上述原则,即使在半开放的网络库中,也能安全地利用 HTTPDNS 的解析结果。