资讯详情

资讯详情

CSRF漏洞深度解析:从跨站请求伪造原理到实战绕过与防御

在实际业务里摸爬滚打过一段时间后我对CSRF这个老牌漏洞有了些新的理解。今天不聊那些嘴上说烂的“Token校验、SameSite”空话而是用一篇完整的教程从底层机制到实际场景把CSRF这个看似简单的漏洞讲透彻。无论你是刚入行的新人还是写过几年业务代码的开发我相信这篇文章都能给你一些不一样的启发。1. 内容整体设计与思路拆解1.1 为什么说CSRF“入门容易精通难”CSRFCross-Site Request Forgery跨站请求伪造在各类漏洞排行里一直没掉出过前排但很多零基础的安全爱好者在学习它时会经历这样一个过程刚看教程时觉得“这还不简单”无非就是诱导用户点击一个链接就能伪造请求。真正上手测试后才发现实际情况复杂得多——CSRF漏洞的利用成功与否往往取决于你对目标站点的业务逻辑理解有多深而不是仅仅会构造一个表单就完事。我记得团队里一个新人A同学第一次接触CSRF时对照网上模版写了一个恶意的提交表单兴冲冲地跑去测试某个内部系统。结果显而易见请求被拦截了。他当时疑惑地问我“是不是目标系统没这个漏洞”我让他去抓包看下实际请求里有没有Token参数再看看Referer头部是怎么处理的。结果发现目标系统不仅校验了Token还把SameSite属性设置成了Lax。这个案例很典型让我意识到CSRF的“简单”只停留在教科书层面真实环境下CSRF最难的其实是“绕过”与“防御”之间的博弈。1.2 这期教程的价值与适合人群这篇文章的定位不是一篇“读起来很爽”的漏洞列表而是一篇具备实操参考价值的挖掘指南。我会从零开始拆解CSRF的触发链路逐层分析“同源策略”“表单提交”“JSON跨域”这些看似基础但综合起来能决定漏洞是否存在的因素。如果你正在学习Web安全或者你是后端开发、全栈工程师想从“防御者视角”反向理解为什么CSRF会让开发团队头疼这篇文章很适合你。我会用自己的实战经历、模拟测试环境和测试中踩过的坑给你展示一个符合真实业务场景的CSRF测试全流程。提示所有测试操作均应在具备合法授权的前提下进行。不建议对未经许可的目标发起任何安全测试否则后果自负。2. 核心机制解析CSRF为什么能够存在2.1 先从“会话”聊起Cookie与身份认证想要理解CSRF必须先理解Web应用是如何识别一个用户的。HTTP协议本身是无状态的服务器无法直接知道“当前发起请求的人是谁”。为了让用户不需要每次请求都重新输入用户名密码Web应用引入了“会话Session”机制通常通过Cookie在客户端保存一个“会话标识”Session ID。你登录了一个网站服务器生成一个Session ID存在你浏览器的Cookie里并把它和你的用户身份绑定在一起。之后你的每次请求带上这个Cookie服务器确认无误后就认为“这是本人在操作”。这个机制本身没有问题但它催生了一个盲区浏览器自动携带Cookie的特性。2.2 攻击的核心逻辑浏览器的“无脑”行为CSRF的攻击逻辑是建立在浏览器“自动携带身份凭据”这一行为之上的。攻击者构造一个恶意页面页面里“藏”着一个指向目标网站的请求。当受害者访问这个恶意页面时浏览器会忠实地替受害者发出那个请求并且只要受害者在目标网站处于登录状态浏览器就会自动附带上他的Cookie。举个最常见的例子假设你在某个论坛保持了登录状态黑客在某个人气很旺的图片分享帖里嵌入了一个隐藏表单表单的提交地址是那个论坛的“修改邮箱”接口。当你打开这个帖子时隐藏表单自动提交你的邮箱就被修改成了黑客的邮箱。整个过程你完全无感知请求已经发出并且携带了你的合法身份凭证。这就是CSRF最核心的模型。2.3 关键误区CSRF与XSS的本质区别很多零基础同学会把CSRF和XSS跨站脚本弄混这里我用一句话说清楚XSS利用的是“用户对网站的信任”核心是“在目标网站内执行恶意脚本”。CSRF利用的是“网站对用户浏览器的信任”核心是“在受害者的浏览器里发起带有身份的伪造请求”。在CSRF攻击中攻击者完全不需要拿到目标网站的Cookie、Session ID或其他任何身份凭证攻击者只需要知道请求的目标URL和参数格式。2.4 CSRF利用成功的条件缺一不可在实际测试中一个CSRF漏洞想要利用成功通常需要满足以下三个条件之一或全部目标请求必须使用Cookie或浏览器自动携带的身份进行鉴权。如果目标接口改用Token放在请求头比如Authorization: Bearer那么纯CSRF攻击基本行不通。目标请求没有防伪校验。比如没有CSRF Token、没有校验Referer/Origin或者校验方式可以被绕过。攻击者能够构造一个“命中”的请求。这意味着攻击者要精确知道目标接口的URL、请求方法POST/GET、必要的参数名和参数值。理解了这个链路你才能明白为什么CSRF漏洞的高发区往往是**“非核心业务但涉及状态变更”**的接口比如修改个人资料、绑定手机号、修改密码一定条件下、点赞、关注、发表评论等。这些接口往往安全防护松懈但又真实地改变了用户数据。3. 实操要点从零构造一个CSRF验证环境以“教”带“学”是最快的成长路径。想要真正掌握CSRF漏洞的利用和防御自己动手搭一个靶场环境是必经之路。我分享一下我平时测试用的最小化环境方案简单、直接、不依赖外部网络。3.1 环境准备三个组件缺一不可你需要准备这三个角色一个目标站点我建议用本地PHPStudy或者直接写一个最简单的PHP/Flask/Express服务提供登录鉴权接口和“修改个人信息”接口。一个攻击者站点同样可以放在本地或者使用本地文件file://协议模拟跨域注意文件协议在某些浏览器里Cookie行为不同建议还是起一个本地HTTP服务。一个受害者浏览器推荐使用无痕窗口方便模拟登录态。3.2 核心靶场代码目标接口设计我以Python Flask为例写一个最典型的“修改昵称”接口用于演示。这个接口仅依赖Cookie进行身份识别没有CSRF防护为了模拟真实性我特意让它使用POST请求内容编码格式为表单application/x-www-form-urlencodedfrom flask import Flask, request, make_response, session app Flask(__name__) app.secret_key test-secret-key # 仅演示用 users { admin: {password: 123456, nickname: Admin}, } # 登录接口设置Session app.route(/login, methods[POST]) def login(): username request.form.get(username) password request.form.get(password) user users.get(username) if user and user[password] password: session[username] username return make_response(login ok) return make_response(login failed, 403) # 修改昵称接口 —— 仅检查登录状态无CSRF Token app.route(/update_nickname, methods[POST]) def update_nickname(): if username not in session: return make_response(not logged in, 401) new_nickname request.form.get(nickname) # 实际业务在这里更新数据库 users[session[username]][nickname] new_nickname return make_response(fnickname updated to {new_nickname}) if __name__ __main__: app.run(host0.0.0.0, port8000)这段代码里update_nickname接口没有Token校验逻辑极其简单——只判断当前浏览器是否携带了有效Session Cookie。3.3 攻击者页面隐藏表单与自动提交接下来是攻击者的阵地。我需要构造一个“恶意页面”这个页面放在另一个本地端口比如8001上。关键点是这个页面里“藏”的表单提交地址是目标站点127.0.0.1:8000的接口并且由于表单提交天然支持跨域浏览器不会拦截这种“页面发起跨域请求”的行为。html body h1一个正常的私人博客页面/h1 p如果你看到了这篇文章说明你已经中招了。/p form idcsrf-form methodPOST actionhttp://127.0.0.1:8000/update_nickname enctypeapplication/x-www-form-urlencoded input typehidden namenickname valueHacked-By-CSRF / /form script // 页面加载完成后立即提交 window.onload function() { document.getElementById(csrf-form).submit(); } /script /body /html页面看起来人畜无害但实际上是一个“请求发射器”。任何登录了目标站点的用户只要访问了这个恶意页面浏览器就会向目标接口发出一个POST请求并把受害者的Session Cookie一并带上。3.4 完整复现与现象解释操作步骤很简单我按顺序演示一遍打开无痕窗口A访问http://127.0.0.1:8000/login提交用户名和密码admin/123456确认登录成功。登录后访问任意页面确认Cookie已被设置此时浏览器对目标站点是“已认证”状态。另开一个无痕窗口B确保和目标站点没有直接关联访问攻击者控制的恶意页面http://127.0.0.1:8001/evil.html。观察窗口A或者直接查询数据库中的nickname字段你会发现即使没用目标站点的Cookie、没有输入密码用户的昵称也已经被修改成了Hacked-By-CSRF。现象背后发生了什么窗口B的浏览器向目标服务器发送了一个携带了SessionID的合法POST请求目标服务器只认Cookie不关心这个请求到底是不是用户本人主动发出的于是直接更新了数据。受害者完全没有感知。这里补充一个容易被忽略的细节为什么表单提交能跨域因为 HTML 表单form的action属性可以指向任意域名的地址浏览器出于历史原因老式的Web交互模式允许这种POST跨域行为。而XMLHttpRequest / fetch 则受同源策略限制无法直接跨域发送“可携带Cookie”的请求需要额外配置CORS。这也是CSRF攻击最传统的载体是“表单”的根本原因。4. 常见问题与排查技巧为什么我的测试不成功实际测试中不可能每次CSRF利用都一击即中。我把近几年测试中遇到的高频失败原因做了汇总你对照着排查基本能解决95%的问题。4.1 防伪Token校验导致的失败现象提交恶意表单后对方返回“请求无效”或“参数校验失败”。排查思路这是最常见的拦截手段。目标接口在渲染时生成了一个一次性Token存入隐藏字段或自定义Header下一次提交时对比是否一致。这里有个关键测试思路不要一上来就说“这里防御了没法绕过”。你要在合法业务里找“Token是否被复用、是否可预测、是否在特定接口缺失”的场景。比如注册接口的新用户Token是否固定某些接口如退订邮件、消息已读上报是否因为历史原因漏掉了TokenGET类型请求也能触发状态变更且无Token时能否利用图片标签img srchttp://target.com/delete?id123直接触发4.2 SameSite Cookie策略导致的失败现象写好的利用页面请求始终不携带Cookie抓包看Cookie字段是空的。排查思路这是现代浏览器抵御CSRF的标准手段之一。SameSite属性有Strict、Lax、None三个值简单说Strict完全禁止第三方Cookie随跨站请求发送。Lax只有“顶层导航”的GET请求会携带Cookie表单POST和异步请求都不会携带。None允许所有请求携带Cookie但需要在HTTPS环境配置。如果目标站点的Cookie设置的是SameSiteLax或Strict传统的表单自动提交方式大概率失效。这时候你得转换测试思路尝试寻找“子域漏洞Cookie域配置宽松”的组合或者看看是否有“JSONP”“CORS配置错误”可以利用的服务端逻辑。4.3 Referer/Origin校验带来的挑战现象目标服务器校验了Referer或Origin头发现请求来源不是自身域名直接拒绝。排查思路如果Referer校验是通过“包含匹配”例如检查请求头中是否包含了某个域名片段那么就存在绕过空间。举个例子目标校验Referer中是否包含target.com那攻击者可以把恶意页面放在target.com.attacker.com域名下不同子域名Referer就会变成http://target.com.attacker.com/evil-page包含目标域名但实际是攻击者控制的。不过这种方式需要攻击者拥有一个可控域名的子域解析在真实SRC挖掘中属于高危接口可利用边缘场景的结合。4.4 JSON接口与Content-Type校验现象目标接口要求Content-Type: application/json而HTML表单只能发送text/plain、application/x-www-form-urlencoded、multipart/form-data这三种编码无法直接提交JSON数据。排查思路碰到这种情况传统的form提交失效。可以试试这两个方向JSONP接口如果目标站点存在返回JSON数据的Callback接口老系统常见可以构造script src...跨域加载并执行特定函数间接向接口发送请求。Flash / 表单跨域漏洞2010年前后的老系统内部处理函数有的会把text/plain主体按JSON解析因为request.getParameter无法读取但request.getInputStream是通的这种情况纯CSRF攻击也有可能成立。4.5 调整请求方式GET型CSRF别忽略现象目标接口只支持GET请求但按照“传统CSRF教程”好像都需要POST表单。排查思路如果GET请求直接携带了敏感操作参数例如DELETE /index.php?id2或者POST 接口支持 GET 方式访问很多开发框架为了方便调试默认允许这种场景下用img、link、script标签就能触发跨站请求根本不需要表单。为什么不建议只测POST因为“能用GET绝不用POST”的老一代开发习惯以及RESTful接口的普遍化导致“GET方法修改状态”的案例至今没有断绝。这是一个非常典型的“低投入高回报”测试点。5. 防御方案与有效性对比说完了攻击侧和测试侧我站在开发者的视角聊几套CSRF防御方案的实际效果。记住没有银弹安全的本质是“成本与收益的博弈”。5.1 同步令牌模式Synchronizer Token Pattern思路服务器生成随机Token写入表单隐藏字段或响应Header中并在Session中保存一份。每次请求提交时比对两个值是否一致。有效性与缺点这是最经典的CSRF防御机制有效防止“无脑表单提交”。但它的防护强度取决于Token是否绑定用户身份全局Token在“登录前功能”上容易被绕过Token是否在每次请求后刷新一次性Token比固定Token安全得多Token的随机性生成算法是否安全实际踩坑时你会发现很多系统中的Token只做了“存在性校验”没做“一致性校验”或者虽然做了校验但Token同时存在于Cookie中导致可以配合XSS缺陷绕过。5.2 双重提交CookieDouble Submit Cookie思路服务器要求前端提交一个Token这个Token在客户端以Cookie形式存在。服务器校验“提交的Token”和“Cookie里的Token”是否一致由于跨站请求无法设置目标域名的Cookie所以认为安全的。有效性与缺点这个方案在“纯CSRF”场景下很有效但如果目标环境存在子域任一处XSS或者Cookie由于某些配置可以被子域影响例如Cookie Domain设置太宽攻击者可以在攻击者域名下写入恶意Cookie来伪造提交Token导致绕过。5.3 SameSite Cookie 属性前面已经提到过这是浏览器层面提供的原生防护。强烈建议开发团队将所有“不要求跨站携带”的Cookie一律设置为SameSiteLax必要时用Strict。在Chrome和Firefox高版本中这基本能把传统CSRF的90%问题堵在门外。这也是2020年以后CSRF漏洞数量陡降的主因之一。5.4 Origin/Referer校验思路如果请求头中的Origin不是本站域名则拒绝。这种方案部署成本低但依然存在“空Origin”通过比如沙箱页面、内嵌页面、某些旧版浏览器的情况。建议配合Token方案做双保险。5.5 防御方案对比速查表防御方案CSRF防护强度部署成本绕过难度备注Token同步令牌高中高需注意Token生成算法和失效机制双重提交Cookie中低中对子域XSS较敏感SameSite属性高极低高主流浏览器不能完全替代服务端防御兼容性问题Referer/Origin校验中低中需关注空值和子域解析问题验证码/二次确认极高高极高常用于高敏感操作如改密、转账我的建议是核心业务采取“TokenSameSite”组合重要操作修改密码、绑定手机、转账额外增加二次验证。在成本和体验之间寻求一个可控的平衡点。6. 从漏洞挖掘角度看CSRF的行业变化6.1 “降级”为高危链里的一环这两年CSRF在独立漏洞挖掘中的地位有所下降原因正如前面提到的浏览器对Cookie的跨站限制越来越严格开发者框架默认启用防伪校验独立触发一个“纯CSRF”漏洞的难度确实大了。但注意CSRF并没有消失而是更多作为“高阶漏洞链条”中的一环出现。比如在以下场景中CSRF依然是关键点睛之笔配合XSS降级利用一个理论上只能自我触发的存储型XSS通过CSRF将数据写入目标用户扩大影响范围。配合并发逻辑漏洞利用CSRF让受害者在不知情的情况下启动某个操作如绑定攻击者账号、关注特定用户、上传特定资源配合竞态条件实现“双重操作”。攻击“边缘业务”很多大公司在核心业务边边角角的“活动页面”“埋点上报”“第三方登录回调”里依然存在CSRF。这些接口数据价值不高但一旦涉及“修改回调地址”或者“绑定手机号”就可能是高分值漏洞。6.2 零基础学习的建议不要为了“挖洞”而“挖洞”很多同学学习安全时容易陷入一种“刷漏洞”的心态。作为一个过来人我的建议是先把一条完整链路的底层原理摸透。为什么表单能跨域为什么浏览器要默认携带Cookie为什么SameSite设置为None时容易出问题如果一个漏洞的原理你已经能够用自己的语言向别人解释清楚那你离真正掌握它就不远了。同时一定要熟悉抓包工具的使用。无论是Burp Suite还是浏览器开发者工具你需要从“结果”反推“过程”观察请求的来龙去脉。我见过很多初学者明明漏洞已经触发了却因为看不懂请求面板里的参数来源错失了确认漏洞的机会。6.3 合法测试的边界最后必须非常严肃地强调一遍本文所有内容仅为技术交流与教育目的。每一个涉及漏洞的工具、思路、代码片段都应当在合规授权的范围内使用。企业授权测试和公益SRC有明确测试范围——在范围外测试即使没造成破坏也是违背法律和道德的行为。做安全技术重要边界感更重要。这一点每个从事安全领域的人都应该牢记。现在可以打开你身边的靶场用本地环境按照上面的演示手动复现一遍CSRF的完整攻击和防御流程。这比刷一百个漏洞报告都管用。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →