Agent 网络出口防护:阻断 SSRF、DNS 重绑定与重定向绕过
允许 Agent 自由抓取 URL 会把模型变成内网请求代理。本文给出 URL 规范化、全地址校验、连接 IP 钉扎、逐跳重定向检查、出口代理和攻击回归方案。
本文要点
- 主题聚焦:AI、AI Agent、DevOps
- 适合人群:独立开发者、全栈工程师、AI 应用开发者
- 核心价值:快速理解背景、实践路径、常见误区和工程建议
浏览、Webhook 检查和文档抓取工具通常接受模型生成的 URL。攻击者只要把 http://169.254.169.254/、http://localhost:... 或指向内网的域名藏进网页,就可能让 Agent 读取云元数据、管理面板和只在集群内开放的服务。即使响应没有回显,状态码和延迟也能用于扫描;若内部接口错误地用 GET 产生副作用,风险更高。
编程 Agent 沙箱权限 建议限制网络,但通用“可联网”仍然过宽。MCP 安全审计 覆盖工具整体威胁,本篇只处理 HTTP 出口从 URL 接收到 socket 建连的完整链路,特别是验证后 DNS 变化与重定向绕过。
默认使用目的域名 allowlist
最强策略是为每个工具声明有限目的地,例如文档抓取器只访问批准的官方站点,模型供应商客户端只访问固定 API 域。规则匹配规范化后的完整 hostname,不使用 endsWith("example.com") 这类会放过 evil-example.com 的字符串判断;子域规则必须显式表达边界。工具若没有业务理由访问任意互联网,就不提供通用 fetch。
确需开放网页搜索时,也要限制到 HTTP/HTTPS、标准端口、无用户名密码、最大 URL 长度和可接受路径。拒绝 file:、gopher:、ftp:、data:,拒绝 URL 中嵌入凭证以及模糊 IP 表示。先用标准 URL parser 解析,再对 parser 生成的 hostname 做判断,不能靠正则处理 user@host、IPv6 方括号、尾点和百分号编码。
校验所有解析地址而不是只看域名
对 hostname 同时查询 A 与 AAAA,并检查返回集合中的每一个地址。只要包含 loopback、私网、链路本地、共享地址、组播、文档保留段、IPv4-mapped IPv6 或其他 RFC 特殊用途地址,就拒绝整个请求;不能挑其中一个公网地址继续。0.0.0.0、127.0.0.0/8、::1、fc00::/7、fe80::/10 和云元数据链路本地地址都在拒绝范围。
const target = parseAndNormalize(inputUrl);
assertAllowedSchemeAndPort(target);
const answers = await dns.promises.lookup(target.hostname, {
all: true,
verbatim: true,
});
if (!answers.length || answers.some(({ address }) => !isPublicAddress(address))) {
throw new Error("EGRESS_TARGET_NOT_PUBLIC");
}
仅在校验时解析还不够。攻击域名可以第一次返回公网 IP,通过检查后在 HTTP 客户端再次解析时返回 127.0.0.1,这就是 DNS rebinding 的时间差。安全请求器应选择已校验地址并把连接钉扎到该 IP,同时保留原 hostname 作为 HTTP Host 和 TLS SNI;禁止客户端、代理或系统在建连时再次解析。证书仍按原 hostname 验证,不能因为使用 IP 建连就关闭 TLS 校验。
每一次重定向都视为新请求
关闭库的自动重定向,手工读取 Location,用当前 URL 解析相对地址,然后从协议、端口、DNS 到 IP 钉扎完整重跑。设置最多三至五跳、已访问集合和总时间预算,拒绝循环。一个公网短链重定向到内网与用户直接提交内网 URL 等价;只校验第一跳没有安全意义。
请求不转发用户 Cookie、Authorization、内部 tracing baggage 或代理凭证。使用专用 User-Agent、方法 allowlist、连接与读取超时、最大响应字节、压缩后上限和内容类型约束。下载大文件需要单独工具与隔离存储,不能让普通抓取器无界解压。返回模型前再做文本提取和不可信标记,Prompt Injection 防御 负责内容层风险,SSRF 过滤不能替代它。
用网络层形成第二道边界
应用校验可能有实现漏洞,因此 Agent worker 通过专用 egress proxy 出口,网络策略禁止直接访问 VPC、Pod/Service CIDR、宿主、控制面和元数据地址。proxy 重新解析并执行同样的公共地址与域名策略,记录规则版本、目标域、钉扎 IP、端口、重定向链和拒绝原因,但不记录敏感 query。
DNS 解析器只使用受控服务器,不接受任务容器修改 /etc/hosts 或代理环境变量。将 HTTP_PROXY、NO_PROXY 的解释固定在启动配置,避免工具输出改变它们。云网络基础 中的子网与安全组用于最后一道路由阻断,即使应用错误放行,请求仍不能到达内部资产。
建立专门的 SSRF 回归环境
测试服务提供公网地址、私网地址、混合 A/AAAA、十六进制或 IPv4-mapped 表示、带 userinfo URL、非标准端口、超长重定向和公网到私网跳转。再部署可控 DNS,第一次解析返回公网、第二次返回 loopback,证明实际 socket 仍连接第一次审查的地址。成功标准不是模型拒绝,而是目标服务完全收不到包且审计出现确定性 code。
正向测试覆盖允许域名、合法 CDN 多地址、相对重定向和证书更新,避免规则把正常抓取全部阻断。上线先以 audit 模式观察会被拒绝的真实目标,但 audit 阶段的请求只能在无敏感网络的测试环境发送;生产不能“记录但放行”私网请求。
事故时关闭通用出口而不是放宽规则
发现 SSRF 或解析异常后,立即禁用通用 HTTP 工具,保留固定供应商与批准域名的专用客户端;在 proxy 封禁攻击域和目标 IP,轮换可能暴露的元数据凭证,查询同一 run 的出口审计并隔离结果。不要依赖 DNS 缓存自然过期。
修复时恢复上一版已签名策略和请求器,先在回归环境验证混合地址、rebinding 和逐跳重定向,再按域名小批开放。若新验证器误拒绝,回滚也只能回到旧的受控 allowlist,不能暂时改为任意 URL。网络工具 fail closed 会降低部分功能,但远比让 Agent 成为内网代理更容易恢复。
延伸阅读
Related