尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
SSRF漏洞原理与实战:从内网探测到云元数据获取
SSRF这个名词我第一次真正“吃透”不是因为看文档而是在一次模拟演练里被它摆了一道。当时某内部系统的图片预览功能可以传入任意URL服务端会自动把那个地址的内容拉取下来渲染成缩略图。我抱着试试看的心态把URL换成一个内网地址结果响应里直接出现了内网管理后台的标题。那一刻我才明白这个漏洞跟普通的注入、XSS不是一个套路——攻击者不直接打前端而是借服务器的手去访问自己够不着的内网。如果你刚接触Web安全或者已经在看漏洞原理但总觉得“纸上谈兵”这篇文章适合你。我会从SSRF的原理讲起把能干什么、为什么危险讲透然后带你在本地搭一套简易靶场一步一步复现内网探测、读文件、读云元数据这些利用手法最后再聊防御和踩坑。整个过程不依赖任何线上靶场平台全部在自己电脑上完成放心跟着操作就行。1. 先搞懂SSRF是个什么东西1.1 大白话解释服务端请求伪造SSRF全称是Server-Side Request Forgery中文叫服务端请求伪造。理解它之前先想一个正常流程你在一个网页里提交URL服务器拿着你给的地址去请求内容然后再把内容返回给你。比如很多站点提供的“链接预览”、“远程图片抓取”、“网页快照”功能核心逻辑都是这样。问题出在服务器拿到你给的URL后它是以服务器的身份去发请求的而不是你浏览器直接发。如果代码没有校验URL指向哪里那你就等于握着服务器的“手”让它按你的指挥去访问任意地址。访问127.0.0.1是它自己访问192.168.x.x是内网访问file协议是读文件访问特殊云元数据地址可能把云环境的密钥都吐出来。我打个比方服务器是一辆高级车的司机你坐在后排司机本来只负责把你送到指定的地方。结果你发现只要报地址司机就真去——哪怕那个地址是禁区、是别人的车库他也照开。SSRF就是抓住了这个“指哪打哪”的信任。它本质上不是服务器漏洞而是业务逻辑里“用户输入URL”这个功能设计得不够严谨。1.2 为什么服务端会变成“中转站”很多初学者会问我自己浏览器也能访问这个URL为什么非要通过服务器关键在于网络位置不同。你的电脑在外网服务器既在外网也在内网。它有一张内网网卡能访问数据库、管理后台、Redis、对象存储等一堆内网服务。你人在外网碰不到这些但服务器可以。只要服务器帮你发请求你就获得了“服务器视角”的网络访问能力。这个能力有多可怕假设内网有个管理后台监听在192.168.1.10:8080没有任何认证防护管理员以为外网访问不到就安全了。结果SSRF一条请求打过去后台页面原样返回给你等于把内网服务直接“搬运”到了外网。更进一步的姿势还包括用SSRF做端口扫描探测内网存活主机和开放端口用file协议读取服务器本地敏感文件用gopher、dict等协议构造特殊数据包直接攻击内网服务读取云环境上的元数据信息拿到临时密钥一个看起来人畜无害的URL预览功能一旦参数可控且没校验就变成了攻击者通往内网的门。1.3 SSRF最爱藏身的地方结合我平时做代码审计的经验下面这些功能点出SSRF的概率非常高如果你在开发或测试建议重点瞄一眼图片加载/缩略图传入图片URL服务端去拉取常见的头像上传、外链图片预览URL分享/链接预览像聊天工具里发个链接能显示标题和摘要那种Webhook配置用户填写回调地址服务端向该地址推送通知PDF生成很多PDF生成组件支持传URL服务端加载后转成PDF这种还能顺带读文件文档/网页快照搜索引擎爬虫、快照服务远程文件包含、导入比如导入CSV、导入邮件的功能看到这类功能第一反应就该是SSRF。判断一个请求是不是SSRF核心就一句话URL是否来自用户输入请求是否由服务器发出。2. SSRF到底能干多大事2.1 内网端口扫描与存活探测SSRF第一个实用价值就是把“能不能访问”这个信息变成你的情报来源。在没有SSRF之前你扫内网得先打进内网才行。有了SSRF你直接在公网输入目标内网IP和端口就能判断远端服务是否存在。原理也很简单你让服务器去请求http://192.168.1.10:3306如果服务存在响应可能是数据库协议特征如果不存在通常报连接拒绝或超时。你让服务器去请求不存在的IP时响应时间明显更久。这就形成了类似端口扫描的效果。但在实战里纯靠页面响应判断会受不少干扰。有的应用会把返回内容截断有的统一抛异常页面。这时候可以观察响应时间、状态码、返回内容的差异慢慢积累一条判断规则。我一开始做的时候习惯先对回环地址127.0.0.1的常见端口挨个试一遍再扩展到内网网段。2.2 读取本地文件如果服务端没有限制可用协议那么内含file协议就能直接读服务器上的文件。请求file:///etc/passwd正常Linux环境下一份账号信息就到手了。这东西为什么危险因为它等于把服务器文件系统暴露给你。翻配置文件可能翻到数据库密码、密钥、代码逻辑进一步扩大战果。真实世界里很多语言的内建函数支持多种协议比如Python的urllib就能直接处理file协议。但也有人会用requests库这个库默认只支持http/https遇到file协议会直接报错。所以同样叫SSRF不同语言不同库利用方式和难度差距很大。2.3 读取云元数据这是云环境下SSRF最著名的利用场景。公有云厂商在虚拟机里通常会提供一个特殊地址访问它能拿到这台机器的元数据主机名、网卡信息、标签甚至临时安全凭证。地址格式形如169.254.169.254。拿到临时凭证后攻击者可以直接调用云API读取存储桶、创建新实例影响范围从单台机器扩大到整个账户。我在自己测试环境里复现时通常用一个本地服务模拟元数据接口路径和真实云环境保持一致目的就是让这个“拿到凭证”的过程可视化。初学者做靶场自己模拟一个元数据服务放在内网再用SSRF去读就能把整个链路跑通。2.4 向内网服务二次打击上面说的都是直接请求、直接拿回结果。还有一种进阶玩法用SSRF作为跳板向内网服务发起特定协议的请求。比如Redis、Memcached这类服务它们走的是TCP协议通过HTTP协议没法直接构造命令。但如果你用的语言支持dict、gopher这类特殊协议就能往目标TCP端口写入自定义数据包。典型操作是请求dict://内网Redis:6379/执行命令或者用gopher构造一条完整的写入命令往Redis里写SSH公钥、写计划任务最终拿下那台内网机器。这一步需要比较深的内网协议知识入门先不急知道这个方向存在就行。3. 自己搭一套SSRF靶场3.1 靶场设计思路我们自己搭靶场目标很简单模拟一个具有URL抓取功能的Web应用同时在内网塞入几个“只允许内网访问”的敏感服务。整个环境都跑在本地不需要真实云资源。我用Python的Flask写应用用两个服务模拟内网目标整体结构是外网Web应用绑定8000端口对外提供/fetch接口存在SSRF内网业务后台绑定127.0.0.1:8080只能从本机访问内网元数据服务绑定127.0.0.2:80模拟云上的元数据接口为什么这样设计因为贴近真实。外网只能访问80008080虽然开了但绑在回环地址上外部网段根本无法直接访问。而/fetch接口发出的请求来自本机所以能“够到”8080。这就是SSRF利用的关键——借助应用本身的网络位置访问内网。3.2 靶场代码实现先装依赖当然得有Python环境。然后写一个文件比如叫vuln_app.pyfrom flask import Flask, request import urllib.request app Flask(__name__) app.route(/fetch) def fetch(): url request.args.get(url, ) if not url: return url参数为空 try: resp urllib.request.urlopen(url, timeout5) data resp.read() return data[:1000].decode(utf-8, errorsignore) except Exception as e: return f请求出错: {e} if __name__ __main__: app.run(host0.0.0.0, port8000)注意这里用的是urllib.request.urlopen而不是requests库。原因刚才提过urllib原生支持file协议和HTTP重定向方便我们后续演示不同利用方式。实际业务代码里这么写也一点都不罕见。再写内网服务文件叫internal_app.pyfrom flask import Flask app Flask(__name__) app.route(/) def index(): return 内网管理后台首页这里只有本机能访问 app.route(/flag) def flag(): return FLAG{internal-only-data} if __name__ __main__: app.run(host127.0.0.1, port8080)再写一个模拟云元数据的服务叫metadata_app.pyfrom flask import Flask app Flask(__name__) app.route(/latest/meta-data/) def metadata(): return instance-id: i-xxxxxxxx\nsecurity-credentials: fake-secret app.route(/latest/meta-data/credentials) def credentials(): return FakeCloudAccessKey: AKID-fake-123456 if __name__ __main__: app.run(host127.0.0.2, port80)这里绑定127.0.0.2是一个环回地址不需要额外授权相当于本机的另一个虚拟网卡。真实云环境里的169.254.169.254也是链路本地地址你用127.0.0.2模拟同一层意思。如果你的系统绑定127.0.0.2有困难也可以改成127.0.0.1配合不同端口原理一样不耽误演示。3.3 启动靶场并验证连通性三个服务分别启动终端分别运行python internal_app.py python metadata_app.py python vuln_app.py先做一次正常访问验证打开http://127.0.0.1:8000/fetch?urlhttp://example.com大概率能看到example.com返回的HTML片段。这个步骤的意义在于确认外网应用本身工作正常。你再用浏览器直接访问http://127.0.0.1:8080/flag应该能打开因为你自己就在本机说明内网服务是通的。接下来重点来了如果你从外部视角想访问127.0.0.1:8080正常情况下行不通比如你在另一台电脑或者用容器隔离环境访问根本连不上。而通过SSRF就不一样了。4. 靶场实战从探测到利用4.1 第一步探测本机回环地址端口在最简单的情况下直接构造请求curl http://127.0.0.1:8000/fetch?urlhttp://127.0.0.1:8080/flag如果一切正常返回结果就是FLAG{internal-only-data}。你看一行请求内网页面就通过外网应用转发到了你面前。如果返回的是“请求出错: [Errno 111] Connection refused”说明该端口没有服务。通过这种差异就能摸出本机哪些端口开了服务。拿127.0.0.1尝试几个常见端口比如22、80、3306、6379依次看响应差别。这一步相当于告诉你SSRF下确实可以做端口探测并且反馈信息不隐藏。4.2 第二步读取服务器本地文件继续利用urllib的协议支持把URL改成file协议curl http://127.0.0.1:8000/fetch?urlfile:///etc/passwd返回的内容里会出现系统账号列表。如果应用跑在Linux容器里读到的就是容器内的/etc/passwd。你再想想如果读到应用配置文件、密钥文件呢原理都一样只是路径不同。我个人测试时经常读的是应用本身的代码文件比如vuln_app.py。因为找到业务代码后能更好地分析它调用了哪些接口、连接了什么数据库相当于拿到了内部地图。4.3 第三步探测内网其他主机实战里不可能只有本机内网往往还有192.168.x.x或10.x.x.x网段。在靶场里操作你可以先用ifconfig查看自己内网IP段然后让SSRF去探测同一网段的其它机器。curl http://127.0.0.1:8000/fetch?urlhttp://192.168.1.1/返回超时多半是目标不可达返回内容则是目标服务响应内容。这里有个经验如果目标IP不存在连接很可能直接拒绝速度很快如果存在但端口关闭同样拒绝如果存在且开了端口就会有一段时间的握手和响应。多试几个IP和端口你就能画出一张简单内网拓扑。这一步不需要任何扫描器全靠手搓URL。4.4 第四步读取模拟云元数据这是最有成就感的一步。请求模拟元数据服务curl http://127.0.0.1:8000/fetch?urlhttp://127.0.0.2/latest/meta-data/返回里出现instance-id、security-credentials等模拟字段。如果把地址换成/latest/meta-data/credentials就能看到模拟的AKID密钥。真实环境里这一步拿到的就是云厂商的临时凭证利用价值极大。实战完整链路结束后你回头看整个过程从外网发起一个看似普通的URL请求最终拿到了内网文件、探测到内网服务、获取云凭证。SSRF的危害不是单一目标而是给攻击者开了一扇通往内网的任意门。5. 白名单也拦不住常见的绕过思路5.1 URL解析差异符号和编码很多开发者知道要防SSRF于是在代码里校验url的域名是否在允许列表里。但校验本身也可能有漏洞。URL里藏着个历史遗留语法http://userinfohost/path前面的部分表示用户信息真正的主机是后面的host。有些校验代码用字符串匹配看到url里带了允许的域名就放行结果请求却发向了后面的地址。举个例子假设校验规则是“域名必须包含trusted.com”那么请求http://trusted.com127.0.0.1:8080/flag就可能绕过。解析器认为host是127.0.0.1而字符串里确实包含trusted.com。类似思路还有把IP写成分段形式、十进制、十六进制比如127.0.0.1写成2130706433如果校验代码简单判断“不是IP格式就不拦”这种就溜过去了。5.2 利用重定向如果应用在请求目标时会跟随重定向那白名单就可以被“跳”掉。攻击流程是在可控的公网域名上放一个302响应Location指向内网地址。应用先请求公网域名校验发现是白名单内的放行服务端跟随重定向又请求了内网地址校验已经结束自然拦不住。实践里我用本地起一个极简重定向服务来演示from flask import Flask, redirect app Flask(__name__) app.route(/redirect) def red(): return redirect(http://127.0.0.1:8080/flag) if __name__ __main__: app.run(host0.0.0.0, port8888)然后构造请求http://127.0.0.1:8000/fetch?urlhttp://127.0.0.1:8888/redirect。如果应用跟随重定向就会拿到内网后台的flag。这个测试点提醒大家校验URL时不仅要校验初始地址还要考虑重定向后地址。5.3 IPv6、DNS重绑定和协议扩展IPv6是绕IP黑名单的好工具因为很多校验代码只看了IPv4。例如http://[::ffff:127.0.0.1]:8080/flag这种写法把IPv4映射成IPv6地址校验时如果没处理IPv6就可能被绕过。DNS重绑定则更隐蔽第一次DNS解析返回公网IP通过校验第二次解析返回内网IP请求就发起到了内网。防御方很难用一个静态IP列表彻底拦住。这也是为什么有些厂商要做“两次解析结果必须一致”的强校验。协议扩展也好理解。前面的例子都用http协议如果应用没限制协议改成dict、gopher还能做更多事情。虽然这会增加利用复杂度但它意味着“防御只校验URL前缀是否http”是不够的攻击者可以换协议。6. 防御视角别再写出下一个SSRF6.1 代码层白名单优先黑名单不可靠说到防御我的第一原则是能用白名单就不用黑名单。黑名单需要枚举所有内网段、保留地址、特殊协议攻击者总能找到你漏掉的一个角度。白名单把访问范围严格限定在需要的域名/IP列表里天然挡掉大部分问题。演示里的校验代码可以这样写from urllib.parse import urlparse ALLOWED_HOSTS {example.com, trusted-cdn.com} def check_url(url): host urlparse(url).hostname if host not in ALLOWED_HOSTS: return False return True如果业务上必须允许用户传任意URL无法用固定白名单那就至少要限制协议只允许http/https并且解析DNS后校验IP不能是内网、回环、链路本地、保留地址。校验过程中还要特别注意解析结果可能不止一个IP要遍历所有结果。6.2 网络层把内网隔离看成最后防线应用层的校验永远可能被绕过所以网络层隔离极其重要。常见做法是让Web应用通过一个正向代理Proxy出口访问外网同时明确禁止代理访问内网网段。这样即便业务代码有SSRF攻击面也被网络层截住。另一个思路是在云安全组里配置出方向规则只允许业务服务器访问特定服务的特定端口其它一律deny。这个办法效果直接因为SSRF的本质是“服务器发起了不该发的请求”而你从网络策略上定义了“这台服务器到底该发哪些请求”。6.3 响应与异常处理别帮忙泄露情报防御还有一个细节错误信息别给太多。当请求失败时如果把异常堆栈原样返回攻击者就能区分“连接拒绝”和“超时”甚至看到代码里的绝对路径。正确做法是统一返回“无法获取内容”吞掉底层异常。同时对响应内容做长度限制避免把一个超大内网页面完整回传给攻击者。就算拦不住请求也别把数据完整送出来。有些团队还会加一层“禁止重定向”的开关。像requests库就可以设置allow_redirectsFalse只允许第一次请求重定向响应内容原样返回但不再继续跳转。这样至少断掉了302跳转绕过。7. 常见问题与实操避坑7.1 为什么用requests发file协议报错这个坑我遇到很多次。初学者搭靶场时用requests.get请求file:///etc/passwd发现直接抛MissingSchema错误以为是自己姿势不对。其实requests库从设计上就不支持file协议只有urllib底层才默认支持。所以搭靶场时我特意选了urllib。真实业务代码用requests也不是不能用SSRF只是利用方式变成对内网HTTP、HTTPS服务的探测和攻击文件读取这条路被堵了一部分。7.2 页面返回内容总被截断我在/**fetch接口里用data[:1000]做了限制这只是演示。实战中很多应用确实会对响应体长度做限制有的只返回前多少字节有的直接不返回内容。你不妨换个思路既然看不到全部内容那就看重定向状态码、响应时间甚至利用报错差异做盲探测。举个例子请求到内网某个端口时应用返回“超时”而请求不存在的端口时秒回“拒绝”这个时间差本身就是线索。7.3 本机绑定127.0.0.2失败怎么办Windows和部分Linux环境绑定非本机IP的127.x.x.x会遇到权限或语法问题。如果遇到这种情况别硬刚把元数据模拟服务改成绑定127.0.0.1的另一个端口比如9000。然后SSRF请求http://127.0.0.1:9000/latest/meta-data/演示效果一样。记住学原理比死磕还原真实地址更重要。7.4 授权与边界问题最后必须说一句SSRF利用的每一步都是在你自己的靶场环境里操作千万别拿这套手法去测线上系统。网络安全测试的前提是授权明确了测试范围再动手。自己搭环境练手怎么折腾都行未经授权对目标测试那性质就变了。我从入行到现在见过太多人技术没问题却在边界问题上栽跟头。我自己的经验是每次搭这种靶场都会把“靶场环境”“临时授权”写在笔记最显眼的地方。因为一旦技术熟练起来很容易顺手就想在真实目标上验证一下但这个念头必须按下去。按这套流程把SSRF跑完一遍你对“服务端到底在替谁发请求”会有一个特别直观的理解。后面再去审计代码、排查漏洞你会自带一种敏感度只要看到用户输入URL、服务端发请求脑子里自动弹出SSRF四个字母。这种条件反射靠看一百篇文章都建立不起来得自己亲手把环境搭一遍、把flag打到手才靠谱。
RELATED

相关推荐

Java基础:Object与String的底层原理与高频陷阱解析

Java基础:Object与String的底层原理与高频陷阱解析

当学到Java基础中间阶段,多半会碰到两个绕不开的名字:Object和String。很多人对它们的认知停留在"Object是所有类的父类""String是不可变的",然后就去背面试题了。但实际写代码时,equals和用错、循环里拼字符…

📅 2026/10/21 16:30:05
Python与PyQt6实现Windows移动硬盘安全弹出工具

Python与PyQt6实现Windows移动硬盘安全弹出工具

1. 事情起因:系统"安全弹出"是怎么折磨我的你是不是也遇到过这种场景:素材拷贝完毕、照片整理完、项目文件终于收工,你点开系统右下角那个隐藏的小箭头,想找到"安全弹出"对应的图标,结果先是找不到…

📅 2026/10/21 16:30:05
LNMP一键安装包后门检测与应急清理实战指南

LNMP一键安装包后门检测与应急清理实战指南

这两个月我连续处理了三起生产服务器被植入后门的救援请求,前两起是某公司跑业务接口的应用机,后一起是给客户演示用的测试环境。三台机器放在一起对比,共同点非常扎眼:都在半年到一年前,用过从网上下载的LNMP一键安装…

📅 2026/10/21 16:25:04
MORE NEWS

更多资讯

📰

基于Python的网络流量分析与入侵检测系统实战解析

如果你也选到了这类题目,大概率会经历这样一个阶段:论文里架构图画得挺漂亮,一打开Wireshark看到满屏的数据包就发怵。 基于Python的网络流量分析与入侵检测系统 ,这个名字听起来像是把“网络流量分析”和“入侵检测”两个概念拼…

📰

MCP协议+AI Agent驱动工业仿真自动化

1. 项目概述:当工业仿真遇上自然语言交互,到底发生了什么?“MCP AI Agent 驱动工业仿真”这个标题一出来,很多做CAE、CFD、结构动力学或热管理的老工程师第一反应是:又一个概念包装?但如果你真在某高校实验…

📰

PowerContext:面向智能编程的项目级上下文底座架构

1. 这不是“又一个上下文管理插件”,而是项目级状态基建的重新定义“MiniMax Code 接入 PowerContext:构建跨会话与跨 Agent 的项目上下文底座”——这个标题里藏着三个被多数开发者低估的关键信号:“跨会话”“跨 Agent”“底座”。它不指向…

📰

ThreadPoolExecutor七参数与生产环境调优实战:从任务流转到动态监控

我先把线程池这个老生常谈的话题捋了一遍,发现网上讲参数、讲流程的文章确实不少,但大多数要么是源码翻译,要么是概念堆砌,真正能落到生产环境、经得起实际业务考验的内容其实不多。这篇文章不打算从“什么是线程池”这种教科书式…

📰

AI赋能专业工作流:设计师/CAD/测试三端协同实践

1. 为什么“让AI干专业活”不是口号,而是正在发生的生产力迁移最近在帮某高校实验室做一套跨平台图像处理Demo时,我遇到一个典型场景:导师需要快速生成三版不同配色方案的UI线框图,用于学生课堂演示;同时还要把其中一版…

📰

基于S7-200和组态王的双容水箱液位控制系统设计与整定

要是你没亲手调过双容水箱的液位,可能很难理解为什么一个只有两个罐、一根管道、一台泵的小装置,能成为那么多过程控制教材和课程设计里的常客。双容水箱液位控制系统的重点从来不在“水箱”本身,而在于它背后那个典型的二阶惯性对象&#xf…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬