
适用场景DNS劫持是运营商、恶意软件或中间人通过篡改DNS解析结果将用户导向错误服务器的攻击手段。本API通过向阿里AliDNS、腾讯DNSPod、360安全DNS、Cloudflare四家公共DoHDNS over HTTPS服务商并发查询同一域名对比IP与CNAME的一致性自动识别以下异常运营商劫持多家DoH返回IP不一致其中一家被篡改。Hosts文件篡改本地解析被重定向。异常GeoDNS分流不同地域指向不同CDN但IP归属异常。跨域CNAME跳转可见提取完整CNAME链辅助判断CDN配置是否被篡改。典型使用者包括CDN运维人员验证全球解析一致性、安全工程师部署域名监控、桌面工具开发者提供DNS健康检查功能。接口能力边界特性说明并发查询四家DoH服务器同时发起请求总耗时取决于最慢服务器通常2sCloudflare在中国大陆可能超时记录类型AIPv4和AAAAIPv6同时查询CNAME链路提取到最终IP前的全部CNAME跳转TTL汇总返回各服务器最小TTL用于缓存时间评估输入自动剥离支持domain、https://domain、domain:port、domain/path统一提取纯域名最长253字符风险分级基于联盟投票算法safe / safe_with_geodns / suspicious / hijack_likely / unknownQPS限制每账号5次/秒超出返回429或限速错误注意Cloudflare服务器位于美国在中国大陆网络环境下大概率超时该服务器的超时不会被判定为劫持仅标记为timeout并计入success_count减少风险算法只基于成功响应的服务器做交叉验证。参数详解与鉴权Query参数参数名必填类型描述domain是string待检测域名最大253字符。自动去除http://、https://、路径、端口号仅保留域名部分。示例domainbaidu.comdomainhttps://www.taobao.com/page→ 实际检测www.taobao.comdomainexample.com:8080→ 检测example.comHeader参数参数名必填类型描述X-API-Key否stringAPI密钥。若不传使用匿名额度通常QPS更低或有次数上限具体以官方文档为准。推荐在生产环境中始终携带有效Key以避免被动限流。curl示例请求与响应以下示例使用环境变量$APIZERO_API_KEY存放密钥检测域名www.taobao.comcurl -sS \ -X GET \ -H X-API-Key: $APIZERO_API_KEY \ https://v1.apizero.cn/api/dns-check?domainwww.taobao.com成功响应截取关键字段{ code: 0, data: { domain: www.taobao.com, exec_ms: 312, input: www.taobao.com, servers: [ { key: alidns, name: AliDNS, status: ok, ipv4: [59.82.121.163, 59.82.122.130], ipv6: [], cname_chain: [www.taobao.com.danuoyi.tbcache.com], latency_ms: 105, ttl_min: 60, error: null }, { key: dnspod, name: DNSPod, status: ok, ipv4: [59.82.121.163], ... }, { key: china360, name: 360, status: ok, ... }, { key: cloudflare, name: Cloudflare, status: timeout, error: Operation timed out after 6000 ms, latency_ms: 6000 } ], summary: { risk_level: safe, risk_score: 95, status_text: DNS解析正常, explain: 4 家 DoH 全部相互验证通过未检测到劫持迹象。, success_count: 3, total_count: 4, unique_ipv4_count: 8, unique_ipv6_count: 0 }, unique_ipv4: [59.82.121.163, 59.82.122.130, ...], unique_ipv6: [] }, msg: 成功, request_id: mota-xxxx }返回字段逐层解读顶层data字段类型说明domainstring实际检测的域名剥离后exec_msnumber整体执行耗时毫秒从请求发出到所有DoH响应或超时inputstring用户传入的原始字符串未剥离前serversarray四家DoH服务器的独立结果unique_ipv4array所有服务器返回的去重IPv4地址列表unique_ipv6array去重IPv6地址列表summaryobject风险聚合信息servers子项每个服务器的独立对象包含字段类型说明keystring服务器标识alidns、dnspod、china360、cloudflarenamestring可读名称statusstringok成功、timeout超时、error其他错误ipv4array该服务器返回的IPv4地址列表可能为空ipv6arrayIPv6地址列表cname_chainarrayCNAME跳转链如[www.taobao.com.danuoyi.tbcache.com]若无则为空数组latency_msnumber该DoH请求的延迟毫秒超时则为超时值如6000ttl_minnumber该服务器返回的最小TTL秒用于缓存时效参考errorstring/null当status不为ok时此处为具体错误描述summary风险等级字段类型说明risk_levelstring风险等级safe安全、safe_with_geodns安全但存在GeoDNS差异、suspicious可疑、hijack_likely高度疑似劫持、unknown信息不足risk_scorenumber0–100的分数越高越安全95以上极安全status_textstring简短状态描述explainstring自然语言解释直接说明是否检测到劫持success_countnumber成功返回ok的服务器数量total_countnumber总服务器数量固定4unique_ipv4_countnumber全局去重IPv4数量多服务器返回相同IP时只计1unique_ipv6_countnumber去重IPv6数量风险算法简析系统对比各服务器的ipv4集合。若所有成功服务器返回的IP完全一致判为safe若存在部分差异但均在合理CDN范围内如阿里云和腾讯云指向同一CDN的不同节点可能判为safe_with_geodns若某服务器返回的IP完全不同于其他服务器且延迟异常低疑似本地缓存劫持则判为hijack_likely。suspicious对应少量IP差异但无法确认为合法CDN。常见错误与处理HTTP状态码code值可能原因建议处理400400domain参数缺失或格式无效空字符串、超过253字符验证输入长度先剥离协议/路径401401X-API-Key无效或过期检查密钥配置从安全环境变量读取429429超过QPS限制5/s引入本地节流令牌桶/固定窗口或请求间隔≥200ms500500服务端内部错误或DoH集体故障重试2–3次若持续失败降级为手动检查503503临时过载指数退避重试注意超时timeout是服务器层面的预期行为不应视为错误当success_count为0时risk_level会是unknown此时应建议用户更换网络环境后重试。工程化注意事项1. QPS控制与并发管理API限制为5次/秒。若需要在单进程内频繁检测多个域名建议使用线程池或异步队列限制并发数import asyncio import aiohttp API_KEY your-key BASE_URL https://v1.apizero.cn/api/dns-check async def check_domain(session, domain): params {domain: domain} headers {X-API-Key: API_KEY} async with session.get(BASE_URL, paramsparams, headersheaders) as resp: return await resp.json() async def batch_check(domains): sem asyncio.Semaphore(5) # 控制并发≤5 async with aiohttp.ClientSession() as session: async def bounded_check(d): async with sem: return await check_domain(session, d) tasks [bounded_check(d) for d in domains] return await asyncio.gather(*tasks) # 使用 results asyncio.run(batch_check([baidu.com, taobao.com, ...]))2. 超时处理与重试策略由于Cloudflare服务器经常超时6000ms整体请求可能在6秒左右。生产环境中可设置客户端超时为10秒。对于status为timeout的服务器不做重试因为超时是网络环境决定的但若整个请求超时或返回5xx应重试import requests from time import sleep def robust_check(domain, max_retries3): for attempt in range(max_retries): try: resp requests.get( https://v1.apizero.cn/api/dns-check, params{domain: domain}, headers{X-API-Key: API_KEY}, timeout10 ) if resp.status_code 200: return resp.json() elif resp.status_code in (429, 503): sleep(2 ** attempt) continue else: resp.raise_for_status() except requests.exceptions.Timeout: # 请求级别超时重试 sleep(2 ** attempt) raise Exception(Max retries exceeded)3. 缓存策略对于中低风险域名如safe或safe_with_geodns解析结果在TTL内通常是稳定的。可以通过ttl_min字段决定缓存时长若ttl_min为60则缓存60秒后重新检测。4. 输入预处理API会自动剥离协议头和路径但建议客户端自行预处理以避免无效请求def extract_domain(url_or_domain): # 去除协议头和路径 import re domain re.sub(rhttps?://, , url_or_domain) domain domain.split(/)[0] if / in domain else domain domain domain.split(:)[0] if : in domain else domain return domain5. 多服务器结果对比逻辑不要只依赖单个服务器的响应即使4家中3家返回相同IPCloudflare超时也应以多数派为准success_count≥ 2时结果可靠。当success_count 2时建议提示“检测数据不足”。参考文档DNS劫持检测API官方文档原始接口说明Markdown