跳转到帖子

SSRF(Server-Side Request Forgery,服务器端请求伪造)并不是“让服务端代替用户发一次请求”这么简单。它真正危险的地方在于:应用通常拥有比普通用户更高的网络可达性,攻击者一旦能够影响请求目标,就可能借助应用访问内网管理面、云平台元数据服务、仅绑定本机的调试接口,甚至把内部响应带回到外部。

在实际审计中,SSRF 往往不以明显的 url 参数出现,也可能隐藏在图片抓取、Webhook、文件导入、Markdown 预览、第三方接口代理、PDF 生成等功能中。本文以防守和代码审计为主线,整理一套适用于研发自查、漏洞复现和修复验证的方法。

一、先明确问题边界:哪些功能值得优先检查

判断一个功能是否可能存在 SSRF,核心不是看参数名,而是确认服务端是否会根据外部输入发起网络请求。以下场景通常风险较高:

  • 根据用户提交的 URL 下载头像、图片、附件或远程文档。
  • 提供 URL 预览、网页截图、网页转 PDF、RSS 抓取等能力。
  • 允许配置 Webhook、回调地址、通知地址或第三方集成地址。
  • 服务端作为代理访问外部 API,并将响应转发给浏览器。
  • 解析 SVG、XML、Office 文档或其他包含外部资源引用的文件。
  • 后台任务根据数据库中的地址定时同步内容。

审计时可以从“出网能力”倒推输入点。先搜索项目中的 HTTP 客户端调用,再追踪目标地址是否来自请求参数、数据库字段、消息队列或用户可编辑配置。常见调用包括 Java 的 HttpClient、RestTemplate、WebClient,Python 的 requests、urllib,Node.js 的 axios、fetch 等。

二、典型漏洞形成条件

一个可利用的 SSRF 通常同时具备三个条件:

  • 攻击者能够影响请求目标,或者影响目标的一部分。
  • 服务端会解析目标并发起网络连接。
  • 连接结果能够造成安全影响,例如读取敏感响应、触发内部操作、探测网络状态,或产生高额资源消耗。

下面是一段简化的危险代码。问题不在于使用了某个特定库,而在于没有对目标进行策略校验:

String target = request.getParameter("url");
HttpRequest httpRequest = HttpRequest.newBuilder()
        .uri(URI.create(target))
        .GET()
        .build();

HttpResponse<String> response = client.send(
        httpRequest,
        HttpResponse.BodyHandlers.ofString()
);
return response.body();

即使增加了“只允许 HTTP 和 HTTPS”的判断,也不能视为完成修复。攻击者仍可能利用内网地址、域名解析变化、重定向、非标准 IP 表示方式、IPv6、代理配置或解析器差异绕过简单过滤。

三、代码审计时应关注的关键细节

1. URL 解析是否只做字符串匹配

诸如 startsWith(" 之类的判断不可靠。它们无法正确区分主机名、用户名信息、端口和路径,也无法处理编码、大小写及规范化问题。

审计时应确认程序是否使用标准 URL 解析器,并且明确检查:

  • 协议是否属于业务需要的最小集合。
  • 主机名是否经过规范化和解析。
  • 端口是否属于允许范围,是否禁止显式端口。
  • 用户名、密码、片段等不必要字段是否被拒绝。
  • 最终连接的 IP 是否属于允许的网络范围。

2. DNS 解析和实际连接是否使用同一结果

只在校验阶段解析一次域名,然后把原始域名交给 HTTP 客户端连接,可能产生 DNS rebinding 风险:校验时得到的是公网地址,真正连接时解析结果却已经变化。

更稳妥的做法是由受控的解析逻辑完成解析和连接,并确保校验过的 IP 被实际使用;或者将出网流量交给统一的网络代理,在代理层执行域名和 IP 策略。对于高风险服务,不建议让业务代码直接拥有任意出网能力。

3. 是否跟随重定向

初始 URL 可能是允许的公网地址,但服务端跟随 30x 重定向后进入受限网络。因此需要限制或关闭自动重定向,并对每次跳转重新执行完整校验。

// 伪代码:每一次跳转都重新校验,不信任 Location 头部
for (int i = 0; i < MAX_REDIRECTS; i++) {
    ValidatedTarget target = policy.validate(currentUrl);
    HttpResponse response = client.request(target);

    if (!response.isRedirect()) {
        return response;
    }
    currentUrl = response.location();
}
throw new SecurityException("redirect limit exceeded");

4. 响应处理是否存在二次风险

SSRF 不只关注“能不能发请求”,还要看响应如何被处理。如果服务端把内部响应原样返回给用户,风险通常更直接;如果响应会被解析为 XML、SVG、图片或压缩包,还需要继续检查 XXE、路径遍历、解压缩炸弹和内容类型混淆等问题。

建议限制响应大小、读取超时时间、允许的内容类型和最大重定向次数,并避免把内部错误信息、响应头和详细网络异常直接返回给前端。

四、推荐的防御策略

1. 优先使用目标标识,而不是让用户提交任意 URL

如果业务只需要抓取固定供应商或固定站点,不要让用户提交完整 URL。可以让用户选择一个服务标识,再由服务端从配置中心映射到预先登记的地址。这样能显著缩小攻击面,也便于变更和审计。

2. 采用正向允许列表

黑名单很难覆盖所有地址表现形式。更合理的策略是仅允许业务确实需要的域名、协议、端口和路径,并在请求前后都进行校验。允许列表至少应包含:

  • 协议:通常只保留业务需要的 HTTPS。
  • 域名:使用精确匹配或经过明确设计的子域名匹配。
  • 端口:默认只允许 443,必要时逐项登记。
  • 路径:限制到具体 API 前缀,避免访问同一站点上的管理路径。
  • 响应类型:只接受业务需要的 MIME 类型。

3. 对地址进行规范化和网络范围校验

无论是 IPv4、IPv6 还是域名,都应在连接前解析为实际 IP,并拒绝回环地址、链路本地地址、私有地址、未指定地址以及企业内部明确禁止的网段。不能只检查字符串是否以某个前缀开头。

需要注意的是,是否允许私网地址取决于业务。如果服务本身确实要访问内部服务,应采用精确的服务注册和网络策略,而不是简单地对所有内网开放。对于云环境,还应在网络层限制访问云平台元数据服务,并根据云厂商建议启用更严格的元数据访问机制。

4. 在网络层设置第二道防线

应用层校验容易因新功能、依赖升级或边界遗漏而失效。建议将出网流量经过 egress gateway、正向代理或防火墙策略,默认拒绝不必要的内网访问,只开放登记过的目标。

容器和虚拟机环境中,不要因为“服务运行在隔离网络里”就忽略 SSRF。网络隔离配置经常随着部署变化,应用本身仍应遵循最小权限原则。

五、安全验证:如何在不触碰真实内网的情况下复现

验证修复时,应使用自建的测试环境,不要探测第三方网络或生产内部地址。可以准备两个本地测试服务:

  • 允许目标:返回固定文本,并记录请求方法、请求头和访问次数。
  • 拒绝目标:模拟回环地址、私有地址、重定向地址和超大响应。

测试重点不是“能否访问某个敏感服务”,而是确认策略是否稳定执行。建议覆盖以下用例:

  • 正常的允许域名和不允许域名。
  • 域名大小写、尾部点号和国际化域名的规范化。
  • 显式端口、非默认端口和缺失端口。
  • 重定向到禁止地址,以及多次连续重定向。
  • IPv4、IPv6、域名解析失败和解析到多个地址的情况。
  • 超时、连接失败、响应过大和内容类型不匹配。
  • 并发请求下的连接池、DNS 缓存和限流行为。

一个合格的测试结果应同时记录:原始输入、规范化后的目标、解析结果、最终连接目标、策略判定原因以及是否发生重定向。这样既便于定位绕过问题,也方便后续审计。

六、日志与监控:不要只在漏洞修复后停止

SSRF 的检测价值很大程度上取决于日志质量。建议在不记录敏感响应内容的前提下,保留以下字段:

  • 调用功能和业务用户标识。
  • 目标域名、端口、协议及规范化后的地址。
  • 策略判定结果和拒绝原因。
  • DNS 解析结果、连接耗时、响应状态和响应大小。
  • 重定向次数、最终目标类别以及异常类型。

监控方面,可以关注短时间内大量请求不同域名、频繁命中拒绝规则、连接超时集中出现、响应体积异常增大等行为。日志中的 URL 参数应进行脱敏,避免把访问令牌、签名参数或用户隐私直接写入集中式日志系统。

七、常见修复误区

  • 只过滤几个字符串。 这类修复通常无法覆盖解析差异和重定向问题。
  • 只禁止 127.0.0.1。 回环、私网、链路本地和 IPv6 地址都需要纳入策略。
  • 校验域名后直接请求原始 URL。 这会留下 DNS 变化和重定向带来的风险。
  • 只在前端限制输入。 前端校验不能替代服务端校验。
  • 发现问题后直接删除功能。 如果业务确实需要远程访问,应通过固定目标、代理和网络策略实现,而不是留下不受控的通用请求能力。
  • 忽略非 HTTP 协议。 如果底层库支持文件、FTP 或其他协议,必须显式限制协议集合。

八、落地检查清单

检查项建议结果
目标来源固定配置或明确的允许列表,避免任意 URL
协议与端口只开放业务必需项,默认拒绝其他组合
DNS 与 IP规范化解析,并校验实际连接地址
重定向默认关闭,或逐跳重新执行策略
响应控制限制超时、大小、类型和读取时间
网络边界通过代理、防火墙或 egress 策略二次限制
审计与告警记录判定原因、最终目标和异常模式

总结

SSRF 的本质是“不受控的服务端出网能力”,而不是某个特殊 payload 或单一过滤规则。审计时应从输入点追踪到 DNS 解析、连接建立、重定向、响应处理和网络出口;修复时则应采用正向允许列表、规范化解析、重定向控制、响应限制以及网络层隔离的组合方案。

对于研发团队,最值得长期保留的做法是封装统一的安全 HTTP 客户端,禁止业务代码各自实现 URL 校验,并在代码审查和自动化测试中固定覆盖地址解析、重定向、超时和响应边界。这样才能把一次漏洞修复转化为可持续的工程能力。

服务器与云环境安全示意图
服务器、云资产与权限边界梳理示意

0篇意见

推荐意见

没有意见。

游客
抱歉,你的帖子内容包括我们不允许的字词。请编辑你的帖子,删除下面高亮的屏蔽字。
添加意见…

SiteMap HACKHAT © 2026 All rights reserved.