AI AgentSSRF工具安全URL抓取

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 查看平台对比与排行榜,并确认工具参数透传、请求追踪和错误语义满足你的安全验收要求。

找到最适合你的 AI API 中转站

收录 125+ 服务商,按价格、模型、标签一键筛选

查看所有中转站 →