服务端请求伪造(SSRF)并不只是“让服务器访问一个外部 URL”。在真实项目中,它往往出现在图片抓取、Webhook、在线预览、文件导入、URL 扩展等功能里。问题的核心是:攻击者能够影响服务端发起请求的目标,而应用又没有正确限制目标地址、协议、重定向和请求范围。SSRF 的危害取决于服务端所在网络环境。一个看似只能访问公网的功能,可能因为网络分区、代理配置、云环境元数据服务、内部管理接口或本机调试端口而获得更高权限。因此,审计时不能只盯着某一条黑名单规则,而应从“输入如何流向网络请求”以及“请求最终能到达哪里”两个方向同时分析。一、先明确审计边界和风险模型在开始复现前,应确认测试对象属于授权范围,并尽量使用本地靶场、隔离测试环境或由团队提供的模拟服务。验证 SSRF 不需要访问真实的内网资产,也不需要请求云平台元数据地址。最稳妥的方式是准备一个可控的本地 HTTP 服务,观察应用是否按照预期发起请求。建议先回答以下问题:用户可控的输入是否最终进入了 HTTP、HTTPS、TCP 或其他网络客户端?应用是否允许用户指定完整 URL,还是只允许指定路径、资源编号或域名?请求是否会自动跟随 30x 重定向?域名解析发生在校验之前还是之后?请求实际连接的 IP 是否经过再次确认?应用运行环境是否能访问管理网、容器网桥、主机回环地址或云厂商特殊地址?响应内容是否会返回给用户,还是仅作为后台任务执行?二、从代码中定位 SSRF 数据流代码审计时,建议采用“源点—传播—汇点”的方式,而不是只搜索某个函数名。常见源点包括请求参数、JSON 字段、数据库中可编辑的 URL、消息队列任务内容和文件元数据。传播过程可能经过 URL 拼接、Base64 解码、模板渲染、重试逻辑或代理配置。常见汇点则包括 Java 的 HttpClient、Python 的 requests、Node.js 的 fetch、Go 的 http.Client,以及一些图片处理、PDF 转换和网页截图组件。下面是一段典型的高风险代码。问题不在于使用了 HTTP 客户端,而在于目标完全由用户控制,并且默认允许自动跳转。public byte[] fetch(String target) throws IOException {
URI uri = URI.create(target);
HttpClient client = HttpClient.newBuilder()
.followRedirects(HttpClient.Redirect.NORMAL)
.build();
HttpRequest request = HttpRequest.newBuilder(uri)
.timeout(Duration.ofSeconds(10))
.GET()
.build();
return client.send(request, HttpResponse.BodyHandlers.ofByteArray()).body();
}这类代码至少存在几个审计关注点:协议未限制、主机未限制、域名解析结果未校验、重定向目标未重新检查、响应体大小没有上限。即使后续加了一条“禁止 localhost”的规则,也不能覆盖所有等价地址表达形式和解析时序问题。三、验证漏洞时使用可控的本地服务为了避免触碰非授权目标,可以在本机启动一个简单的模拟服务,并让业务程序只访问这个服务。下面的 Python 示例会记录请求路径、来源地址和请求头,便于判断服务端是否真正发起了请求。from http.server import BaseHTTPRequestHandler, HTTPServer
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
print(
推荐意见