跳转到帖子

SSRF(Server-Side Request Forgery,服务端请求伪造)并不是一个只靠“拦截内网 IP”就能解决的问题。实际审计中,风险通常出现在图片抓取、Webhook、URL 预览、文档转换、第三方接口探测等功能里。应用一旦允许用户影响服务端发起网络请求,就需要同时考虑协议限制、地址解析、重定向、DNS 变化、响应大小和网络出口控制。

一、问题背景与典型场景

常见代码模式是接收一个 URL,然后由后端下载内容并返回给用户。例如:

String target = request.getParameter("url");
URL url = new URL(target);
URLConnection connection = url.openConnection();
InputStream input = connection.getInputStream();

这段代码的危险不在于 Java API 本身,而在于 target 完全由外部输入控制。攻击者可能让服务端访问不应该暴露的管理接口、云环境元数据服务、内部调试端口,或者借助重定向绕过初始校验。

从防守角度看,审计重点不是寻找某一个特殊 payload,而是确认以下问题:

  • 请求协议是否限制为 HTTPS 或明确允许的协议。
  • 目标主机是否采用严格的业务白名单。
  • 域名解析后的所有地址是否经过校验。
  • 连接建立后是否还会发生重定向。
  • DNS 解析结果与实际连接目标是否可能不一致。
  • 是否设置连接超时、读取超时和响应大小上限。
  • 服务器网络层是否阻断了不必要的内网出口。

二、代码审计中的分析路径

第一步是从网络请求入口开始追踪数据流。搜索参数名并不可靠,建议同时关注 URL、URI、host、callback、webhook、image、avatar、source、fetch 等字段,再沿着调用链定位真正发起网络请求的位置。

第二步要区分“字符串校验”和“网络连接”。很多修复只对原始字符串做判断,例如禁止出现 127.0.0.1 或 localhost,但 URL 可以使用域名、IPv6、十进制整数形式的 IPv4 地址,或者通过重定向指向不同目标。因此需要以解析后的网络地址为准进行决策。

第三步检查 HTTP 客户端的默认行为。部分客户端默认跟随 3xx 重定向、自动解压响应、复用连接或允许多种协议。如果业务只需要下载固定类型的公开资源,默认行为通常过于宽松。

三、推荐的防护策略

1. 优先使用业务白名单

如果功能只需要从几个固定的对象存储域名下载图片,最稳妥的方案是维护精确的主机名白名单,并限制协议、端口和路径。黑名单只能作为补充,不能作为主要防线。

允许的协议:HTTPS
允许的主机:cdn.example.test、assets.example.test
允许的端口:443
允许的响应类型:image/png、image/jpeg
单次响应上限:5 MB

主机名比较应采用规范化后的结果,避免大小写、尾部点号和端口表示差异造成策略绕过。对于国际化域名,还应明确使用 IDNA 规范化后的形式进行比较。

2. 解析后校验所有 IP 地址

在无法使用严格白名单时,至少要对目标域名解析出的每一个地址进行检查,拒绝回环地址、私有地址、链路本地地址、未指定地址、组播地址以及业务明确不需要的保留地址。不要只检查一次 DNS 结果后就无限期复用。

URI uri = URI.create(input);
if (!"https".equalsIgnoreCase(uri.getScheme())) {
    throw new IllegalArgumentException("unsupported scheme");
}
if (uri.getUserInfo() != null || uri.getHost() == null) {
    throw new IllegalArgumentException("invalid authority");
}

InetAddress[] addresses = InetAddress.getAllByName(uri.getHost());
for (InetAddress address : addresses) {
    if (address.isAnyLocalAddress()
            || address.isLoopbackAddress()
            || address.isLinkLocalAddress()
            || address.isSiteLocalAddress()
            || address.isMulticastAddress()) {
        throw new IllegalArgumentException("private or reserved address");
    }
}

上面的判断适合作为示意,生产环境还应补充企业网段、云厂商保留网段和 IPv6 特殊地址的策略。不同语言和库对“私有地址”的定义并不完全一致,不能只依赖一个便捷方法。

3. 禁止自动跟随重定向

即使初始 URL 通过了检查,服务端也可能收到 301、302、307 或 308 响应并继续请求另一个地址。建议关闭自动重定向,由业务代码逐跳检查新的 Location,并限制最大跳转次数。

HttpClient client = HttpClient.newBuilder()
        .followRedirects(HttpClient.Redirect.NEVER)
        .connectTimeout(Duration.ofSeconds(3))
        .build();

处理 Location 时,应重新执行协议、主机、端口和解析地址校验,不能把它当作普通字符串直接拼接或复用原有连接配置。

4. 限制请求规模和资源消耗

SSRF 防护不能只关注“能不能访问”,还要关注“访问会消耗多少资源”。应设置连接超时、读取超时、最大响应体、最大响应头、最大重定向次数和并发限制。对于图片或文档抓取,还要在服务端根据 Content-Type、文件头和解码后的尺寸再次校验,避免压缩炸弹和超大图片导致内存异常。

四、DNS 重绑定与网络层防护

如果应用先解析域名做安全判断,随后又由底层客户端独立解析并建立连接,就可能出现两次解析结果不同的问题。攻击者控制的域名可以在短时间内改变 DNS 响应,使校验阶段返回公网地址,而连接阶段返回内部地址。

应用层可以通过固定解析结果、使用受控 DNS 解析器、在连接建立前后再次确认目标地址等方式降低风险,但不同 HTTP 客户端对底层连接的控制能力不同。更可靠的做法是将应用层校验与网络出口策略结合起来:

  • 在容器或主机防火墙层禁止访问云元数据地址和不必要的内网网段。
  • 让抓取服务运行在独立网络区域,只允许访问明确的代理或外部出口。
  • 通过 egress proxy 统一执行域名、地址、端口和审计策略。
  • 对异常目标、频繁失败、连接内网地址等行为记录安全日志。

应用层校验解决“业务是否允许请求”,网络层隔离解决“即使校验失效,服务端还能访问到什么”。两者不应互相替代。

五、修复验证与测试用例

修复后不要只测试一个正常 URL。建议建立自动化测试矩阵,覆盖协议、地址族、重定向和异常输入。测试目标可以使用本地模拟服务或专用测试域名,不需要访问真实内部系统。

测试类别示例预期结果
正常请求白名单 HTTPS 主机允许,并记录目标主机
协议限制HTTP、file、gopher 等非业务协议拒绝
地址限制回环、私有、链路本地和保留地址拒绝
重定向公开地址重定向到不允许地址在跳转前拒绝
资源限制超大响应、慢响应、多次跳转超时或中止
解析异常无效域名、IPv6、空主机名安全失败

在测试环境中可以启动一个仅绑定本机的模拟 HTTP 服务,用于验证超时、响应大小和重定向处理:

python3 -m http.server 8000 --bind 127.0.0.1

这里的重点是验证应用是否按预期拒绝不允许的目标,而不是通过真实内网探测来“证明漏洞”。测试日志中应保留请求 ID、规范化后的主机、解析地址、最终状态和拒绝原因,但不要记录敏感响应正文。

六、常见错误修复方式

  • 只拦截字符串 127.0.0.1:无法覆盖域名解析、IPv6 和其他地址表达形式。
  • 只校验 URL 的 hostname:未检查解析结果,也未处理重定向。
  • 使用正则判断 URL:容易忽略用户信息、端口、编码和规范化问题。
  • 校验通过后长时间缓存 DNS:会放大地址变化带来的风险。
  • 只依赖云平台元数据服务的访问令牌:这属于纵深防御,不是应用层授权校验的替代品。
  • 修复后没有限制响应体和超时:即使不能访问内网,仍可能形成资源消耗问题。

七、总结

SSRF 的本质是将服务端的网络位置和权限暴露给了不可信输入。可靠治理需要从数据流审计开始,结合协议与主机白名单、解析后地址校验、重定向控制、资源限制、日志监控和网络出口隔离。对于高风险功能,建议把“任意 URL 抓取”改造成“业务资源 ID 获取”,从设计上减少用户直接控制网络目标的机会。

最终验收时,应同时检查代码路径、HTTP 客户端配置、容器网络策略和自动化测试结果。只有当应用层和基础设施层都具备明确的拒绝边界,修复才不容易因库升级、配置变化或新增功能而再次失效。

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

0篇意见

推荐意见

没有意见。

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