适用场景
在日常运维或安全巡检中,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.com |
| QPS限制 | 5次/秒(同一API Key) |
| 超时设计 | 单次请求建议设置2-3秒超时(因需要等待5个上游响应) |
| 结果粒度 | 仅返回is_hijacked布尔值 +risk_level(low/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?domain=baidu.com"如果直接硬编码Key(不推荐):
curl -sS -X GET -H "X-API-Key: your_actual_key_here" \ "https://v1.apizero.cn/api/dns-hijack?domain=baidu.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, headers=headers, params=params, timeout=timeout) if resp.status_code != 200: raise RuntimeError(f"HTTP {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_KEY=your_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 响应结构(以code=0为例):
{ "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": "成功" }| 字段 | 类型 | 说明 |
|---|---|---|
code | int | 0 表示业务成功;非 0 见错误码 |
msg | string | 业务描述信息 |
data.domain | string | 查询的域名 |
data.is_hijacked | bool | true表示检测到劫持/污染 |
data.risk_level | string | low/medium/high,结合冲突IP数量判断 |
data.summary | string | 可读的摘要,适合直接展示给用户 |
data.unique_ips | string[] | 所有DoH返回的去重IP列表 |
风险等级判定逻辑(推测)
- low:5个DoH解析结果完全一致。
- medium:少数DoH出现不同IP,但大部分一致。
注:素材未明确分界,实际以文档为准。 - high:多个DoH返回不同子集,强烈暗示中间人篡改或解析服务器被攻击。
常见错误及处理
| HTTP状态 | 错误码 | 常见原因 | 解决建议 |
|---|---|---|---|
| 401 | - | API Key 无效或未携带 | 检查X-API-Key头和密钥 |
| 400 | 1001 | domain参数缺失或格式不对 | 确保只传域名,不含http:// |
| 422 | 1002 | 域名无法被DoH解析(如不存在) | 验证域名合法性 |
| 429 | 1003 | QPS 超过上限(5/s) | 加入重试退避逻辑 |
| 502/503 | - | 上游DoH服务临时不可用 | 稍后重试,可加入指数退避 |
注意:完整错误码列表请查阅官方文档。
工程化注意事项
- API Key 管理:不要在代码库中硬编码,使用环境变量或密钥管理服务(如Vault)。
- 请求重试:建议实现最多2次重试,间隔1秒;避免对429响应无脑重试。
- 结果缓存:对于相同域名,3分钟内重复查询结果几乎不变,可引入本地缓存(TTL=180秒)减轻API压力。
- 日志记录:记录每次查询的域名、结果、风险等级和时间戳,方便事后审计。
- 并发限制:若需批量检测多个域名,控制并发数不超过QPS上限(5/s),可使用信号量或队列。
- 超时防护:单次请求设置2-3秒超时(Python requests默认无超时,务必指定)。
参考文档
- API 官方文档:https://apizero.cn/aidocs/dns-hijack
- 原始 Markdown 文档(如需要接口细节):https://apizero.cn/aidocs/dns-hijack/raw.md