AI Agent 能访问任意网址安全吗?URL 抓取工具 SSRF 防护实战
2026-09-14 · 约 10 分钟阅读
给 AI Agent 增加“读取网页”“下载文件”或“调用 Webhook”能力后,模型可能把用户提供的 URL 直接交给后端请求。此时风险不只是不良网页:攻击者可能诱导服务访问本机管理端口、云环境元数据、内网数据库或仅对服务器开放的后台,这类问题通常称为 SSRF(服务端请求伪造)。
不能指望模型判断 URL 是否安全,也不能只用 Prompt 写一句“禁止访问内网”。真正的边界必须位于工具执行器和网络出口。本文是与厂商无关的方法论,不涉及易变的模型、定价或事件数据。
为什么简单的域名黑名单不够
字符串看起来是公网域名,不代表最终连接一定去公网。域名可以解析到私网地址,解析结果可能在检查与连接之间变化;URL 还可能使用用户名段、编码、IPv6、重定向和不同端口绕过粗糙正则。只拦截 localhost 和 127.0.0.1 远远不够。
此外,首次请求安全,后续重定向也可能跳到受限地址。某些 HTTP 客户端默认自动跟随重定向,应用甚至看不到中间目标。安全设计必须对每一次实际连接进行判断。
第一道边界:工具参数不要接受任意能力
先根据业务缩小工具。只需要搜索结果摘要,就调用受控搜索服务,不要提供通用 URL fetch;只需要读取已上传文件,就接受对象 ID,不接受外部 URL;Webhook 目标可以在配置阶段登记,运行时只允许使用目标 ID。
确实需要开放网页读取时,Schema 至少限制协议、端口、响应类型、最大字节和超时。默认只允许 HTTPS,拒绝 file:、ftp:、data: 等非预期协议。模型输出的请求头也不能原样透传,尤其不能允许覆盖 Host、Authorization 或代理相关字段。
URL 解析必须使用标准库
不要通过 startsWith("https://safe.example") 判断域名,因为相似域名、用户名段和编码可能造成误判。使用标准 URL 解析器,取出规范化协议、hostname、port 和路径;拒绝包含凭证、异常端口或无法规范化的地址。
function validateUrl(raw: string) {
const url = new URL(raw);
if (url.protocol !== "https:") throw new Error("scheme_denied");
if (url.username || url.password) throw new Error("credentials_denied");
const port = url.port || "443";
if (!ALLOWED_PORTS.has(port)) throw new Error("port_denied");
return url;
}
规范化是第一步,不是完整防护。域名通过检查后,还要解析全部 IP 并判断地址范围。
DNS 与实际连接必须绑定
执行器应解析目标域名的所有 A、AAAA 结果,拒绝回环、私网、链路本地、保留地址和组织定义的敏感网段。不能只检查第一条记录,也不能因为某条是公网就忽略同时返回的私网地址。
更稳妥的方式是让专用出站代理完成解析和连接,应用只把经过审批的目标交给代理。代理根据实际目标 IP 执行策略,从而缩小“检查时解析”和“连接时解析”之间的竞态窗口。容器或云防火墙还应从网络层禁止访问元数据、控制平面和内部网段,即使应用校验被绕过也无法建立连接。
重定向要逐跳复检
关闭客户端自动重定向,手动读取 Location,将相对地址解析为绝对 URL,然后重新执行协议、端口、域名、DNS 和 IP 检查。设置最大跳数并检测循环。任何一跳进入禁止范围,都终止整次任务。
async function safeFetch(start: URL) {
let current = start;
for (let hop = 0; hop < MAX_REDIRECTS; hop++) {
const target = await resolveAndAuthorize(current);
const res = await egressFetch(target, { redirect: "manual" });
if (!isRedirect(res.status)) return limitResponse(res);
const location = res.headers.get("location");
if (!location) throw new Error("redirect_without_location");
current = validateUrl(new URL(location, current).toString());
}
throw new Error("too_many_redirects");
}
不要只复检 hostname;每一跳都可能改变协议、端口和实际 IP。
响应内容也需要限制
SSRF 防护通过后,目标仍可能返回超大文件、压缩炸弹、无限数据流或恶意内容。先检查状态和 Content-Type,但不要完全信任响应头;按流读取并设置解压前后上限、总时限、空闲超时和允许类型。达到任一边界立即取消连接。
网页解析建议移除脚本、样式和不可见节点,只提取业务需要的文本。下载文件应在隔离环境做类型识别和安全扫描,不要让 Agent 直接执行、渲染或导入返回内容。抓取结果属于外部不可信数据,不能因为由工具返回就自动升级为系统指令。
Allowlist 比 Blocklist 更适合高风险业务
内部知识助手、财务 Agent 和自动化运维通常不需要访问整个互联网。使用域名 allowlist,并明确是否允许子域、端口和路径,比维护无限黑名单更可控。对于多租户 SaaS,allowlist 应按租户隔离,普通用户不能修改组织级出口策略。
若业务必须访问用户自有域名,可建立登记流程:验证域名所有权、保存批准范围、定期重新解析,并在运行时继续进行 IP 与重定向检查。登记过不代表永久安全。
日志与告警怎么设计
记录工具调用 ID、用户与租户、原始 hostname 的受控表示、规范化目标、解析 IP 分类、重定向链、阻断规则、下载字节和结束原因。Authorization、查询参数中的令牌以及完整页面内容不应进入普通日志。
告警关注短时间大量被拒地址、对相邻端口的扫描式请求、重复访问内部网段和异常大响应。被策略阻断时,给 Agent 返回稳定错误码,例如 target_not_allowed,不要泄露内部网段、主机名或防火墙结构。
防护验收清单
- 能用资源 ID 或受控搜索替代通用 URL 的场景已经收窄
- URL 由标准库解析,协议、凭证和端口采用白名单
- DNS 全部结果及实际连接 IP 都会检查
- 网络层明确阻断本机、私网、元数据和控制平面
- 每次重定向都重新校验,跳数和循环有上限
- 响应有类型、字节、解压、总时限和空闲时限边界
- 外部内容按不可信数据处理,不能直接成为高优先级指令
- 日志可审计但不会泄露 URL 中的秘密
总结
URL 抓取工具表面上只是一次 HTTP 请求,实际上把 Agent 接到了服务器的网络视角。最有效的 SSRF 防护来自能力收窄、逐跳授权、出站代理、网络隔离和响应限额,而不是让模型自己遵守网址规则。评估支持工具调用的 AI API 中转站时,可前往 openairouter.net 查看平台对比与排行榜,并确认工具参数透传、请求追踪和错误语义满足你的安全验收要求。