SSRF 这个漏洞我最早是在渗透测试报告里看到“服务器端请求伪造”这个词当时一脸懵觉得和我熟悉的 SQL 注入、XSS 完全不是一个画风。后来在 PortSwigger Academy 里把 Server-side request forgery 整个章节的系统性实验刷了一遍才真正明白它为什么被称为“内网摆渡车”——攻击者不直接打内网而是让服务器替自己把请求发进去。这篇东西就基于我在 PortSwigger Academy 的实操过程来写把原理、绕过思路、以及我在实验室里踩过的坑一次性说清楚。如果你是做 Web 安全、负责漏洞修复的研发或者准备安全面试SSRF 都是绕不开的一环。下面我会从原理讲到工具再拆解 PortSwigger 的典型实验思路最后补上我自己的排查经验。全篇没有废话你可以直接照着练。1. 先搞清楚 SSRF 到底在打什么SSRF 的本质一句话服务端发起的请求目标地址由攻击者控制。普通漏洞是攻击者往服务器“送”恶意数据而 SSRF 是攻击者诱导服务器主动“去访问”一个恶意指定的地址。这个特性决定了它有两个很特殊的攻击面。第一是内网探测服务器和你内网其他机器在同一个网段它能访问到 10.0.0.x、192.168.x.x 这些你直连不到的地址。第二是访问本机服务服务器上有大量服务监听在 127.0.0.1尤其是 redis、docker API、云厂商的元数据服务这些服务通常没有鉴权或鉴权很弱但只要不回暴露到公网就没人注意。而 SSRF 让攻击者借用服务器的视角把这两块“想都不敢想”的区域直接暴露出来。举个例子很多云服务器上有一个固定地址 169.254.169.254。我碰到过的情况是某网站的“图片缩略图”功能允许用户传一个图片 URL 让服务器去抓取。我直接把 URL 换成了http://169.254.169.254/latest/meta-data/服务器返回了它的云主机元数据。这里头有临时密钥、实例 ID配合后续其他漏洞就能横向。这就是 SSRF 最危险的场景——它不直接给你 shell但常常是内网沦陷的第一步。1.1 SSRF 攻击面不只“内网 IP”很多人觉得 SSRF 就是“把地址改成内网 IP”这个理解太窄。端口扫描、协议利用、云元数据、内网应用交互都是它的攻击面。我用一个表格把常见场景列出来方便你在测试时对号入座目标类型典型地址/协议能拿到的东西本机回环127.0.0.1、localhost未鉴权的管理服务、缓存服务、接口云元数据169.254.169.254临时凭证、用户数据、实例标签内网主机10.x.x.x、172.16.x.x、192.168.x.x内网端口、Web应用、数据库文件协议file:///etc/passwd服务器本地文件内容特殊协议gopher://、dict://与内网 TCP 服务交互甚至打 Redis这里要注意file 协议不算传统意义的“请求伪造”但它同样是 SSRF 的一种利用形态。有些防护只封了 http/https没封 file结果本地文件被读了个遍。我在后面会专门讲协议层面的绕过。1.2 判断一个功能是否可能存在 SSRF不是所有能传 URL 的功能都有 SSRF 风险但有几种典型场景你看到它们就该多留个心眼URL 转码、网页快照、分享卡片预览图片抓取/下载、头像/封面远程加载PDF 导出时渲染外部图片Webhook 配置、回调地址校验报表工具里填数据库连接地址核心判断标准是输入的值最终被当成“网络请求的目标地址”由服务器发起请求。如果这个过程中你能改方案、改协议、改 host就有戏。改不了就看它是否校验了协议或域名校验是否能绕过。提示很多 SSRF 集成在“URL 上传”类功能里但真正容易出问题的是那些只做了前端校验的后端接口。前端校验只是给用户看的后端必须有自己的校验逻辑否则就是白搭。2. PortSwigger Academy 的资源结构值得刷什么PortSwigger Academy 是 PortSwigger 官方出的免费安全学习平台其中 SSRF 章节有完整的理论讲解和配套实验。你不需要把整站刷完但 SSRF 这个 topic 绝对值得全刷。它把 SSRF 拆成了几个独立的实验从最简单的到带 WAF 绕过的难度梯度做得比大部分教学材料都好。它的实验分三种难度标签Apprentice、Practitioner、Expert。SSRF 系列里我建议至少要刷两个一个是基础的Basic SSRF against the local server另一个是SSRF with blacklist filters。前者让你理解漏洞本质后者让你理解真实世界中 WAF/过滤的存在感。我第一次刷的时候心态有点急总想跳过基础实验直接看复杂绕过结果发现完全不行。SSRF 的绕过手法是建立在对 HTTP 请求本身的深刻理解上的你不亲手抓一次请求、改一次 host、观察一次响应很难把后面的组合拳看懂。基础实验的意义不是教你复制粘贴而是建立“请求从哪里来、到哪里去”的直觉。2.1 这个平台的教学方式和传统教程有什么不同传统教程通常给你一段 Payload 让你打靶机打完就完了。PortSwigger 的做法不太一样每个实验都模拟一个具体业务场景比如“库存检查功能存在 SSRF”你得先找到那个功能点再判断输入点在哪里然后一步步构造请求拿到预期结果。这种“业务场景 自由探索”的方式考验的不只是 Payload 记忆而是你对漏洞触发的整个过程理解。比如基础实验里你拿到一个“检查库存”的接口你得先意识到它内部会去访问一个内部 API然后你再决定怎么替换地址。这种思路在真实渗透测试里恰恰是最值钱的能力。它还会记录你的实验进度和答题时间但我觉得这个不是重点。重点是它给每个实验写了很完整的解决方案刷完题之后可以对照官方解法复盘自己思路上的偏差。2.2 我的建议刷题顺序SSRF 在 PortSwigger 的目录下是一个独立主题但它的前置知识其实是 HTTP 基础、DNS、内网常识。所以我的建议顺序是先把 HTTP 基础HTTP Host header 那部分过一遍不然不太容易理解 URL 解析差异刷Basic SSRF against the local server建立最基础的直觉刷SSRF with blacklist filters和SSRF with whitelist filters理解两大类防护机制刷Blind SSRF with out-of-band detection理解盲测思路有余力再看SSRF with filter bypass via open redirect这类组合题这套顺序从“漏洞触发”到“防护绕过”再到“盲测发现”逻辑上是递进的。我见过不少人直接卡在 whitelist 那个实验上就是因为他们跳过了基础实验对 URL 的解析规则没有形成概念。3. 实操拆解从基础实验到绕过实验全记录下面我按自己实际操作过的流程来写不抄官方解法重点讲“你为什么想不到这一步”和“操作时容易忽略什么”。建议你边看边把 Burp Suite 打开光看不练真的记不住。3.1 基础实验直接魔法替换第一个实验的场景是一个商品库存查询功能。页面上有个“查看库存”按钮点击它会向/stock这个 API 发请求。我打开 Burp 的 HTTP History 一看请求长这样POST /product/stock HTTP/1.1 Host: 0a1b2c3d4e5f6g7h8i9j.web-security-academy.net stockApihttp%3A%2F%2F192.168.0.42%3A8080%2Fproduct%2Fstock%2Fcheck%3FproductId%3D1%26storeId%3D1关键在stockApi这个参数。服务器收到后会用这个参数里的地址再发起一次请求然后把结果拼到响应里返回。这个“服务器替用户发起二次请求”的结构就是典型的 SSRF 触发点。我把它改成stockApihttp://127.0.0.1:8080/admin响应直接返回了一个管理后台页面。再带上删除用户的参数就能完成管理员操作。这个实验的启发是很多 SSRF 就藏在看似人畜无害的“服务器内部跳转”功能中。用户填的 stockApi 表面上是“要访问的库存接口”实际上服务器完全信任这个值。我后来在真实测试中遇到很多类似的参数名不叫 stockApi但结构一模一样url、path、next、callback、target。3.2 黑名单过滤地址的“变着法儿写法”第二个实验加了黑名单直接写127.0.0.1会被拦admin这个词也被拦了。我一开始以为要写复杂脚本后来发现其实考的是“对 IP 地址表示方式的理解”。先解决 IP 被拦127.0.0.1可以写成十进制整数2130706433因为 HTTP 客户端解析 host 的时候IPv4 地址本身就可以用整数形式表达。像http://2130706433:8080/admin会被解析成访问 127.0.0.1。这个知识点在日常开发中基本不会用到但它恰恰是逃避字符串匹配的经典手法。再解决admin被拦把路径写成http://127.0.0.1:8080/administrator如果目标系统的管理后台路径恰好是/administrator就能绕过关键词过滤或者用 URL 编码%61dmin看后端是否先解码再校验。实验结果证明黑名单只做了最简单的前缀匹配换个写法就直接绕过了。这件事给我的教训是黑名单校验在 SSRF 面前几乎没有意义因为可表示同一个 IP 的方式太多了十六进制、八进制、整数、十进制混合写法只要规则稍有遗漏就能绕过。3.3 白名单校验玩的就是 URL 解析差异最让我有挫败感的是白名单实验。后端有个校验逻辑URL 的 host 必须是以某个合法域名结尾的比如stock.portswigger.net。直接用http://stock.portswigger.net127.0.0.1:8080/admin会被拦因为校验规则似乎能识别符号。然后我想到试用#把后面的内容变成锚点http://stock.portswigger.net#127.0.0.1/admin。一些后端在做 host 校验时取的是域名部分而最终的请求由 Java 的 URL 类发起解析结果完全不同。在这个组合里校验器认为目标是stock.portswigger.net但实际请求却去了127.0.0.1。这个实验让我意识到一个关键问题同一个 URL 字符串在不同语言、不同库里的解析结果可能完全不一样。后端校验时拿到的是“它认为的目标”发 http 请求时用的底层库又给出了另一个目标。这就是 URL 解析不一致带来的经典绕过。我用同样的思路还试过http://localhost:8080/#stock.portswigger.net之类的变形核心都是利用不同解析器对分段优先级的差异。这类漏洞修复起来也很麻烦黑名单能打补丁白名单如果只做“字符串包含校验”而没做“严格 Host 校验”形同虚设。真正的解决方案是解析两次取真正要建连的 host 做比对。3.4 盲测 SSRF看不到响应怎么办Blind SSRF with out-of-band detection这个实验没有回显你发一个请求服务器去访问一个内部地址但响应里完全不体现结果。这时候怎么判断“有没有被触发”思路是让目标是一个你能监控的地址。最简单的做法是用一个带 token 的 URL 作为外部请求目标。PortSwigger 实验里给了 Burp Collaborator它会生成一个子域名所有对这个子域名的 DNS 查询或 HTTP 请求都会被记录。我把 stockApi 改成http://自己生成的子域名然后回 Collaborator 一刷新看到 DNS 查询记录。这就证明服务器确实发出了这个请求SSRF 存在只是没有回显。这招在真实测试中非常重要因为大量 SSRF 都是无回显的。你没法从响应中看到 127.0.0.1 返回了什么但你能通过 DNS 交互来证明“服务器主动请求了外部地址”。我测试过不少目标最后拿到证据都是靠这种 out-of-band 方式。注意盲测时一定要带上唯一标识比如xxx.子域名。多个人同时测试或多次请求时这个标识能帮你精准定位是不是该请求触发的。我吃过这个亏有一次忘了带唯一标识看 Collaborator 里全是混杂记录根本没法判断。4. 现实中的 SSRF为什么比实验室更难刷完 PortSwigger 全部 SSRF 实验后我有种错觉SSRF 不过如此。直到在真实项目里碰了几个带防护的目标才发现实验室把“知识点”提炼好了但真实的业务逻辑会制造大量噪声。现实中的难点主要有三个。第一是入口隐藏并非所有可 SSRF 的接口都长一个url参数样有的参数经过了多层 JSON 嵌套有的夹在签名验签之后你不先把前面的认证逻辑打通根本摸不到。第二是协议限制实验里能直接用 http 协议现实里很多场景只允许 https或者干脆把字典协议层封了。第三是回显过滤服务器即使返回了内网响应内容也常常被前端截断或统一包装成 JSON你看到的响应和真实返回完全不同。我遇到过一个案例某系统的 “商品主图抓取” 功能带了开头的域名白名单。我直接改 URL 肯定被拦后来发现它允许跳转。我用一个自己控制的 URL 先返回 302Location 指到内网地址http://10.0.0.5:8080/admin结果服务端在跟着跳转时不再校验目标地址最终访问到了内网。这就是 PortSwigger 里open redirect那个实验的现实版。所以我的观点是实验室给你的是“招式”但真正决定你能不能挖到 SSRF 的是懂不懂业务逻辑。4.1 防护绕过的组合思路现实中遇到的防护很少是单一类型的更多是“黑名单 入站方向限制 协议白名单”混在一起的组合。我给你一个我常用的绕过排查顺序先看目标地址的校验逻辑是基于字符串还是基于解析后的 host如果字符串匹配试 IP 的各种写法十进制、十六进制、混合写法如果 host 校验试、#、、反斜杠、中文句号等 special 字符如果协议被限看是否能通过重定向、DNS 解析记录切换协议如果端口被限检查是否有可用的非标准端口服务如果完全盲测用 DNS 交互确认触发点这套顺序不是万能的但它能帮你系统性地排除干扰项。还有一个容易被忽略的思路对方可能只校验了出站请求的“第一跳”没校验后续跳转。open redirect 绕过的本质就是这个。我在真实测试中经常把目标放在自己控制的域名下返回各种 302/307利用服务端跟随跳转的特性绕过前置校验。4.2 修复 SSRF比发现它更考验功底作为安全开发者如果收到 SSRF 漏洞的修复任务我建议你不要只加一个黑名单。黑名单处理不了 IP 变形也管不了后续跳转。比较稳的方案有这几层严格校验协议只允许 http/https把 file、gopher、dict 这些协议全部禁用DNS 解析校验先解析域名确认解析到的 IP 不是内网地址再放行二次校验建立连接之前再解析一次目标地址防止 DNS Rebinding出站 ACL在服务器网络层限制只能访问特定网段或特定端口统一错误处理除非业务需要否则不向用户返回内网请求的原始响应其中 DNS Rebinding 是很容易被忽略的。攻击者可以注册一个域名第一次解析给你校验第二次解析返回内网 IP。如果服务端只校验一次就发请求就会绕过。应对方法是校验和连接各解析一次对比 IP 是否一致。在代码层面还有个心理关要过不要相信任何用户传来的 URL“看起来”合法。很多开发者看到自己公司域名就放心了但 URL 里的和#会迅速击碎这份信任。不管哪个语言拿到 URL 之后应该用标准解析库强制解析然后只取解析后的 host而不是直接拼接请求。5. 实操中常见问题与排查记录刷实验和真实测试过程中我攒了不少问题。这里挑几个最常出现的写出来希望能帮你少走弯路。5.1 “为什么我改了 URL 但响应没有变化”这是新手最常见的问题。改 URL 后响应和原来一模一样八成是你改的这个参数不是真正触发 SSRF 的那个。有次我盯着一堆参数改了半小时最后才发现真正触发的是请求体里的一个 JSON 嵌套字段不是我看到的 URL query 参数。排查建议用 Burp 看完整请求把所有参数列出来逐个测试替换成你自己的地址。也可以先改成一个外部 DNS 记录能观测的地址比如 Collaborator 平台用盲测来确认哪个参数真正被服务端当成了请求目标再看有没有回显。5.2 “127.0.0.1被拦了但内网 IP 可以用”这说明对方用了黑名单只过滤了本地回环地址。这种情况就把目标换成内网网段10.0.0.1、172.16.0.1、192.168.1.1逐个探测。如果端口也限制先扫几个常见端口80、8080、22、3306、6379。我在实验里试过127.0.0.1和localhost的过滤往往不完整。有些系统只拦127.0.0.1没拦LOCALHOST大小写变体或者2130706433整数形态有些拦了localhost但127.1这种简写形式能绕过。没事就把这些变体都拉出来跑一遍。5.3 “所有内网地址都被拦死了”如果对方校验了“目标 IP 必须是外网 IP”那直接用内网地址行不通。这时候可以考虑用你自己服务器做跳板先访问你的服务器再由它返回 302 跳转到内网地址用公开的重定向接口有些知名网站的跳转服务也能作为中转用 DNS 记录解析一个域名指向内网 IP前提是对服务端没做反向解析校验但注意这些都是实验意义上的绕过思路在真实测试中请确保有授权出站流量到达目标内网属于敏感操作。5.4 “能访问但读不到/etc/passwd”这种情况一般是协议限制了。有些后端只允许 http/https直接把file://替换成file:///etc/passwd没反应。你先看它返回什么错误如果是“协议不支持”说明协议白名单生效如果是“连接超时”说明地址解析被拦。更隐蔽的是某些代码会做 URL 解析后再取 host 拼接路径file://根本过不了解析。你要么找协议绕过点比如利用重定向到 file 协议但这种只在特定语言库下有效要么换一个思路既然出站 HTTP 能访问内网那就先扫内网 Web 服务别再纠结本地文件读取。5.5 “盲测时 Collaborator 收不到回显”先别怀疑工具被拦先自查三件事第一你替换的 URL 是否真的是触发点第二目标是否只发起 DNS 请求而不发起 HTTP 请求这也算回显只是类型不同第三是否有中间代理把出站流量过滤了。我用 Collaborator 的经验是多等一会儿很多内部网络有延迟DNS 记录到达慢。同时观察记录里的源 IP 和解析类型能帮你定位是目标服务器直接发出的还是经过了 CDN。6. 我的实操体会和扩展方向SSRF 是非常典型的“低门槛、高破坏力”漏洞。它不像堆溢出需要扎实的二进制功底只要能控制一个 URL 参数就够了但正因为入口好找它造成的破坏常常超出预期。我刷 PortSwigger 的 SSRF 实验时最有价值的不是背住 Payload而是培养了一种条件反射看到一个服务器会发起外部请求的功能我第一反应就是“这里能不能指向 127.0.0.1”。这个条件反射在后来看代码、做代码审计时帮了我大忙。有一次同事提交的代码里有个“获取远程图片”的工具类我扫了一眼 URL 拼接逻辑就知道没有做 host 校验——立刻让他加白名单和 DNS 解析校验。大部分 SSRF 漏洞不是多么高深的技术失误而是开发时少写了一个校验。如果你把 PortSwigger 的 SSRF 都刷完了还想继续深入我建议再看看 cloud metadata 攻击、容器环境下的 SSRF、以及和其他漏洞的组合利用SSRF 到 RCE 是很多真实攻击链的核心链路。另外强调一点云安全环境下STS 元数据接口几乎成了 SSRF 攻击的标准落地目标云服务商的元数据地址尽量从第一行代码就封死。我的经验就是多刷几遍 PortSwigger 的实验把每个绕过的底层原理真正搞懂别满足于“能过就行”。现在记住的每一条规则都是以后在真实项目里省下的几个小时。
阅读完成 · 觉得有帮助?