
刚接触 web 渗透时很多人会把 SSRFServer-Side Request Forgery服务端请求伪造当作一个“听名字很凶、实战里老碰不到”的漏洞。真正做过一段时间安全测试后你会发现SSRF 的破坏力远不是“能访问个内网端口”这么简单它经常是内网横向、云上凭证泄露、甚至直接拿下一台主机的前置跳板。尤其近几年云原生架构普及之后SSRF 的利用价值被放大了一个量级。我打算把这块从原理到实战再到最近的 AI 辅助漏洞挖掘趋势一次讲清楚。这篇文章适合三类人看正在学 web 渗透、想系统理解 SSRF 的学生做企业安全建设、需要排查修复 SSRF 的工程师以及想了解 AI 辅助漏洞挖掘到底能做什么的安全从业者。我会尽量用“当时我是怎么一步步测出来的”这种实际经验来讲而不是把 OWASP 的定义复读一遍。内容偏长但每段都有信息量建议按顺序读。1. SSRF 的核心原理服务器擅自替你“出差”先说本质。SSRF 的触发点是服务端在接收用户传入的 URL 之后由服务器本身发起请求去访问这个 URL并且没有做严格的访问控制。这里的关键不是“用户能输入 URL”而是“请求是从服务器发出去的”。攻击者把自己的意图包装成一个地址操纵服务器作为代理去访问攻击者无法直接访问的地方。打个比方你是一个员工公司前台可以帮你收发任何快递。前台本来只应该帮你接收来自指定快递公司的件但如果你说“请帮我去隔壁大楼取个文件”前台也照做了那你就借助前台进入了平时进不去的区域。SSRF 就是这场“借他人之手进入禁区”的戏。日常业务里下面这些场景经常藏着 SSRF图片处理服务用户传一个图片 URL服务端去抓取然后裁剪、压缩、加水印。链接预览功能IM 工具、社交平台里发一个链接服务端去爬取标题和缩略图。文档转换服务把远程 URL 对应的文件转成 PDF 或图片。Webhook 通知用户自定义回调地址服务端主动 POST/GET 过去。支付回调、短信回执、电子合同签署等业务方需要访问用户提供的地址。这些场景的共同点是用户对最终发起请求的服务端地址不可见但服务端会替用户去访问任意 URL。当目标 URL 变成http://127.0.0.1、http://10.0.0.5、http://[::1]甚至云元数据地址时危险就出现了。为什么说它比很多漏洞更隐蔽因为 SSRF 的本质不是“攻击代码执行”而是“边界被绕过”。传统 WAF 会盯着入站流量里的 payload但 SSRF 的请求看起来就是一个正常的 HTTP 抓取请求而且真正的攻击流量是服务器自己发出去的。很多防御体系的视野在内网出口处才消失正好给 SSRF 留出了空间。实战中SSRF 的影响范围至少有这样几个层次访问本机服务比如 Redis、Memcached、docker API、管理后台端口。扫描内网网段探测存活主机、开放端口判断内网资产。访问云元数据服务拿到临时凭证、用户数据。借助其他协议如gopher://、dict://构造特殊请求去攻击非 HTTP 协议的服务。变成跳板从内网继续横向移动攻击其他主机、数据库、堡垒机。理解了这一层再看后续的利用和防御思路就会清晰很多。2. 攻击面找对入口少走弯路很多新手在测试 SSRF 时只知道找“url 参数”。确实绝大多数 SSRF 都藏在 URL 参数里但入口点远不止这一个。我实际测试时习惯把入口划分为几类这样效率更高。2.1 容易被忽略的输入点最常见的是 GET/POST 里的 URL 参数典型参数名叫url、src、target、addr、dest、redirect、callback、source、link、image、domain包括中文系统里的“图片地址”“跳转链接”。不要只看参数名有没有 url我用dirsearch或手工翻接口时常见到开发把远程资源地址写成?source、?file甚至?path这类同样可能触发请求。除了参数还要注意这几个地方请求头X-Forwarded-Host、X-Real-URL、Forwarded、Referer某些框架会根据这些头去拼接地址并主动请求。JSON/XML 结构体字段比如{img_url: ...}图片上传组件常常在 JSON 里放一个地址字段后端拿去抓取。文件导入支持从 URL 导入文件的功能比如“从链接导入文档”“同步远端图片”。Webhook 配置用户创建一个 webhook 时填写的回调地址如果服务端不做限制会变成典型的 SSRF。域名解析功能部分在线工具提供“查看域名信息”实质是后端发起 DNS/HTTP 请求输入内网域名就会触发。SSRF 出现在“反向代理/跳转服务”业务上做短链、统一登录跳转时目标地址如果没做域名校验也会形成 SSRF。测试时有个捷径观察前端 JS 里出现的“服务端请求”字样或者直接抓包看触发后服务器是否产生新的出站连接。如果页面本身就能加载远端图片多半后端有请求能力。2.2 有回显型与盲打的差别从攻击者的视角SSRF 可以分为三类直接回显型服务端把响应内容直接返回给前端。比如图片抓取服务把抓到的图片字节流返回或者文档预览功能把远端 HTML 渲染出来。这类最好利用因为你能直接看到内网服务的响应内容。半回显型不返回完整响应但会根据结果产生差异。比如“封面图是否抓取成功”会提示成功/失败“链接预览”会显示标题或简介。通过差异能判断端口是否开放、页面是否存在。盲打型服务端发起请求但结果完全不反馈给客户端。比如日志系统记录回调结果或消息队列异步处理。这种只能靠 DNS 查询、HTTP 请求日志等外带通道来验证也就是常见“盲 SSRF”。很多人一遇到无回显就放弃实际上盲打的价值也不小。后面第 6 章会专门讲推进姿势。3. 实操中的探测与确认确定一个入口是否真的能产生 SSRF不能光靠看代码。我平时的验证流程一般是“先带外后内网”用最少的请求确认最可靠的事实。3.1 用带外监控确认请求第一种验证方式是把目标地址指向一个你自己控制的公网服务器。目的很简单确认服务端是否真的发起了请求、请求的来源 IP 是什么、走的什么协议。具体操作可以这样准备一台有公网 IP 的 VPS在上面跑一个简单的 HTTP 监听比如nc -lvnp 8080记录请求日志。在目标应用里找一个可能触发 SSRF 的地址字段填入http://你的IP:8080/test。触发功能观察服务器是否收到请求记下来源 IP、请求头、User-Agent、时间戳。如果收到请求说明服务端确实具备“替用户发起 HTTP 请求”的能力。第二种更推荐的方式是使用带外监控平台它们通常提供 DNS 解析记录和 HTTP 记录。测试时给一个唯一的子域名比如xxx.dnslog.cn如果服务器收到 DNS 查询请求就说明存在请求逻辑。DNS 通道的优点是很多业务代码会先解析域名再决定是否继续连 HTTP 请求都不一定能走到但 DNS 查询一定会有。我的习惯是先填一个 http 地址再填一个不存在的域名分别看日志。如果 HTTP 地址有回显但 DNS 没有可能代码里做了协议限制如果 DNS 有记录但无 HTTP 记录可能是服务端先解析域名但后面的连接没建立成功也可能是只发起了 DNS 查询。这一步的意义是完成“存在性确认”。从安全测试角度看再往下才是判断地址限制和可利用范围。3.2 通过响应差异判断内网资产在确认服务端会发请求之后就要判断这个请求是否能访问内网地址。如果目标应用有响应差异这一步会更快。方法是在 URL 里逐个尝试内网常见地址、探测目标端口观察响应差异填入http://127.0.0.1:80/和http://127.0.0.1:9999/看是否一个成功一个失败。填入http://127.0.0.1和http://192.168.1.1看超时时间是否不同。填入一个假的公网域名和一个真实存在的公网域名看响应是否不同。观察错误信息代码里如果直接返回connection refused、timeout、no route to host那通过错误类别就能反推目标端口状态。比较实用的响应差异维度有维度现象含义内容返回了 HTML、JSON、二进制目标服务可访问状态码200/302/404/500 不同端口开放但路径不同超时时间立即失败 / 长时间等待目标地址可达性不同错误文本“拒绝连接”“超时”“解析失败”判断协议和网络状态长度响应内容长度明显不同确认返回内容不同源在做完“存在性确认”和“内网探测”之后不要急着继续扩大攻击范围。很多目标系统有请求限流、WAF 和告警高频探测会暴露指纹。我这边的节奏是先小范围探测拿到足够证据就整理报告而不是把内网全扫一遍。4. 常见过滤手段与绕过思路企业开发多少会有防御意识常见的做法是黑名单封禁内网 IP或者要求 URL 的域名必须在白名单里。但绕过思路也一直在演进这里站在防御侧反推它们是怎么绕的。4.1 黑名单过滤到底哪里不够用黑名单的思路是禁止127.0.0.1、10.、192.168.等内网 IP 出现在 URL 中。问题在于 IP 地址在标准里有大量等价写法URL 解析器会把“看起来完全不同的字符串”解析成同一个 IP。举几个真实的例子http://127.1可以被解析成127.0.0.1因为很多系统默认把省略段补成 0。http://2130706433是127.0.0.1的十进制整数形式。http://0x7f000001是十六进制形式。http://0177.0.0.1是八进制形式。http://[::ffff:127.0.0.1]是 IPv6 映射 IPv4 的写法不少过滤逻辑只查 IPv4 字符串根本不识别。如果开发只做了简单的字符串匹配上面任意一种都能绕过去。而且不要忽略 DNS 层域名解析到的最终结果才决定请求去哪里黑名单如果只检查文字面值不检查解析后的 IP那么攻击者可以自己注册一个域名解析到内网 IP用这个合法域名就能绕过规则。还有 URL 解析不一致的问题。比如http://example.com127.0.0.1/在大多数浏览器里的语义是“访问127.0.0.1”而不是访问example.com。如果黑名单检查的是整段字符串里的“example.com”就会漏掉了后面真正的目标地址。另一个常见例子是http://127.0.0.1#example.com片段部分根本不是实际请求主机。这属于“解析器语义差异”绕过字符串层面的黑名单很难根治。4.2 绕过手法清单我根据实战和公开研究整理了一个精简的清单按类别说明常见手法。测试和防御时都可以对照绕过类别典型案例本质原因IP 进制转换2130706433、0x7f000001、017700000001过滤只认十进制点分格式IPv6 变体[::ffff:127.0.0.1]、[::1]过滤没有覆盖 IPv6 地址族短格式 IP127.1、10.0.0解析器自动补 0过滤没适配特殊符号http://127.0.0.1%00.baidu.com同一字符串在不同解析器里含义不同重定向先访问公网地址服务端跟随 302 跳到内网过滤只验证原始 URL没检查目标响应DNS 重绑定域名第一次解析为公网 IP第二次解析为内网 IP检查和请求之间出现时间差协议换用gopher://、dict://、file://过滤只封了 http/https控制字符URL 编码后的换行、空格影响解析解析器差异防御方看到这张表应该意识到一个结论只靠 String.contains 判断目标地址是封不住的正确做法是“统一解析 解析后校验 重定向处理”三层叠加这部分在第 8 章会给完整方案。5. 云环境里的高危目标实例元数据SSRF 在内网里折腾半天最终极的目标之一是云上的实例元数据服务。云原生环境里几乎每台云主机都能访问一个保留地址通过这个地址可以获取主机自身的元数据包括网络配置、用户数据甚至临时访问凭证。当 SSRF 能打到这个地址时攻击面就从“内网端口扫描”升级成“云凭证窃取”。5.1 元数据地址为什么会成为靶子在大部分云平台上元数据服务的地址是一个全局保留的链路本地地址形如169.254.169.254。这个地址对攻击者来说有个致命特点它不在公网但在每一台云主机内“天然可达”。外部攻击者发一个请求到169.254.169.254是到不了的但如果服务端存在 SSRF攻击者让服务器去访问这个地址就能拿到这台主机的元数据。拿到元数据意味着什么能读取实例 ID、主机名、网卡信息辅助后续内网渗透。能读取用户数据可能存在初始化脚本里的敏感配置。能申请临时 API 凭证。拿到凭证后攻击者就能调用云平台接口读写对象存储、创建资源、操控安全组影响范围从一个实例扩大到整个账号。这不是理论漏洞。早在多年以前就有过知名案例某个网站通过http://169.254.169.254最终拿到了云账号凭证然后横向到整个云资源池。这个漏洞模式至今仍在大量云上应用里出现。从防御角度看最关键的一条是默认情况下不能假设服务器永远访问不到元数据地址。任何发往元数据地址的出站请求都值得告警。5.2 测试时的取证要点做授权范围内的安全测试时如果确认存在 SSRF并且目标是云主机我通常按这个顺序取证先确认目标主机的网络环境。如果目标部署在云上通过页面底部备案、报错日志、DNS 解析记录等线索能大致判断云厂商。用 SSRF 访问元数据地址的根路径或健康检查路径确认能拿到响应。注意这里只需要访问基础路径不需要急着申请凭证避免不必要的风险扩散。确认可达性后直接截图记录“请求发出 响应返回”的完整数据包作为漏洞报告的核心证据。如果目标是内网中间件比如 Redis、数据库尽量只做端口连通性验证不深入执行命令测试边界控制在 POC 层面。我见过不少测试人员一拿到 SSRF 就马上尝试读取完整元数据、申请凭证、访问对象存储结果把一次授权范围内的测试变成了越权操作。安全测试的基本原则始终是“最小化验证记录证据不扩散影响”。6. 盲 SSRF 的推进姿势盲 SSRF 的意思是服务端确实发起了请求但任何响应都不会返回给客户端。这在真实业务里太常见了比如异步回调、消息队列消费、日志采集。很多新手卡在“看不到响应”这一步其实盲打也有自己的推进方式。6.1 无回显不等于没用盲 SSRF 的核心验证通道是“带外数据”。即使页面没有任何变化只要服务端会发起请求它就会产生 DNS 解析记录、TCP 连接、HTTP 请求日志甚至是邮件发送日志。常见的推进方法是在带外监控平台上申请一个唯一的子域名填入 SSRF 入口触发请求。如果收到该子域名的 DNS 解析记录说明服务器确实请求了这个域名。再换一个内网 IP 的 URL比如http://10.0.0.1:port配合带外监控平台的“IP端口的请求”来判断内网主机是否存活、端口是否开放。这里有个技巧如果服务端对 URL 的协议有限制不允许 http 外的协议但允许 DNS 解析那么可以在带外平台上配置任意解析记录请求不同内网 IP 时会触发不同的 DNS 查询由此判断“这段内网 IP 是否可路由”。盲 SSRF 的另一个价值是作为“内网探测器”让服务器逐个请求内网地址记录哪些地址产生连接、哪些没有相当于在隐蔽地绘制内网资产分布图。这在实战里经常用于确认内网目标再通过其他漏洞去进攻主机本身。6.2 盲打场景下的判断方法盲打怎么判断“请求真的发出去了”我用过的可靠方法有三个DNS 查询记录这是最轻量的确认方式。比如给入口填入test.dnslog.cn如果收到查询记录说明服务端至少执行了 DNS 解析。DNS 解析不等于 HTTP 请求成功但至少说明 URL 没有被静态过滤拦截。HTTP 访问日志如果带外平台收到 HTTP 请求说明 TCP 连接已建立协议栈走通了。这时候可以记录请求路径、User-Agent、来源 IP判断目标设备的指纹。TCP 连接记录有些时候服务端发起的不是 HTTP 请求而是其他协议比如 FTP、SMTP。带外平台的原始 TCP 监听端口会收到连接此时能确认“可以访问任意 IP端口”为后续利用协议变体提供了证据。不管哪种方法盲 SSRF 的利用通常需要耐心。因为没法即时回显需要反复调整 URL、等待日志刷新。我的习惯是每测试一个入口先建一个全新的带外子域名避免不同测试用例之间互相污染判断。7. 当 AI 参与 SSRF 挖掘新工具与新坑最近圈子里的热词是“AI 漏洞挖掘”。很多人问AI 到底能在 SSRF 上帮多少忙我的观点是AI 不能直接“打穿”目标但它在漏洞模式发现、测试用例生成、代码审计辅助这三个方向上确实有用同时也带来了一些新问题。7.1 AI 能帮上什么忙第一个方向从代码里快速定位疑似 SSRF 入口。传统人工审计要找requests.get(url)、urlopen(url)、HttpClient之类的方法调用还要跟进参数来源。AI 可以快速扫一遍代码标记“用户可控参数进入网络请求函数”的数据流并给出调用链。这个能力在代码量大的项目里很省时间。第二个方向生成绕过策略和测试用例。针对黑名单过滤AI 能根据规则自动生成一批变体 URL比如进制转换、IP 缩写、URL 编码嵌套、 符号混淆直接作为输入用例。这里的价值不是“神奇”而是高效枚举把人类容易漏掉的组合补齐。第三个方向辅助理解响应差异。当 SSRF 返回大量内网探测结果时AI 能帮忙归类状态码、判断端口服务类型甚至从头疼的报错日志里提炼出“端口开放”的规律。我自己试过一个场景一个老旧的 Java 项目找不到 URL 参数但有很多getResource()调用。用 AI 辅助分析后发现其中一个接口会根据用户传入的路径前缀拼接资源地址这不就是藏得很深的 SSRF 入口吗。这种“代码数据流 人工验证”的组合确实比纯手工省力。7.2 使用边界与校验成本AI 辅助也踩过坑重点说两条。第一AI 生成的“漏洞结论”不能直接采信。它经常会基于“看起来像”的代码结构得出误报结论比如把${url}用在redirect:里误判成 SSRF但对真实的利用链一无所知。我见过有人拿着 AI 扫描报告去提交漏洞被打回好几轮原因是根本没验证请求是否真的发出。正确的姿势是AI 给线索人工验证事实。第二不要把敏感的真实目标 URL 直接丢给公共 AI 服务。企业授权测试的资产信息、内网 IP、漏洞数据都涉及保密边界直接拿去和公共模型对话等于变相泄露资产数据。合规的做法是使用私有化部署的模型或者只在工作环境里做静态分析。我的个人看法是AI 在 SSRF 挖掘里更像一个“加速器”而不是“替代者”。它能帮你找线索、生成用例、整理输出但最终对漏洞边界的判断、影响范围的评估、利用链的构造还是得靠人对协议、网络和业务的深入理解。这个观点以后也不会变。8. 修复不是简单封 IP从代码到网络的完整防御很多开发在收到 SSRF 漏洞报告后的第一反应是“把内网 IP 加到黑名单”。这个方案治标不治本而且就像第 4 章说的黑名单绕过手法一大把。真正有效的修复需要从应用代码、网络控制、日志监控三个层面一起做。8.1 代码层的白名单方案核心原则是服务器发起的对外请求目标必须经过显式校验且只允许访问允许列表中的域名或 IP。具体做法可以参考下面这个思路解析用户输入的 URL把协议、域名、路径拆出来。只允许 http/https 协议其余协议直接拒绝。对域名做 DNS 解析拿到解析后的 IP。校验该 IP 是否在允许列表内且不是内网、环回、链路本地、多播等特殊地址。对重定向也要重新校验一次不能只看最初的 URL。防止 DNS 重绑定校验 IP 和实际连接 IP 必须一致。一个简化版的安全实现Python 示例可以这样写import ipaddress import socket from urllib.parse import urlparse ALLOWED_HOSTS {example.com, img.example.com} ALLOWED_NETWORKS [ipaddress.ip_network(100.64.0.0/10)] def is_safe_url(user_url): parsed urlparse(user_url) if parsed.scheme not in (http, https): return False host parsed.hostname if host not in ALLOWED_HOSTS: return False try: ip ipaddress.ip_address(socket.gethostbyname(host)) except Exception: return False if ip.is_private or ip.is_loopback or ip.is_link_local: return False for net in ALLOWED_NETWORKS: if ip in net: return False return True当然这段代码只是示意。生产环境要处理 IPv6、URL 解析差异、代理环境、重定向跟随、DNS 重绑定等细节但它体现了“先解析、后校验”的正确思路。值得强调的是不要只校验字符串里有没有“127.0.0.1”这几个字而要校验最终解析出来的 IP 和实际建立连接的 IP。修复代码时必须把“用户输入的 URL”和“服务器实际请求的 URL”区分开。前者是可控变量后者才是安全决策的依据。8.2 网络层的附带控制就算应用代码写得再严谨也不可能覆盖所有历史接口。网络层的兜底控制非常关键。具体可以做的在出站防火墙上限制服务器可访问的 IP 范围至少挡住内网网段和云元数据地址。使用代理网关统一转发外网请求在代理层加白名单域名。微服务环境里对外请求统一走 Egress Gateway在网络策略里只放行必要的对外访问。对云主机配置安全组策略禁止普通业务实例访问云元数据服务端口除非确有需要。对直接访问云元数据地址的出站流量在网络层做阻断并告警。网络层方案和代码层方案不是二选一。我的经验是代码白名单是第一道闸门网络策略是第二道保险。再完善的应用层校验也可能被解析差异绕过去但网络层的目标过滤是最后能拦住一切的底线。8.3 日志与告警建设修复 SSRF 不等于完事还要保证下次出现时能第一时间发现。日志和告警至少覆盖这几类所有服务端发出的出站请求完整记录 URL、目标 IP、状态码、请求来源。对访问内网网段、环回地址、链路本地地址的出站请求单独标记高危。对访问云元数据地址的出站请求必须告警。统计短时间内的异常出站请求数量高频探测行为要触发限流。记录 DNS 解析失败但仍有后续行为的请求这可能是过滤绕过的前兆。在 SIEM 或日志平台里我会建一条简单的规则源 IP 属于业务服务器 目标 IP 属于 RFC1918 地址或 169.254.0.0/16 请求协议是 HTTP/HTTPS → 触发中危告警。这条规则误报率不高还能覆盖很多还没被利用的 SSRF 入口。9. 踩坑记录与实战经验最后一部分我想直接记录这些年测试 SSRF 时踩过的坑和总结下来的习惯都是文档里不太会写的东西。9.1 几个容易误判的情况误判一公网 DNS 记录不等于 SSRF。有时你填一个域名带外平台确实收到解析记录但这是前端浏览器发出的 DNS 查询而不是服务端发起的。判断方法很简单看来源 IP。浏览器发出的查询来自客户端出口 IP服务端发起的查询来自目标服务器 IP。不看来源 IP 就断言“存在 SSRF”很容易闹乌龙。误判二把“前端 JavaScript 文件获取”当成服务端请求。如果后端只是返回一个包含img src用户可控地址的页面加载图片的是浏览器不是服务器。这种“前端 SSRF”严格说不是服务端请求伪造。真正确认 SSRF必须证明请求是从服务端进程发起的。误判三请求发起成功不代表目标内网可访问。有时服务端请求了一个10.x.x.x地址但因为网络隔离或安全组限制连接超时或失败。这时候只能证明“存在对任意地址发起请求的能力”不能直接证明“能访问内网资源”。报告里要区分“能力存在”和“影响成立”。误判四只测了一个协议就结束。很多入口支持http://但同时也支持file://、gopher://、dict://。如果后端过滤只拦了 http说不定换file:///etc/passwd就能直接读本地文件。测试时把协议变体都试一遍不要预设结论。9.2 个人工具习惯与建议我在 SSRF 测试里常用的工具和习惯用带外监控平台而不是只靠 VPS原因是它能自动生成唯一子域名DNS/HTTP/TCP 记录集中管理回溯测试时省心。准备一个常用探测 IP 清单包括环回地址、内网保留段、云元数据地址测试时直接复制不需要现场手写。抓包时记得开Ignore HTTP Proxy否则请求会走本地代理导致来源 IP 和服务端 IP 混在一起。测试时尽量用唯一的 URL 路径区分每次请求比如http://监控地址/ssrf1、/ssrf2。这样在日志里能直接定位是哪个 payload 产生的记录。报告里一定要附“请求包 服务端出站日志”的对照截图。只贴一张 SSRF 界面截图漏洞审核人员很难判断是否是浏览器行为引起的。说到 AI 辅助我最后再分享一个小技巧。现在用 AI 做代码审计时会明确告诉它“只寻找服务端向用户可控 URL 发起请求的数据流忽略前端逻辑输出调用链和入口函数”这样得到的线索比单纯问“有没有 SSRF”准确得多。拿到 AI 输出后还是要自己手动验证一遍数据流是否真的可控、服务端是否真的发起了请求。测多了就会发现AI 最大的价值不是替你判断而是帮你把注意力放到真正值得深挖的代码位置上去。这个配合思路后面做各种漏洞挖掘都能复用。