资讯动态

SSRF原理、绕过与防御:从入门到实战的完整指南

发布时间:2026/10/20 5:07:21 来源:尧图企业网站定制
“SSRF原理及绕过从零基础到精通收藏这篇就够了”一眼看这个标题就想起当年在某内部测试平台上抓到第一个SSRF时的场景——一个URL参数换了个IP写法就直接打通了内网。这个漏洞不像SQL注入那样“有名”但它一直是OWASP Top 10的常客原因很简单它让服务器替你发起请求等于把内网大门钥匙交到了攻击者手里。这篇文章我不打算讲太多玄乎的理论而是从原理到绕过、再到防御完整梳理一遍SSRF的来龙去脉给刚入门的新手一条清晰的学习路径也给已经在实战中的朋友一些可落地的参考。坦白说SSRF的门槛比RCE、反序列化低不少但它极度依赖“脑洞”。同样的一个URL参数不同的解析差异、不同的协议支持、不同的DNS解析方式都能组合出完全不同的绕过姿势。这也是为什么很多人学了SSRF却觉得自己“只会打一个点”因为缺少对漏洞本质的拆解。看完这篇你会明白那些绕过手法的底层逻辑而不是死记硬背payload。全文聚焦四件事SSRF的成因和攻击面、URL解析差异与各种绕过手法、内网探测和云环境下的进阶利用、以及服务端防御与排查方案。你可以把这篇当作一份工具手册遇到相关需求时直接翻到对应章节照着思路去测去补。1. SSRF原理与漏洞成因1.1 从一次请求看SSRF的本质SSRF服务端请求伪造英文全称Server-Side Request Forgery。中心词是“请求伪造”本质是服务端发起了攻击者可控的请求。这么说可能还是有点抽象用一个场景来理解假设某网站有个功能叫“远程图片抓取”你提交一个图片URL服务端用curl或file_get_contents去抓取这张图片并展示。正常逻辑下用户提交https://xxx.com/a.jpg服务器就去公网抓图片。但如果用户提交的是http://192.168.1.1/admin呢服务器同样会乖乖地替你去请求这个内网地址并把响应返回给你。这就是一个典型的SSRF。为什么说这个漏洞“可怕”因为服务器通常处于内网环境中它能访问到大量外部攻击者访问不到的敏感系统——内部管理后台、云服务器的元数据接口、数据库、Redis、Elasticsearch等等。攻击者虽然连不上内网但服务器能连上。SSRF的本质就是借助服务器打通内外网之间的壁垒。用个生活化的类比你被挡在公司大门外但快递员可以自由进出。你让快递员进公司帮你拍几张内部照片再带出来给你看——快递员就是服务器公司就是内网而SSRF就是那个“让快递员跑腿”的指令。1.2 SSRF产生的三类典型场景不是所有能发起请求的功能都会存在SSRF关键要看目标地址是否可控以及服务端是否做了足够的限制。从我接触过的实际案例来看SSRF最常见的温床有三类第一类URL参数直传型。这是最简单粗暴的方式代码里直接把用户传入的URL作为请求地址比如上面的“远程图片抓取”。这种场景下用户输入什么服务器就请求什么。常见于头像上传、URL预览、文章配图抓取等功能。确认方法也最简单——改URL参数为内网地址看响应内容是否出现内网系统的特征。第二类间接可控型。有些系统不直接接收完整URL但会接收域名、IP、端口等参数。比如某运维系统提供“Ping检测”功能你输入一个IP它就去Ping再比如某些数据同步工具要求填写“源数据库地址”。这些参数最终会被拼接到服务器发起的请求中间接形成SSRF。这类场景的绕过思路会更多样因为参数经过了拼接往往要考虑拼接后的URL结构。第三类文件处理与协议支持型。一些系统具备文件解析、图片处理、文档转换能力会主动去加载图片或文档中的外部资源。PDF生成器加载外部图片、Office文档解析器读取远程模板、图片处理库加载SVG中的外链资源都属于这一类。这类SSRF往往藏得更深因为用户输入的不是一个直接的URL而是通过文件内容间接触发。有的系统还会支持file://、gopher://等协议这会让漏洞危害进一步升级。1.3 为什么SSRF容易被人忽视SSRF不像SQL注入有极其明显的数据泄露特征也不像XSS能直接在浏览器里弹个框。它很多时候表现为“访问了一个内网地址但没有响应”或“响应异常”新手很难从这些表象里判断是否存在漏洞。加上现代应用普遍使用HTTPS、负载均衡、反向代理很多请求到了服务端已经不是最原始的URL形态排查起来更费劲。另一个容易被忽视的原因是很多开发者在写远程请求相关功能时并不知道这有风险。在他们看来服务器访问公网是“正常的互联网行为”根本没有意识到还需要限制访问目标。这也是SSRF在各类众测和实战项目中长盛不衰的原因之一——它是业务功能设计层面的疏漏单纯靠框架或WAF很难完全防住。2. 绕过手法拆解URL解析差异是关键2.1 前端过滤与后端解析的“认知差”几乎所有SSRF绕过手法的核心都围绕一个矛盾点前端校验/后端过滤的逻辑和最终HTTP客户端实际发起的请求两者之间对URL的解析结果不一致。只要能构造出一个“前端校验规则看不懂、后端请求库却能正常解析”的URL就成功绕过了限制。拿一个常见的PHP场景举例开发者的过滤逻辑是用parse_url解析用户输入的URL然后校验host是否为白名单域名。但是parse_url对某些畸形URL的解析结果和curl实际请求的目标可能完全不同。比如http://example.com192.168.1.1这个URLparse_url解析出的host是example.com但curl在发起请求时会把前面的部分当作用户名实际连接的主机是192.168.1.1。这样一来开发者用parse_url做了校验认为用户只能访问example.com但请求却打向了内网——完美的绕过。类似的“认知差”还有很多http://192.168.1.1#example.com#后面的部分在HTTP请求中不会被发送但某些正则却会匹配到example.com误以为目标是安全的http://192.168.1.1%2fexample.comURL编码后的斜杠可能被某些解析器忽略导致校验逻辑与实际请求脱节。绕过手法的本质就是不断寻找过滤规则与真实请求之间的缝隙。实操中判断一个过滤规则能不能绕关键在于把自己的思维切换到“解析器视角”过滤规则用什么解析器请求库用什么解析器两者之间在协议头、编码、特殊字符处理上有什么差异想清楚了这一点不需要死记payload也能在遇到新过滤规则时迅速找到突破口。2.2 IP地址变形与编码绕过这一类手法主要用于绕过目标IP的黑名单过滤。很多系统会限制用户只能访问公网IP或干脆把内网网段、保留地址段加入黑名单。但IP地址本身存在多种表示形式同一个IP用不同写法表达黑名单就形同虚设。十进制整数表示法192.168.1.1可以转换为十进制整数3232235777用Python的int计算192*256^3168*256^21*2561直接访问http://3232235777/部分HTTP库能正确解析并连接到192.168.1.1。这个方法对IPv4有效很多黑名单只拦截了标准点分十进制格式却忽略了整数形式。十六进制表示法192.168.1.1转换成十六进制是0xC0A80101访问http://0xC0A80101/同样可行。类似的还有八进制表示法0300.0250.01.01。这些变体本质上都是IP地址的合法表达形式但过滤规则如果不做归一化处理很容易漏掉。短域名与URL跳转通过一些短链接服务或自己的可控域名做302跳转——如果某个在线工具对URL有二次跳转支持先请求一个合法的短链接服务端跟随重定向到内网地址同样能达到目的。这个手法在真实环境中命中率很高因为服务端往往只校验了初始URL忽略了重定向后的目标。注意这里说的是一种通用绕过技术不涉及任何具体平台或工具。编码绕过也是同一类思路URL中的%2f、%23、%3f等编码字符在解析过程中可能被解码也可能不被解码取决于服务端语言和HTTP客户端的具体实现。比如http://192.168.1.1%2f%2fadmin某些解析器会把它还原为http://192.168.1.1//admin而校验规则可能因为看到%2f而判定路径不匹配结果请求照样发出去了。2.3 重定向与DNS层绕过重定向绕过的场景很常见系统只允许访问某个固定域名但这个域名可控或者系统会跟随重定向。攻击者在自己的服务器上部署一个302跳转初始请求是http://evil.com/redirect?targethttp://192.168.1.1但evil.com的响应是Location: http://192.168.1.1。服务端如果用了curl的默认跟随重定向配置就会直接访问内网地址。这种绕过不需要借助任何畸形URL纯粹利用业务逻辑中的合法重定向机制。DNS层绕过有两种常用思路。一种是DNS重绑定攻击者注册一个域名第一次解析返回公网IP通过校验第二次解析返回内网IP实际请求。条件是在校验和请求之间存在两次独立的DNS解析过程且服务端没有对DNS解析结果做缓存。理论上可行实战中能否成功取决于服务端是否把校验和请求分成了两次独立的解析很多语言默认会这样做。另一种是自定义DNS解析指向内网如果目标系统允许配置自定义DNS服务器或者攻击者能让某个域名的解析结果指向内网IP比如通过DNS服务商的解析记录将域名直接解析到127.0.0.1或10.0.0.1。这种方式比较隐蔽因为从字符串表面看用户提交的是一个“正常”的域名完全符合白名单规则但域名背后的解析结果是内网地址。2.4 协议层面的绕过与扩展利用很多SSRF漏洞能够从“访问内网”升级为“直接RCE”靠的就是服务端支持了不该支持的协议。当技术人员排查SSRF时第一步就是确认服务端使用的请求库支持哪些协议这一步直接决定了漏洞的上限。file://协议是最容易想到的。如果服务端支持该协议攻击者可以直接构造file:///etc/passwd读取服务器本地文件file:///proc/self/environ可能泄露环境变量file:///proc/self/cmdline能看到启动命令。这类读取在部分场景下是致命的因为很多应用的数据库密码、密钥等敏感信息就存在环境变量或配置文件中。gopher://协议则是“大杀器”。它允许攻击者构造一个原始的TCP数据流——可以理解为直接往目标端口发送任意字节。利用它访问内网Redis构造Redis命令写入webshell访问内网MySQL发送查询语句攻击内网Memcached等都曾在真实案例中出现过。不过gopher://能否使用完全取决于请求库是否支持。curl在较早版本中支持gopher协议某些语言内置的HTTP客户端也会间接支持。判断方式很简单直接构造一个gopher payload去请求内网端口看返回结果是否包含预期的协议响应特征。dict://协议也是一个容易被忽略的存在。它可以向指定主机的指定端口发送简单的命令并读取响应。相比gopherdict的利用范围受限但在某些场景下可以用于端口探测或服务指纹识别。还有ftp://协议虽然主要用于文件传输但可以用于探测内网FTP服务是否存在匿名访问某些请求库还会支持FTP的主动/被动模式切换由此引申出一些特殊的网络访问行为。3. 进阶利用内网探测与云环境攻击实操3.1 内网拓扑侦察的思路和手段当确认目标存在SSRF后第一件事不是急着打Redis或读文件而是摸清内网拓扑。内网探测的目标很简单确定127.0.0.1和当前内网网段内有哪些主机存活、哪些端口开放、跑着什么服务。端口扫描是SSRF最直接的应用。由于服务器能访问内网攻击者只需要不断提交http://目标IP:目标端口/的请求就能完成一次“服务器代理扫描”。判断端口是否开放有三种信号响应内容、响应时间差、错误信息差异。举个例子构造一个http://192.168.1.10:22/如果返回字符串包含SSH-2.0之类的特征说明22端口开放且是SSH服务如果返回连接超时或者“Connection refused”的错误提示说明端口关闭或主机不可达。有些过滤规则会屏蔽这类错误信息但响应时间差异仍然可以利用——开放端口通常响应快关闭端口或防火墙过滤的端口通常响应慢。网段存活探测可以用ICMP协议如果服务端支持或尝试访问常见端口如80、443、22、3389。还可以利用服务端发起请求的报错信息判断主机是否存在访问一个不存在的IP可能立即返回“host unreachable”而访问存在的IP则表现为“拒绝连接”或“超时”这就能区分出主机存活状态。这类探测需要耐心不建议单线程跑大量请求一方面容易被安全设备发现另一方面会给目标服务带来不必要的压力。3.2 云元数据接口攻击凡是部署在公有云上的目标SSRF的优先级利用一定是云元数据接口。以某主机服务商的元数据服务为例其地址通常为http://169.254.169.254/。这个地址对公网用户不可见但云内所有主机都能访问。攻击者一旦确认目标在云上直接通过SSRF访问该地址就能获取云主机绑定的角色凭证、临时密钥、实例ID、内部IP、安全组信息等敏感数据。拿到临时密钥后可以进一步调用云API实现云主机管理、对象存储数据读取甚至横向移动到更多云资源。不同云厂商的元数据路径略有差异但整体思路一致。/latest/meta-data/通常返回实例基本元数据/latest/meta-data/iam/security-credentials/是获取临时凭据的常见路径部分云服务还支持用户数据接口/latest/user-data/里面可能包含初始化脚本配置偶尔会泄露敏感信息。实操中如果一个SSRF可以访问该地址且返回JSON格式数据就意味着已经拿到了一台云主机的部分权限。这是SSRF利用中收益最高、也最常见的路径之一因为云上应用部署占比太高了。确认云厂商和元数据接口路径后一般还会尝试读取/latest/meta-data/placement/availability-zone获取可用区信息读取/latest/meta-data/local-ipv4获取内网IP。这些信息在做后续内网横向时非常有用。3.3 内网服务攻击与Gopher实际应用内网里最容易通过SSRF打出RCE的服务排在前两位的是Redis和未授权访问的数据库。这类服务通常监听了内网端口没有做访问控制只要谁能访问到就能直接操作。以Redis为例如果内网里有一台Redis服务监听了6379端口且没有配置密码攻击者利用gopher协议可以向它发送任意Redis命令。经典的利用链是用CONFIG SET dir和CONFIG SET dbfilename把Redis的持久化文件写到Web目录再写入一句话后门或者写入/root/.ssh/authorized_keys实现SSH登录。gopher协议在这种场景下发挥的作用就是把原本需要TCP客户端交互的过程变成一段预构造好的数据流一步到位。构造gopher payload的步骤相对固定先获取目标服务使用的协议格式比如Redis的RESP协议将命令序列化为目标服务能识别的数据格式再进行URL编码最后拼接成完整的gopher URL。这里的编码过程极其容易出错稍有不慎就会导致数据流中断。我的实操经验是先在本地搭一个同样服务做测试确认payload可以完整执行后再放到目标环境上尝试。不要直接在目标上调试gopher payload。数据库场景类似内网MySQL如果没有做来源限制SSRF配合gopher://可以发送完整的MySQL握手包和SQL查询语句。当然由于MySQL协议涉及加密认证利用难度比Redis高不少但当存在未授权访问或弱口令时这条路是行得通的。具体实现细节需要根据目标版本调整这里不展开但思路是通用的。3.4 从SSRF到内网横向的完整路径一个完整的SSRF攻击链通常分五步确认漏洞存在、内网探测、特权接口访问或服务攻击、获取内网凭证、横向扩展。每一步都建立在前一步的信息基础上而不是一次性打穿。举一个模拟项目X的例子帮助理解某目标的“PDF导出”功能存在SSRF攻击者先用file://协议读取了服务器上的配置文件得到数据库连接信息再通过访问元数据接口拿到临时云密钥然后用密钥调用云API列出了该账号下的所有ECS实例和对象存储桶发现某个存储桶开放了公读最终通过存储桶内的备份文件获取了更多系统的账号密码完成了横向渗透。整个链条中SSRF只是入口但它打开了通往内网的通道后续攻击面会指数级扩大。这就是为什么我说SSRF的利用上限极高——它往往不是漏洞链的终点而是一把打开内网大门的钥匙。评估一个SSRF的严重程度不能只看它能否读取本地文件而要顺着链路往下想目标能不能访问到云元数据内网有哪些高危服务本地文件里有没有敏感凭证想得越远漏洞价值评估越准确。4. 服务端防御与漏洞修复方案4.1 黑名单过滤为什么不可靠不少开发者在意识到SSRF风险后第一反应是“加个黑名单把内网IP封掉”。这种做法有一定效果但远远不够原因在前面已经说了一部分IP地址有进制转换、有URL编码、有DNS重绑定、还有重定向黑名单很难把这些变体全部覆盖。更致命的是内网网段不只是192.168.0.0/16和10.0.0.0/8还有127.0.0.0/8、169.254.0.0/16、100.64.0.0/10运营商级NAT保留段、0.0.0.0/8等一堆特殊地址漏掉任何一个都可能被绕过。举个例子http://0x7f000001/就是127.0.0.1的十六进制写法一个只拦截127.0.0.1的黑名单对这个地址完全无感。类似的还有http://2130706433/这种纯十进制整数形式同一个IP换一种表达方式就能绕过。黑名单方案需要开发者穷举所有可能的表达形式这在工程上几乎不可能做到。另一个问题是黑名单只关注了“目标地址”却遗漏了“协议”。即使限制了IP段如果服务端请求库支持file://或gopher://攻击者依然可以利用协议攻击本地文件或内网其他端口。防御SSRF必须从多个维度同时下手单一手段防不住组合拳。4.2 白名单与协议限制的正确姿势白名单比黑名单可靠得多但实现白名单要注意一个问题目标是域名还是IP如果业务上只能访问固定的外部域名直接校验域名白名单即可如果业务需要访问任意公网网站比如URL预览功能则必须采用更复杂的策略。我的建议是分层防御第一层IP白名单把请求目标限定在明确允许的IP或网段。如果业务必须访问任意公网域名就先解析出目标域名对应的所有IP然后只允许公网IP排除保留地址和私有地址段。解决DNS重绑定问题的方法是校验IP和请求保持一致——解析一次IP后直接用该IP发起请求并把请求的Host头设置为原始域名。让“解析”和“请求”使用同一次DNS结果不要做两次独立解析。第二层协议白名单限定请求库只允许HTTP和HTTPS协议关闭file://、gopher://、dict://、ftp://等协议的支持。curl环境下的实现方式是使用CURLOPT_PROTOCOLS设置允许的协议集合。顺手说明一下还有CURLOPT_FOLLOWLOCATION这个选项——如果要跟随重定向必须设置CURLOPT_REDIR_PROTOCOLS限制重定向时允许使用的协议不然非HTTP协议可以通过重定向绕过限制。第三层端口白名单大多数业务只需要访问80和443端口或少数自定义端口。在代码层面对目标端口做强校验可以阻止SSRF用于内网端口扫描。这层简单但容易被忽略很多SSRF就是从灵活的端口控制开始被利用的。4.3 一套可落地的安全请求代码模板以下是一个PHP环境下的安全请求函数模板采用了上面提到的分层防御策略。这段代码不是为了展示标准库用法而是为了说明“每一层防御在代码层面长什么样”。?php function safeRequest($url, $allowedHosts []) { // 1. 协议校验只允许 http 和 https $scheme parse_url($url, PHP_URL_SCHEME); if (!in_array(strtolower($scheme), [http, https])) { throw new Exception(Disallowed protocol: . $scheme); } // 2. 主机名校验如果是白名单模式 $host parse_url($url, PHP_URL_HOST); if (!empty($allowedHosts) !in_array($host, $allowedHosts)) { throw new Exception(Disallowed host: . $host); } // 3. 解析IP并校验是否为内网地址 $ips gethostbynamel($host); if ($ips false) { throw new Exception(Unable to resolve host: . $host); } foreach ($ips as $ip) { if (isPrivateIp($ip)) { throw new Exception(Private IP detected: . $ip); } } // 4. 发起请求使用解析到的第一个IP并设置Host头 $ip $ips[0]; $requestUrl $scheme . :// . $ip . parse_url($url, PHP_URL_PATH); $ch curl_init($requestUrl); curl_setopt($ch, CURLOPT_HOST, $host); // 关键Host头手动指定 curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS); curl_setopt($ch, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0); // 谨慎跟随重定向 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_TIMEOUT, 5); $result curl_exec($ch); curl_close($ch); return $result; } function isPrivateIp($ip) { $ip ip2long($ip); $privateRanges [ [127.0.0.0, 127.255.255.255], [10.0.0.0, 10.255.255.255], [172.16.0.0, 172.31.255.255], [192.168.0.0, 192.168.255.255], [169.254.0.0, 169.254.255.255], [0.0.0.0, 0.255.255.255], ]; foreach ($privateRanges as list($start, $end)) { if ($ip ip2long($start) $ip ip2long($end)) { return true; } } return false; }这里有一个容易踩坑的细节代码第4步先用解析出的IP构造请求URL再通过CURLOPT_HOST强制设置Host头。这样做的目的是确保“校验过的IP”和“实际连接的IP”是同一个IP避免校验和请求分离导致DNS重绑定绕过。如果你直接把原始域名传给curlcurl内部会再次解析DNS两次解析结果可能不同攻击者就有机可乘。这个细节在真实对抗中非常重要。另外注意CURLOPT_FOLLOWLOCATION默认是0也就是不自动跟随重定向。很多业务确实需要重定向能力但除非确认目标域名的重定向目标是可信的否则不建议启用。如果确实需要跟随重定向可以用libcurl的重定向回调函数在每次跳转前校验目标URL发现非法协议或内网地址就终止请求。4.4 网络层与云环境加固代码层面的防御解决了“应用自身直接被利用”的问题但SSRF最大的威胁往往来自内网其他服务缺乏访问控制。即使应用程序防御做得再好如果内网Redis、数据库、消息队列等服务完全没有网络访问限制攻击者一旦找到其他入口进入内网一样能横向滑动。网络层加固的思路是“纵深防御”。内网服务最小化暴露所有数据库、Redis、消息中间件等服务必须绑定内网IP或Unix Socket绝不能监听0.0.0.0。如果业务不需要跨主机访问直接绑定localhost即可。安全组和防火墙策略按“默认拒绝、最小授权”原则配置只放通明确需要的端口和来源。云环境安全组配合云平台的访问控制列表同样要遵循最小授权原则不同业务模块之间通常不需要互相访问的就不放通。SSRF攻击者即使通过SSRF拿到了某个云主机如果安全组限制了出方向流量横向移动就会受阻。当初很多云上的SSRF案例之所以能造成巨大损失就是因为内网全互通后端的各种服务都暴露在同一个内网平面中。DNS解析管控在企业内网DNS层面可以部署策略拦截对169.254.169.254等元数据地址的解析请求和访问请求。某些云平台也提供“元数据服务强制访问控制”的选项开启后只有特定角色能访问元数据接口这是一个有效的缓解措施。在应用层依赖库和框架层面也可以拦截敏感地址。日志与监控开启服务端请求日志对目标地址中出现保留IP段、异常端口、未知协议的请求进行告警。SSRF攻击是一种相对“结构化”的行为很容易表现出扫描特征——大量不同IP/端口、相同来源地址的请求模式一旦出现应当触发告警。掌握这些告警信息至少可以知道攻击者已经盯上了服务器来得及在真正造成破坏前及时处置。5. 常见问题与排查技巧实录5.1 高频问题速查表以下是我在测试和修复SSRF过程中遇到的几个典型问题以及对应的排查思路整理成表格方便查阅问题现象可能原因排查与处理方向提交内网地址后返回空白服务端禁止访问私有IP或请求超时尝试IP变形、域名指向内网确认服务端请求库的协议支持范围内网端口能扫到但无法获取响应内容服务端只返回状态码不返回响应体利用响应时间、错误页差异做端口判断尝试构造能让服务端把错误信息回显的请求gopher协议payload不生效URL编码错误或协议格式不匹配本地复现服务调试payload使用专门的gopher编码工具生成数据流检查请求库是否真正支持gopher白名单域名可访问但重定向后跳到内网服务端跟随重定向但未限制重定向目标在本地用可控域名构造302跳转验证修复时限制重定向协议和目标访问云元数据接口失败目标不在云上或云厂商路径不同尝试多个已知元数据路径检查请求是否被云安全组件拦截同一payload在本机测试成功目标上失败目标环境请求库版本、配置不同不要认为SSRF是标准漏洞不同环境的行为差异很大按目标环境单独排查parse_url校验通过但请求失败PHP parse_url与curl对URL解析不一致多做几组对比测试确认校验逻辑使用了解析方式优先使用白名单IP校验而不是依赖过滤规则5.2 确认SSRF存在与否的实践技巧很多新手拿到一个目标后不确定是否存在SSRF或者不敢确定“这个功能是否能发起服务端请求”。这里分享几个我常用的确认思路判断功能是否发起了服务器请求。最简单的方法是在自己的可控服务器上监听一个端口提交目标URL指向该地址看是否有请求打过来。如果能收到请求说明服务端确实替用户发起了网络请求SSRF的“请求”条件成立。这一步用的方法和API请求调试类似只是站在服务端视角去验证。判断是否可控URL参数。如果服务端收到请求后发现目标URL来自用户输入那么“可控”条件也成立。两者同时满足就具备SSRF探测价值。如果提交的公网地址被拦截可以尝试各种绕过手法观察是否出现放行的情况。利用响应差异做判断。访问一个存在服务的地址和不存在服务的地址返回内容或响应时间通常有差异。通过控制变量不断改变目标的IP和端口记录响应差异可以比较准确地绘制出内网开放端口图。需要注意如果服务端对错误做了统一的模糊处理这个方法会失效但要继续利用“时间差”开放端口的TCP连接通常比拒绝连接耗时更长。5.3 容易被忽略的检测盲区与防御验证在防御侧排查时最容易出现三类盲区业务逻辑盲区。很多开发者只校验了“入口URL”没考虑文件内容中嵌入的外部资源加载。最典型的场景是图片上传用户上传的图片可能是SVG格式SVG里可以嵌入image标签指向外部地址图片处理库解析SVG时会自动请求该地址。防御时需要明确“所有会发起网络请求的点”包括文件解析、文档转换、消息通知、日志上报等逐一排查只防一个入口是不行的。协议代理盲区。有些系统本身是内网代理或跳板机的角色接收外部请求后转发到内部服务。这种系统天然存在SSRF风险因为它的业务功能就是“代理请求”。防御这类系统时不能简单封禁内网地址否则业务就崩了需要结合认证、权限、来源IP、操作审计等多重手段进行限制。DNS解析盲区。有些系统使用了类似HttpURLConnection的组件它默认会跟随重定向且重定向时可能解析新的DNS。如果安全团队只校验了第一次请求的URL没有对重定向后的URL做校验漏洞依然存在。验证方法就是构造一个302跳转到内网地址的测试域名看看请求是否最终打到了内网。我见过不少团队在修复SSRF时只做了IP黑名单上线后很快就被绕过原因就是没有做完整的“威胁建模”。建议在修复前先画一条“用户输入 → 服务端解析 → 发起请求 → 获取响应 → 返回给用户”的完整链路图把每一个环节中可能被利用的点列出来再逐个封堵效果会好很多。5.4 一个实用的测试与验证流程最后给一套我平时用于检测SSRF存在与否的标准化流程也可以作为防御方做安全自查的清单收集所有可能发起外部请求的功能点URL预览、图片抓取、Webhook、PDF生成、文件导入、API代理等。针对每个功能点提交一个可控域名指向的地址确认服务端是否会发起请求。如果确认会发起请求测试协议支持范围分别提交http://、https://、file:///etc/passwd、gopher://测试地址观察响应差异。测试内网访问能力提交http://127.0.0.1:22/、http://192.168.1.1:80/等地址确认是否存在内网过滤。测试绕过能力依次尝试IP整数表示、十六进制、URL编码、符号、#截断、短域名重定向、DNS重绑定等手段评估过滤规则的强度。记录所有响应差异和错误信息形成测试证据模板。这套流程不依赖特定工具纯手动也能完成。自动化扫描器可以作为辅助但SSRF的绕过极具“场景差异性”很多绕过手法只有在人工结合业务逻辑和代码特征时才能发现。扫描器跑不出结果的地方人工往往能发现惊喜。写在最后的个人体会往细了说SSRF的核心攻击思路就一句话想办法让服务器替你去访问它不该访问的地方。所有绕过手法、编码技巧、协议利用本质上都是在“过滤规则”和“真实请求”之间寻找缝隙。这个缝隙有时候来自业务功能本身的逻辑漏洞有时候来自不同组件解析差异有时候来自开发者认知上的盲区。找到缝隙的过程确实有点像解谜但正因为如此它也给了防御者一个非常重要的启示永远不要假定黑名单能覆盖所有情况不要假定请求库的行为和你想的一样。我个人在实际排查中的经验是SSRF的防守远比进攻更考验对系统架构的理解。攻击者只需要找到一个可利用的功能点而防御者必须覆盖到所有发起网络请求的路径。建议做安全测试时把“谁可以发起网络请求”这个问题当成排查核心顺着代码把每个发起点都摸一遍比单纯追着漏洞类型找要高效得多。如果你刚开始学SSRF找一个模拟靶场环境做练习会比自己搭环境高效很多因为靶场内置了多种不同的过滤规则和协议支持场景可以系统地体会各种绕过的触发条件。等你把常见的绕过手法都跑通了再回到真实业务上做测试思路会清晰很多。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑