多源DoH对比检测DNS劫持:一个API的工程化实践
适用场景在日常运维或安全巡检中DNS劫持DNS Hijacking是一种常见的中间人攻击手段。攻击者通过篡改本地DNS缓存、路由器配置或上游递归服务器将域名指向恶意IP导致用户访问钓鱼站点或内容被替换。传统的检测方式需要手动对比多个DNS服务器的解析结果效率低下且难以自动化。本文介绍的API通过一次请求同时查询 Cloudflare、Google、AliDNS、DNSPod 和 OpenDNS 五大公共DoH服务自动比对返回IP集合并给出劫持风险等级。适用于以下场景安全监控系统周期性检测核心域名是否被污染。网络故障排查用户反馈无法访问某网站时快速判断是否为DNS劫持。开发测试验证CDN或DNS切换后多服务商解析是否一致。威胁情报聚合收集不同DoH的解析差异辅助判断域名健康状态。接口能力边界在集成前需要理解该API的能力范围与限制维度说明检测方式对比5个权威DoH的A记录解析结果基于IP集合一致性判定支持域名任意公网域名不带协议前缀如baidu.com、www.github.comQPS限制5次/秒同一API Key超时设计单次请求建议设置2-3秒超时因需要等待5个上游响应结果粒度仅返回is_hijacked布尔值 risk_levellow/medium/high数据时效实时查询不依赖缓存注意该API不提供历史记录、溯源或IP地理位置信息如需更细粒度分析建议配合其他安全数据源。参数与鉴权鉴权方式采用HTTP Header传递 API Key字段名X-API-Key值请向平台申请并妥善保管避免硬编码在代码中。Query 参数参数名必填类型说明示例domain是string待检测域名不含https://example.com请求方法固定为GET终端地址https://v1.apizero.cn/api/dns-hijack?domain{domain}curl 示例可复制将环境变量$APIZERO_API_KEY替换为你的真实Key即可执行curl -sS \ -X GET \ -H X-API-Key: $APIZERO_API_KEY \ https://v1.apizero.cn/api/dns-hijack?domainbaidu.com如果直接硬编码Key不推荐curl -sS -X GET -H X-API-Key: your_actual_key_here \ https://v1.apizero.cn/api/dns-hijack?domainbaidu.com成功时返回JSON数组首个元素为状态描述example字段内为业务数据。代码接入Python 示例以下 Python 脚本封装了调用逻辑包含错误处理和超时设置import requests import sys API_URL https://v1.apizero.cn/api/dns-hijack API_KEY your_api_key_here # 建议从环境变量读取 def check_dns_hijack(domain: str, timeout: int 3) - dict: 检测指定域名是否存在DNS劫持。 :param domain: 待检测域名不含协议 :param timeout: 单次请求超时秒数 :return: 解析后的data对象 :raises: 请求异常或非200状态时抛出 headers {X-API-Key: API_KEY} params {domain: domain} resp requests.get(API_URL, headersheaders, paramsparams, timeouttimeout) if resp.status_code ! 200: raise RuntimeError(fHTTP {resp.status_code}: {resp.text}) body resp.json() # 根据规范返回的是列表第一个元素包含example if isinstance(body, list) and len(body) 0: result body[0].get(example) if result and result.get(code) 0: return result[data] else: raise RuntimeError(f业务错误: {result.get(msg, 未知)}) else: raise RuntimeError(响应格式异常) if __name__ __main__: if len(sys.argv) 2: print(用法: python dns_check.py domain) sys.exit(1) domain sys.argv[1].strip() try: data check_dns_hijack(domain) print(f域名: {data[domain]}) print(f是否劫持: {data[is_hijacked]}) print(f风险等级: {data[risk_level]}) print(f摘要: {data[summary]}) print(f解析结果IP: {, .join(data[unique_ips])}) except Exception as e: print(f检测失败: {e}) sys.exit(1)运行示例export APIZERO_API_KEYyour_key_here python dns_check.py baidu.com输出域名: baidu.com 是否劫持: False 风险等级: low 摘要: 5 个 DoH 服务商解析结果一致未检测到劫持迹象 解析结果IP: 110.242.68.3, 110.242.68.4返回值解读API 返回的 JSON 响应结构以code0为例{ code: 0, data: { domain: baidu.com, is_hijacked: false, risk_level: low, summary: 5 个 DoH 服务商解析结果一致未检测到劫持迹象, unique_ips: [110.242.68.3, 110.242.68.4] }, msg: 成功 }字段类型说明codeint0 表示业务成功非 0 见错误码msgstring业务描述信息data.domainstring查询的域名data.is_hijackedbooltrue表示检测到劫持/污染data.risk_levelstringlow/medium/high结合冲突IP数量判断data.summarystring可读的摘要适合直接展示给用户data.unique_ipsstring[]所有DoH返回的去重IP列表风险等级判定逻辑推测low5个DoH解析结果完全一致。medium少数DoH出现不同IP但大部分一致。注素材未明确分界实际以文档为准。high多个DoH返回不同子集强烈暗示中间人篡改或解析服务器被攻击。常见错误及处理HTTP状态错误码常见原因解决建议401-API Key 无效或未携带检查X-API-Key头和密钥4001001domain参数缺失或格式不对确保只传域名不含http://4221002域名无法被DoH解析如不存在验证域名合法性4291003QPS 超过上限5/s加入重试退避逻辑502/503-上游DoH服务临时不可用稍后重试可加入指数退避注意完整错误码列表请查阅官方文档。工程化注意事项API Key 管理不要在代码库中硬编码使用环境变量或密钥管理服务如Vault。请求重试建议实现最多2次重试间隔1秒避免对429响应无脑重试。结果缓存对于相同域名3分钟内重复查询结果几乎不变可引入本地缓存TTL180秒减轻API压力。日志记录记录每次查询的域名、结果、风险等级和时间戳方便事后审计。并发限制若需批量检测多个域名控制并发数不超过QPS上限5/s可使用信号量或队列。超时防护单次请求设置2-3秒超时Python requests默认无超时务必指定。参考文档API 官方文档https://apizero.cn/aidocs/dns-hijack原始 Markdown 文档如需要接口细节https://apizero.cn/aidocs/dns-hijack/raw.md