资讯动态

CSRF与SSRF漏洞全解析:靶场实战从原理到防御一次搞懂

发布时间:2026/10/19 3:42:57 来源:尧图企业网站定制
靶场这东西很多人把它当成了“刷题软件”进去点两下、抄个Payload、看到弹窗就以为自己会了。但真到了实战或者护网那种场景碰到CSRF和SSRF往往一脸懵——这俩漏洞名字长得像原理却完全不是一回事。我最近在本地搭了一个模拟真实业务的靶场环境专门把CSRF和SSRF从原理到利用到防御整个过了一遍今天就把这套完整的思路和实操过程记录下来。这篇文章适合两类人一类是刚接触Web安全、想在靶场里把漏洞原理吃透的初学者另一类是写业务接口的开发者想搞清楚为什么代码里要加那些“看起来很麻烦”的校验。我会用最直白的方式讲清楚这俩漏洞到底是什么、怎么触发、怎么利用、怎么防御全流程拆开揉碎了讲。1. 先分清两个漏洞的本质一个打用户一个打服务器CSRF和SSRF的缩写只差一个字母但攻击目标和攻击路径完全是两套逻辑。很多人混淆它们是因为都带“Request Forgery”——请求伪造。但伪造的主体不同伪造的目标也不同。1.1 CSRF的本质借用户之手发请求CSRFCross-Site Request Forgery跨站请求伪造的核心思路是攻击者没办法直接向目标网站发合法请求但他可以让“已经登录的用户”去发这个请求。想象一下这个场景你去银行柜台办业务窗口的小姐姐认脸——你就是你你签过的字就是有效。但如果有个小偷站在你身后趁你签字的时候用你的手去签一份“转账授权书”银行一看笔迹是本人的就放行了。CSRF干的差不多就是这个事。它成立的前提有三个用户确实登录了目标网站浏览器里存在有效的登录凭证最常见的就是Cookie。目标网站存在一个“敏感操作”的接口比如修改密码、转账、改邮箱。这个接口没有校验请求的来源也就是缺少CSRF Token或者Token校验形同虚设。浏览器有个默认行为你在浏览任何一个页面时页面里的图片、表单、脚本都可以自动向其他域名发送请求而且会自动带上目标域名对应的Cookie。Cookie一旦发出服务器就只能看到一个“带着合法凭证的请求”根本不知道这个请求到底是不是用户本人的操作。1.2 SSRF的本质借服务器之手发请求SSRFServer-Side Request Forgery服务端请求伪造的思路完全不同。攻击者不是利用用户而是利用“服务器上某个功能”——那些需要服务器主动去访问其他URL的功能。打个比方你住酒店想拿隔壁房间的东西肯定进不去。但你可以给前台打电话说“麻烦帮我去隔壁房间取一份文件”前台如果不够警觉就真的去了还把那边的文件内容念给你听。SSRF就是这个打电话的行为。这类功能的真实案例非常多图片上传/下载功能你给我一个图片URL服务器去抓取。文件预览功能把任意URL转换成PDF或图片返回。数据库/ES的数据导入支持从远程URL拉数据。Webhook回调、SSO单点登录的Metadata获取。问题出在服务器是内网的一份子它能访问到用户访问不到的地址。攻击者精心挑选URL比如http://127.0.0.1:8080/admin、http://192.168.1.1/manager让服务器去访问内网的资源再把结果带出来。1.3 两个漏洞的组合关系CSRF是横向的——在同一个用户权限体系内利用用户的身份操作他的资产。SSRF是纵向的——突破边界从外网打向内网。很多真实攻击场景里它们可以串成一条链先用CSRF让管理员/普通用户触发一个请求这个请求带着内网信息发到攻击者的服务器或者是用管理员身份触发一个服务端请求间接打进内网。我在靶场里就是这么设计的一个普通的用户可以触发CSRF让服务器去执行一个对接第三方系统的URL抓取操作而这个URL内网才能访问到。单体漏洞每个都看着“没啥影响”组合起来就是一条能拿到内网控制权的链路。2. CSRF从原理到通关手写PoC的过程很多靶场里的CSRF关卡核心动作就是“点一下链接密码被改了”。但真正理解它还是要自己从头构造一次完整的攻击请求。2.1 靶场里的CSRF触发条件分析我在靶场里布置了一个典型的业务场景一个账户管理后台用户可以修改自己的邮箱。修改成功后系统会给新邮箱发一封确认邮件。看上去很常规但问题在于修改邮箱的接口是POST /api/user/email请求参数就两个email和csrf_token入口页面里的表单提交时会带一个Token但这个Token只存在页面的隐藏字段里服务端对Token的校验居然是可选的为了验证到底是不是可选的我抓包看了一下实际请求。正常的请求长这样POST /api/user/email HTTP/1.1 Host: target.local Cookie: sessionabc123def456 Content-Type: application/x-www-form-urlencoded emailhacker%40evil.comcsrf_token5d8f3a1c9b7e我试着把csrf_token参数整个删掉再提交了一次。结果服务器返回了200邮箱照样被改了。这基本上就坐实了问题Token不是强制校验的纯属摆设。这种问题的根源是开发者觉得“我页面上带Token了攻击者又拿不到我的Token肯定没法构造请求”。但他们忘了——攻击者根本不需要从页面拿Token他只要让用户的浏览器自己把Token带上去。如果Token是写死在页面里的浏览器在自动提交表单的时候自然会带上如果Token校验本来就可选那更省事直接删掉就行。2.2 手工构造一个CSRF PoC接下来就是经典的PoC构造。对于GET型请求一个img标签或者一个超链接就够用了。但对于POST型接口最稳妥的姿势是用一个隐藏表单自动提交。我构造的攻击页面长这样html body h1点击领取优惠券/h1 form idcsrfForm methodPOST actionhttp://target.local/api/user/email input typehidden nameemail valueattackerevil.com /form script document.getElementById(csrfForm).submit(); /script /body /html这个页面放在我自己的服务器上把链接发给已登录的用户。用户一点开表单自动向目标站发送POST请求浏览器自动带上target.local的Cookie服务器一看Cookie合法、参数齐全就把邮箱改了。这里有个细节很多入门教程把PoC写成form.action里直接报错跨域实际上表单提交是不受同源策略限制的。页面可以任意指定提交地址浏览器允许跨域提交表单只是JS读不到响应而已。这恰恰是CSRF能成立的原因之一。2.3 绕Token校验的几种常见姿势删掉Token是最简单的但现实中更多的情况是Token存在但校验不严。靶场里我复制了三种常见的弱校验逻辑手底下都过了一遍第一Token绑定Session但不校验来源。服务端把Token存在Session里同时也接受请求体里的Token但Token值没有被正确比对。这种漏洞的利用方式很粗暴——直接从正常业务请求里抓一个有效Token放到Payload里用。因为每个用户登录后都有自己对应的Token攻击者完全可以自己注册一个账号拿一个合法Token替换到受害人请求里。第二Token未绑定请求方法。有些代码只在POST /api/user/email里校验了Token但开发者漏掉了GET /api/user/email/change这个入口。我把请求改成GET参数放URL上照样通了。第三Token对比时可被正则绕过。有代码写成if (token csrf_token || token null)这种属于低级错误但实属罕见。还有一种更隐蔽的服务端取了请求里的Referer头判断来源但Referer可以被表单里的meta namereferrer contentno-referrer去掉Referer为空也能过。2.4 防CSRF的正确写法从靶场出来我想聊聊开发侧正确做法。别把希望寄托在“同源策略”上——同源策略是浏览器JS层面的限制表单提交这种古老的机制根本不归它管。靠谱的方案是下面几个在服务端生成一个随机的、带时效的Token绑定到Session每次敏感操作必须校验。用SameSite属性处理Cookie。SameSiteLax已经能挡掉大量跨站请求SameSiteStrict更严格。对于JSON接口强制要求自定义Header比如X-Requested-With: XMLHttpRequest。跨站表单没法设置这个头除非目标站本身存在CORS配置错误。双提交Cookie模式在所有Cookie目录下都能用但它本质上是个降级的方案。我见过很多团队把CSRF防御寄托在中间件上自己在代码里不写。这不靠谱因为中间件只拦截路由贴满业务逻辑的接口往往成了漏网之鱼。3. SSRF从探测到利用补全常用技巧SSRF的靶场通常比CSRF复杂一些因为它不仅仅是“构造一个请求”而是要跟内网探测、协议利用这些东西搅在一起。3.1 靶场里的SSRF入口怎么找最常见的是URL转图片和URL抓取解析功能。我在模拟系统里写了一个“商品图片代理”的接口大致逻辑是用户传一个参数img_url服务端用curl去抓图片然后把图片内容返回给前端。这是SSRF的教科书入口。真正验证SSRF漏洞存在时我习惯按三步走第一步判断请求是否真的会由服务端发出。传一个本地就能访问的URL看响应里能不能看到对应内容。比如传http://127.0.0.1:8080/如果返回内容里包含“Welcome to Local Service”这类字样说明服务器确实请求了内网地址。第二步利用时间延迟来判断能否访问非标准端口。因为有些功能会对端口做限制比如只允许80和443。传一个指向非标准端口的URL比如http://127.0.0.1:3306/如果响应时间和80端口明显不同或者直接超时说明这个端口被防火墙挡了或者协议不匹配。第三步把响应内容带出来验证。如果接口直接把内容渲染到页面上那就拿到了数据。如果只是返回“成功/失败”这类状态就要考虑用盲打的方式逐步探测比如可以访问的URL返回200、不能访问的返回500通过响应码的差异把内网摸出来。3.2 绕IP限制的几种常见姿势CTF和靶场里经常看到“不准访问内网IP”的限制实战中也常见。绕过的路子大概有这么几条整数化IPhttp://2130706433/其实是127.0.0.1的另一种表示不少防线没认出这是内网地址。十六进制和八进制表示http://0x7f000001/也是127.0.0.1。域名写法http://127.0.0.1.nip.io/或http://spoofed.burpcollaborator.net用某个域名做DNS解析到内网IP。重定向服务端如果跟随重定向可以先传一个外部URL它302跳到内网地址这样初次的IP检测就被跳过了。DNS重绑定第一次DNS解析返回公网IP通过检测第二次解析返回内网IP利用请求落到内网。这个需要自己搭DNS服务实操成本高但效果很好。靶场里我用的最多的是“URL规范化绕过”传http://127.0.0.1%2523evil.com/之类关键是让服务端在解析URL时产生偏差。不过每种语言对URL的解析规则不同有时候最简单的反而最有效。先试http://192.168.1.1:80被拦了再试http://192.168.1.1:80通常就能过。3.3 利用file协议和内网端口打进去SSRF不仅能打HTTP还可以利用其他协议。我试过的套路有file:///etc/passwd直接读文件。dict://127.0.0.1:6379/info探测Redis端口。gopher://构造任意TCP包常见目标是打Redis写crontab。gopher协议是个大杀器因为你可以通过它直接构造一段二进制数据。靶场里的Redis利用我专门试过过程比较繁琐——先确认目标Redis端口通然后构造一个Redis命令用gopher://发出去写入一个计划任务文件。虽然现在很多实例Redis都不允许外网直接访问但只要SSRF能触发服务器上的Redis客户端这条链就能通。3.4 SSRF防护怎么落地SSRF的防御思路有两个方向缺一不可限制目标地址。服务端解析出URL后解析它的IP判断是否属于内网网段127.0.0.0/8、10.0.0.0/8、172.16.0.0/12、192.168.0.0/16、169.254.0.0/16等。如果命中就直接拒绝。这里有个关键点解析IP必须在服务端完成不能相信用户传入的参数。限制协议和端口。只允许http和https其他协议一律拒绝。端口最好白名单化只允许80、443、8080等。另外关闭或限制重定向或者对重定向后的地址再执行一次校验防止绕过。4. 完整通关实录一次把CSRFSSRF组合起来打这部分的每一步都是我在模拟靶场中跑通的你来操作时背后的业务逻辑可能不同但思路完全可以照搬。4.1 靶场环境准备靶场我用的是一个开源的综合漏洞练习系统装在本地虚拟机里随时可以重置。系统里有一个完整的模拟业务用户模块登录/注册、商品模块图片上传/查询、管理后台内网日志查看。环境清单就三样靶场系统目录/var/www/target数据库MySQL账密写在config.php里攻击机Kali浏览器装好Burp Suite4.2 CSRF部分通关从发现到利用第一关上来了个“修改收货地址”的功能。我登录账号A进入修改地址页面抓包看到请求是POST /api/address/update HTTP/1.1 Host: target.local Cookie: sessionxxxx Content-Type: application/json {id:123,address:newaddr,token:a3f9d1c2}我第一反应是看token是不是必须的。删掉token直接重复请求返回400——这次没那么幸运Token校验是真的。然后我看了一下Token生成逻辑。这个系统的Token不是随机的而是md5(user_id timestamp)。我马上用自己账号的user_id和当前时间戳算了一串把请求里的token替换成算出来的值。结果服务器接受了。原因是Token本身没有绑定Session只是“看上去是随机数”。这给了个思路如果我构造一个攻击页面让用户在不知情的情况下提交一个地址更新请求Token部分我用自己的值就能通过。但这里面有个坑——用户身份不同服务器校验用户ID时可能不认。继续测试发现这个接口居然没校验用户ID是否和Session匹配只要Cookie里有已登录用户的Session参数写谁的ID就更新谁的地址。最终我构造了这样一个页面form methodPOST actionhttp://target.local/api/address/update input nameid value1 / input nameaddress valueattacker-controlled / input nametoken value4f2b7c9e1d6a / input typesubmit / /form scriptdocument.forms[0].submit();/script用户点进来地址就被改了。这一步很有意思漏洞不是单纯的“没Token”而是“Token生成规则可预测 接口不校验所有者”。两个看起来不大的问题叠加起来才导致整个CSRF链路成立。实战中很多CSRF就是这么堆出来的。4.3 SSRF部分通关从探测到内网击穿第二个靶场任务是“商品图片代理”。业务逻辑很简单用户可以提交一个图片URL服务器去下载图片然后展示。我传了一个http://target.local/static/logo.png能看到图片正常渲染。接下来我换成本机的私有地址GET /api/image/proxy?urlhttp://127.0.0.1:8080/admin HTTP/1.1返回了管理后台的登录框HTML片段。这说明端口和路径都走得通。我顺着摸端口8080是管理后台返回登录页。3306是MySQL响应时间明显变长说明TCP连接成功但协议不通。6379是Redis返回了-ERR unknown command类似的回显确定存活。利用file协议试了一下读文件GET /api/image/proxy?urlfile:///etc/passwd返回了系统的用户列表。到这里利用范围就很大了。“攻陷”这个模拟系统需要构造一个在管理后台添加管理员账号的请求。管理后台在8080端口接口是POST /admin/user/add参数是username和password。用SSRF直接打过去不行因为SSRF只支持GET图片抓取而创建管理员是POST。我试了一种更偏门的组合——利用gopher协议构造一个POST请求打到8080让服务器以为是一个合法内网请求成功创建了一个账户。命令里面用Content-Type: application/x-www-form-urlencodedbody里放账号密码。这种打法的限制是很多但在这套模拟环境里完全成立因为8080的管理接口没有限制来源IP而SSRF服务器在内网天然就是“可信来源”。这也是为什么很多公司在内网里互相不设防、一锤就打穿的原因。4.4 CSRFSSRF组合链路完整走一遍单看这两个洞CSRF“只是改个地址”SSRF“也就是读个文件”。但把它们串起来伤害直接拉满。我的思路是先用SSRF摸清楚内网资源和接口再用CSRF让一个高权限用户触发“修改同步配置”的操作。这个配置项允许用户填入一个远程地址服务器会定期去抓取本质上就是一个定时SSRF。填上攻击者控制的地址后攻击者就能在内网服务端执行任意HTTP请求等于拿到了一条稳定的内网通道。这个组合方式在真实业务里非常常见比如后台的“第三方回调地址”“仓库同步地址”“定时报告导出地址”全都是SSRF的温床而配置操作本身可能又缺CSRF防护。5. 防御清单与常见问题速查打完靶场必须回到防御侧。我把CSRF和SSRF对应的加固项整理成了一张排查清单方便你自己系统过一遍。5.1 CSRF加固清单检查项正确做法敏感操作改密、改邮箱、转账、改地址强制校验随机、不可预测、绑定Session的TokenCookie属性加SameSiteLax或Strict按业务要求调整状态变化请求一律拒绝用GET实现必须POSTJSON接口校验自定义Header比如X-Requested-With用户身份越权校验每次接口都要校验参数中的ID等于当前登录用户的ID框架中间件确认CSRF中间件真的覆盖了所有路由别遗漏API前缀5.2 SSRF加固清单检查项正确做法URL入参服务端解析URL → 提取Host → 解析IP → 判断内网网段 → 拒绝协议白名单只允许http/https禁用file/gopher/dict等端口仅允许80/443/8080等预置端口重定向默认禁止跟随最多跟随一次且再次校验目标IP错误回显禁止前端返回具体访问错误统一报“资源加载失败”内网访问管控服务端所在网络做好最小权限划分出网要收敛5.3 常见问题速查QCSRF Token存在Session里用户同时开了两个Tab后一个覆盖前一个导致操作失败。AToken要允许同一Session内多个并行Token有效或者用双提交Cookie的方式绕过Session存储问题。Q设置了SameSiteStrict用户从第三方站跳到本站时登录态丢了影响转化。A可以把关键操作Cookie设为Strict非敏感Cookie保持Lax。不能因为怕麻烦就全不限。QSSRF的IP白名单里看到了IPv6地址要拦吗A必须拦。IPv6的::1对应IPv4的127.0.0.1内网地址还可能通过IPv6绕过防御代码里务必同时解析IPv4和IPv6。QURL里包含用户名密码的http://user:passhost/写法会被解析成host吗A会很多语言的标准库会把user:pass看作认证信息最终请求发到host。校验时必须用解析出的host字段不能直接比对整个URL字符串。写在最后的实操心得我在靶场里每通关一个漏洞都会回头看看这个漏洞如果放在真实业务里会落在哪个模块。CSRF往往藏在“个人设置”和“导出报表”这种看似平平无奇的功能里而SSRF几乎必然出现在“对接第三方”的接口上。排查的时候优先盯这两类位置效率比乱翻代码高很多。还有一点建议别只看概念自己动手把PoC写出来。你亲手改一次请求、删一次Token、试一次gopher协议对漏洞的理解会完全不同。靶场就是用来反复练习的先打穿再尝试修复修复完再想想怎么绕过修复这样来回几个回合才算真正“通解”了一个漏洞类型。

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

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

免费获取报价 →
↑