跳转到帖子

SSRF(Server-Side Request Forgery,服务端请求伪造)在代码审计中很常见。它通常不是一个“单点漏洞”,而是由用户可控 URL、服务端网络访问能力、协议处理不严谨以及出站访问缺少隔离共同造成。实际排查时,如果只过滤几个字符串,往往只能挡住最简单的测试用例,无法覆盖重定向、IPv6、DNS 解析和代理配置等场景。本文以代码审计和防守为主线,整理 SSRF 的形成条件、常见误区、可复现的安全测试方法,以及更适合生产环境的修复思路。示例均应在自建靶场或已授权的测试环境中使用。一、问题背景:为什么 SSRF 容易被低估很多业务都需要服务端访问外部资源,例如图片抓取、Webhook 回调、在线文档解析、第三方接口代理和 URL 预览。典型代码大致如下:from urllib.parse import urlparse
import requests

def fetch_url(url):
parsed = urlparse(url)
if parsed.scheme not in ('http', 'https'):
raise ValueError('unsupported scheme')
response = requests.get(url, timeout=5)
return response.content表面上限制了协议,但服务端仍然可能访问不应暴露的地址。风险主要来自以下几个方面:应用所在网络能够访问管理端口、内部服务或本机接口。URL 的主机名、端口和解析结果完全由用户控制。HTTP 客户端默认跟随重定向,初始地址与最终地址可能不同。只校验字符串,没有校验 DNS 解析后的全部 IP 地址。应用所在容器或云主机具有过大的网络权限。因此,SSRF 的影响不能只看“是否能访问某个地址”,还要结合应用部署位置、网络分段、云平台元数据服务、凭据权限和响应内容处理方式综合判断。二、代码审计时优先关注哪些位置审计可以先从“服务端发起网络请求”的调用点反向追踪输入来源。常见危险函数和业务位置包括:Python 中的 requests.get、urllib.request.urlopen、httpx.get。Java 中的 URL.openConnection、HttpClient、RestTemplate。Node.js 中的 axios、got、http.request。图片、PDF、网页快照、Markdown 远程资源解析器。Webhook、回调地址、导入 URL、代理接口和远程文件下载功能。判断是否构成 SSRF,建议沿着数据流回答四个问题:用户是否能够影响目标 URL、主机名、端口或请求头?请求是否由服务端发起,而不是由浏览器直接发起?服务端所在网络是否比普通用户网络更可信或更接近内部资源?响应是否会返回给用户,或者至少影响后续业务逻辑?如果四个问题大部分都能得到肯定答案,就应该进一步检查地址校验、重定向、DNS 解析和出站网络策略。三、常见绕过点:不要只做字符串黑名单1. 主机名与解析结果不一致只判断 URL 中是否包含某些内网地址并不可靠。域名可能解析到私有地址,DNS 记录也可能随时间变化。更稳妥的做法是先解析域名,再对所有解析结果进行地址分类。import ipaddress
import socket

def resolve_public_addresses(hostname):
results = socket.getaddrinfo(
hostname,
None,
type=socket.SOCK_STREAM
)
addresses = set()

for item in results:
address = item[4][0]
ip = ipaddress.ip_address(address)
if (
ip.is_private
or ip.is_loopback
or ip.is_link_local
or ip.is_multicast
or ip.is_reserved
or ip.is_unspecified
):
raise ValueError('destination address is not allowed')
addresses.add(str(ip))

if not addresses:
raise ValueError('no usable address')
return addresses这段代码只适合作为示例,生产环境还需要根据业务需求处理保留地址、企业专用地址、IPv4 映射 IPv6 地址以及特殊网络拓扑。关键点是不能只检查第一个解析结果,也不能把 DNS 查询结果长期缓存后无限信任。2. 重定向导致“初始校验失效”即使初始 URL 通过校验,目标服务器仍可能返回 301 或 302,把客户端引导到另一个地址。对于不需要重定向的业务,应直接关闭自动跟随:import requests

def fetch_external(url):
response = requests.get(
url,
timeout=(3, 5),
allow_redirects=False,
headers={'User-Agent': 'approved-fetcher/1.0'}
)
response.raise_for_status()
return response.content如果业务必须支持重定向,应对每一跳重新执行协议、主机名、解析结果、端口和响应大小校验,并限制最大跳转次数。不要只校验第一跳。3. IPv6、非标准 IP 表示和端口问题很多过滤逻辑只考虑常见的 IPv4 字符串,容易遗漏 IPv6 地址、IPv4 映射 IPv6 地址以及不同格式的 IP 表示。防护时应使用标准库解析为 IP 对象后再判断,而不是通过字符串前缀比较。端口也需要明确限制。若业务只是抓取网页,可以只允许 443 和 80;如果确实需要其他端口,应维护清晰的白名单。不要让用户通过任意端口访问本机或内网服务。4. URL 解析与凭据字段混淆URL 语法中可能包含用户名、密码、端口和片段等字段。安全校验应基于标准解析器提取的 scheme、hostname、port,不要直接对原始字符串做截取或拼接。实际工程中还应拒绝携带用户凭据的 URL,避免日志、代理和下游服务意外记录敏感信息。四、一个相对完整的防护流程单靠应用层判断通常不够,建议将防护拆成入口校验、请求执行和网络隔离三层。第一层:规范化并校验 URL只允许业务需要的协议,通常为 HTTP 和 HTTPS。拒绝空主机名、用户名密码、异常端口和不必要的 URL 组件。优先使用域名白名单;如果业务必须支持任意外部站点,再进行 IP 分类。限制 URL 长度,避免解析器差异和资源消耗问题。第二层:控制请求行为设置连接超时、读取超时和整体超时,避免请求长期占用线程。限制响应体大小,不要无条件把远程内容全部读入内存。默认关闭重定向,必要时逐跳校验。限制请求方法和请求头,避免用户借助代理功能构造任意请求。不转发原始 Cookie、Authorization 等用户凭据。第三层:限制出站网络在防火墙、安全组或服务网格层面限制应用出站网段和端口。将需要抓取外部资源的功能放入独立 worker 或隔离网络。使用受控出站代理,在代理侧执行域名、IP、端口和审计策略。云环境中按照厂商建议保护实例元数据服务,并避免应用获得不必要的实例角色权限。经验上,出站网络隔离比应用层黑名单更可靠。应用代码存在遗漏时,网络层仍应提供最后一道边界。五、如何在授权环境中安全验证验证 SSRF 时不建议直接探测真实内网或云平台管理接口。可以在本地或隔离实验环境中准备两个自建服务:公开测试服务:返回固定文本,模拟正常外部站点。内部模拟服务:只监听实验网络地址,返回明显的测试标记,不包含真实凭据或敏感数据。然后观察应用是否能访问内部模拟服务、是否会跟随重定向,以及日志中记录的目标地址是否完整。测试重点应放在防护逻辑,而不是扩大访问范围。例如可以检查:私有地址是否被拒绝。解析到多个地址时,是否逐个校验。重定向到不允许地址时,是否中止请求。超大响应和慢响应是否被限制。异常 URL 是否不会触发服务进程崩溃。测试完成后,应保留请求时间、目标域名、解析结果、拒绝原因和请求耗时等审计信息,但不要记录完整的 Authorization、Cookie 或响应中的敏感数据。六、审计和修复中容易犯的错误只过滤 127.0.0.1:这无法覆盖其他环回地址、私有地址、IPv6 和 DNS 解析结果。只检查 URL 字符串:字符串看起来正常,不代表最终连接地址安全。先解析再无限期复用 IP:DNS 结果会变化,连接阶段还可能发生解析差异。认为关闭重定向就足够:如果业务代码手动处理 Location,仍需重新校验每一跳。把 SSRF 修复成一组黑名单:黑名单维护成本高且容易遗漏,优先采用白名单和网络隔离。忽略解析器和 HTTP 客户端差异:应用层解析出的主机名与底层连接实际使用的地址可能不一致,重要场景应使用统一的网络访问组件或出站代理。七、建议加入的监控与回归测试修复后不要只保留一条单元测试。建议建立覆盖输入解析、网络请求和业务行为的回归用例,至少包括:测试类别检查内容协议拒绝非业务需要的协议和异常协议大小写地址覆盖环回、私有、链路本地、保留地址和 IPv6解析多 A/AAAA 记录、解析失败、解析结果变化跳转正常跳转、跨域跳转、跳转到禁止地址资源慢响应、超大响应、连接失败和重复重试权限确认抓取服务没有不必要的内网访问权限和云端凭据权限监控方面,可以对出站请求按目标域名、解析 IP、端口、状态码、耗时和拒绝原因进行聚合。发现应用突然访问大量新域名、管理端口或异常地址段时,应结合业务变更记录进行核查。八、总结SSRF 的核心不是“过滤一个危险 IP”,而是控制服务端从哪里、以什么协议、通过什么网络路径发起请求。较稳妥的处理顺序是:从数据流确认用户可控输入是否进入服务端请求函数。使用标准 URL 和 IP 解析库,校验协议、主机、端口以及全部解析结果。默认关闭重定向,必要时逐跳重新校验。限制超时、响应大小、请求头和凭据转发。通过出站代理、防火墙和独立网络进一步收敛访问范围。用自建模拟服务完成安全验证,并将关键场景纳入回归测试。从长期维护角度看,最值得投入的是统一网络访问组件和网络出口策略。业务代码不再各自实现一套不完整的 URL 过滤逻辑,审计、监控和修复成本都会明显降低。

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

0篇意见

推荐意见

没有意见。

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