CSRF攻击原理与防御实战:从DVWA靶场到企业级防护方案

发布时间:2026/7/3 4:49:30
CSRF攻击原理与防御实战:从DVWA靶场到企业级防护方案 1. 项目概述从零开始彻底搞懂CSRF攻击与防御如果你是一名Web开发者或者对网络安全感兴趣那么“CSRF攻击”这个词你一定不陌生。它就像一个潜伏在暗处的“冒名顶替者”在你登录了某个网站后悄无声息地利用你的身份去执行一些你本不知情的操作。听起来是不是有点吓人别担心这篇文章就是为你准备的。无论你是零基础的小白还是想系统梳理CSRF攻防的开发者我都会用最直白的方式带你从攻击原理、实战演练到防御策略走完一个完整的闭环。我们的目标很明确不仅要看懂还要能动手复现更要学会如何在自己的项目中筑起防线。我会结合经典的DVWA靶场带你一步步攻破Low、Medium、High三个级别的CSRF漏洞并附上详细的步骤截图让你真正“看一篇就够了”。2. CSRF攻击的核心原理与攻击场景拆解2.1 CSRF到底是什么一个“冒名顶替”的故事CSRF全称Cross-Site Request Forgery中文叫“跨站请求伪造”。这个名字听起来很技术但它的本质很简单攻击者欺骗用户的浏览器让其以用户的名义向一个用户已经认证过的网站发送恶意请求。我们可以用一个生活中的类比来理解假设你有一张签好名的空白支票这相当于你的登录状态比如Cookie。攻击者拿到了这张支票在上面填写了“向攻击者账户转账10000元”的信息然后偷偷塞进了银行柜台目标网站。银行看到是你签名的支票就执行了转账操作。在整个过程中攻击者从未真正拿到你的签名笔迹密码他只是利用了那张你已经签好名的空白支票。在Web世界里这个“签名”就是你的会话凭证通常存储在浏览器的Cookie中。当你登录一个网站比如你的网银a.com后浏览器会保存一个登录成功的Cookie。之后只要你访问a.com下的任何页面浏览器都会自动带上这个Cookie。CSRF攻击就是诱导你访问一个恶意网站b.com这个网站里藏着一个向a.com发起请求的代码比如一个自动提交的表单或者一个图片链接。因为你的浏览器访问a.com时会自动带上Cookie所以a.com的服务器会认为“哦这是那个已经登录的用户发来的合法请求”从而执行了攻击者预设的操作比如修改密码、转账、发布评论等。2.2 CSRF攻击的三大经典类型理解了原理我们来看看攻击者具体是怎么下手的。主要有三种常见的攻击载体2.2.1 GET类型攻击一个“隐形”的图片请求这是最简单粗暴的一种。攻击者只需要在恶意页面里插入一个img标签其src属性指向目标网站的敏感操作接口。!-- 假设这是攻击者页面b.com里的代码 -- img srchttp://a.com/transfer?tohackeramount10000 styledisplay:none;当你访问b.com时浏览器会尝试加载这张“图片”实际上就是向a.com/transfer发起了一个GET请求。如果这个转账接口设计不当仅通过GET请求就能完成操作并且没有验证请求来源那么攻击就成功了。这种攻击完全不需要用户交互页面一打开就中招。注意现代Web开发中敏感操作如修改、删除、支付绝对不应该只用GET方法来实现。这是防御CSRF的第一道也是最基本的防线。2.2.2 POST类型攻击一个“自动提交”的表单对于必须使用POST方法的操作攻击者会构造一个隐藏的表单并通过JavaScript自动提交。!-- 在b.com的页面中 -- body onloaddocument.forms[0].submit() form actionhttp://a.com/change-email methodPOST input typehidden nameemail valuehackerevil.com / input typehidden nameconfirm valuehackerevil.com / /form /body用户一旦访问这个页面onload事件会触发表单自动提交。浏览器会携带用户对a.com的Cookie向a.com发送一个POST请求从而将用户的绑定邮箱修改为攻击者的邮箱。之后攻击者就可以通过“忘记密码”功能重置密码完全接管账户。2.2.3 链接类型攻击诱骗点击的“重磅消息”这种攻击需要一点社交工程学诱使用户主动点击一个链接。a hrefhttp://a.com/delete-account?confirm1 img srchttp://b.com/funny-cat.jpg alt点击查看超萌猫咪 /a攻击者可能在论坛、评论区或聊天中发布一个看似无害的链接比如一张搞笑图片但其真实链接指向一个删除账户的敏感操作。用户点击后同样会触发携带Cookie的请求。2.3 为什么CSRF攻击能成功关键特征分析从我多年的安全测试经验来看一个成功的CSRF攻击通常依赖以下几个条件理解这些条件也是我们设计防御措施的出发点用户已登录目标网站并持有有效的会话凭证Cookie/Session这是攻击的基石。如果用户没登录或者会话已过期请求就不会被授权。目标网站的业务接口存在缺陷接口没有对请求的“意图”进行二次确认。它只认Cookie不关心这个请求是用户主动从网站页面发出的还是从第三方网站“被动”发出的。请求是可预测的攻击者能够轻易地构造出这个请求的所有参数包括URL、请求方法GET/POST、参数名和参数值。如果接口需要一些攻击者无法得知的动态值如CSRF Token攻击就难以进行。用户会触发恶意请求无论是自动加载如图片、自动提交表单还是诱骗点击链接总要有一个途径让用户的浏览器发出那个请求。3. 实战演练手把手攻破DVWA的CSRF模块理论讲得再多不如亲手试一次。DVWADamn Vulnerable Web Application是一个专为安全人员练习用的漏洞靶场。接下来我将带你实战演练其CSRF模块的Low、Medium、High三个安全级别。你需要先搭建好DVWA环境建议使用Docker或集成环境如XAMPP并确保安全级别设置为对应等级。3.1 Low级别毫无防护的“裸奔”状态攻击目标修改DVWA中用户的密码。漏洞分析Low级别下密码修改功能vulnerabilities/csrf/没有任何防护措施。它仅仅检查了新密码和确认密码是否一致以及是否为空完全没有验证这个请求是否来自本网站合法的页面。攻击步骤实录正常登录与观察首先用默认账号admin/password登录DVWA将安全级别设为Low。然后访问CSRF模块。你会看到一个简单的密码修改表单。提交一次修改并用Burp Suite或浏览器开发者工具的“网络Network”标签抓包。你会发现修改密码的请求是一个简单的GET请求URL类似http://your-dvwa-ip/vulnerabilities/csrf/?password_new123456password_conf123456ChangeChange这个URL包含了所有必要参数且没有Token等额外验证。构造恶意页面攻击者根本不需要破解什么他只需要把这个URL发给已登录的用户。我们可以创建一个简单的HTML文件来模拟攻击者页面。!-- evil.html -- !DOCTYPE html html headtitle来看有趣的猫咪/title/head body h2你绝对不会相信这只猫做了什么/h2 !-- 利用图片标签自动发起GET请求 -- img srchttp://your-dvwa-ip/vulnerabilities/csrf/?password_newhackedpassword_confhackedChangeChange width0 height0 / p页面内容.../p /body /html这里我用了img标签并将其宽高设为0使其在页面上不可见。当受害者访问这个evil.html时浏览器会自动尝试加载这个“图片”从而向DVWA发送修改密码的GET请求。模拟攻击保持DVWA的登录状态即浏览器Cookie有效。在同一个浏览器中打开我们刚创建的evil.html文件可以直接双击在浏览器中打开。页面看似什么都没发生但如果你立刻回到DVWA的CSRF页面尝试用旧密码password登录会发现已经登录不上了。用新密码hacked则可以登录。攻击成功实操心得Low级别的漏洞在现实中依然存在尤其是一些老旧系统或内部管理后台。它的修复极其简单绝对不要用GET方法执行写操作增删改。这是Web开发中必须遵守的铁律。3.2 Medium级别脆弱的“Referer”检查漏洞分析Medium级别引入了一层简单的防护检查HTTP请求头中的Referer字段。Referer注意拼写是错的但标准就这么定的字段表示这个请求是从哪个页面发过来的。服务器端代码会检查Referer是否包含本网站的主机名如your-dvwa-ip。攻击步骤实录分析防护逻辑将DVWA安全级别调到Medium再次尝试用Low级别的方法攻击你会发现失败了。查看服务器响应或代码DVWA提供了源码查看功能可以发现类似如下的检查逻辑PHP示例if( stripos( $_SERVER[ HTTP_REFERER ] , $_SERVER[ SERVER_NAME ] ) ! false ) { // 通过检查 }它检查Referer中是否包含服务器名SERVER_NAME。寻找绕过方法Referer是由浏览器发送的但攻击者在一定程度上可以控制或影响它。一个经典的绕过方法是利用同域下的其他漏洞页面。如果攻击者能在目标网站your-dvwa-ip上找到一个可以植入内容的地方比如一个存在XSS漏洞的留言板他就可以在那个页面里构造攻击代码。这样请求的Referer就是http://your-dvwa-ip/vulnerabilities/xss/完美通过了检查。构造攻击页面模拟XSS场景为了演示我们假设DVWA的XSSStored模块存在漏洞并且安全级别也是Medium。攻击者在留言中写入以下内容script window.onload function() { var img new Image(); img.src ../csrf/?password_newmedium_hackedpassword_confmedium_hackedChangeChange; } /script当任何用户包括管理员浏览这个存在恶意脚本的留言页面时脚本会自动执行发起一个修改密码的请求。因为这个请求是从your-dvwa-ip域名下的页面发出的所以Referer检查通过。另一种简单绕过如果服务器检查逻辑不严谨比如只是检查Referer是否存在或者检查是否包含某个字符串攻击者甚至可以通过伪造一个包含目标域名的Referer来绕过。但现代浏览器对Referer的控制越来越严格这种方式难度较大。更常见的是上述的“借刀杀人”法。注意事项依赖Referer防御CSRF是非常不可靠的。首先用户浏览器可能由于隐私设置、使用HTTPS跳转HTTP、或浏览器兼容性问题而不发送Referer导致合法请求被拒绝误杀。其次正如我们演示的攻击者可能通过同域的其他漏洞绕过。因此Referer检查只能作为辅助手段绝不能作为唯一的防线。3.3 High级别挑战CSRF Token机制漏洞分析High级别使用了CSRF Token进行防护。这是目前业界最推荐的防御方案之一。其原理是用户访问密码修改页面时服务器生成一个随机、不可预测的Token令牌将其放在表单的一个隐藏域input typehidden中同时可能在Session里也存一份。用户提交表单时必须将这个Token一并提交。服务器收到请求后比对提交的Token和Session中存储的Token是否一致。只有一致才认为是合法请求。这样一来攻击者无法预先知道这个Token的值因此无法构造出合法的请求。攻击步骤实录观察Token机制将DVWA设为High安全级别打开CSRF页面。查看页面源代码你会发现表单中多了一个隐藏的输入框input typehidden nameuser_token valuea1b2c3d4e5f6g7h8i9j0...一长串随机字符 /每次刷新页面这个value的值都会变化。同时用Burp Suite抓包会发现提交请求时这个user_token参数也被发送了。直接攻击的失败尝试像前两个级别一样直接构造一个静态的恶意页面由于无法获得当前有效的Token攻击会失败。服务器会返回错误或直接忽略请求。理论上的复合攻击要突破High级别的防护攻击者需要解决“获取Token”的问题。这通常需要结合其他漏洞最常见的是XSS跨站脚本攻击。攻击思路如果网站同时存在一个XSS漏洞比如反射型XSS攻击者可以构造一个特殊的URL诱使用户点击。这个URL中的XSS脚本会先向真实的密码修改页面发起一个请求从返回的HTML中解析出当前的CSRF Token然后再用这个Token自动构造一个修改密码的POST请求并提交。模拟过程这需要更复杂的攻击页面和JavaScript代码本质上是通过XSS在用户浏览器中“借来”一个合法的Token。DVWA的High级别CSRF模块本身是坚固的旨在演示“正确的Token防护可以抵御纯CSRF攻击”。要攻破它你必须先找到或利用另一个漏洞如XSS来获取Token这证明了安全是一个整体一处短板可能导致全线崩溃。实操心得实现CSRF Token时务必保证其随机性使用安全的随机数生成器、唯一性每个会话或每个表单唯一和机密性不能通过非预期的方式泄露如通过XSS。Token应该放在表单隐藏域或自定义HTTP头中而不是Cookie里。同时Token验证失败后应该使当前会话的Token立即失效防止重放攻击。4. 从攻击到防御构建坚不可摧的CSRF防护体系了解了攻击手段我们最终的目的是为了防御。一套健壮的CSRF防护体系应该是多层次的。4.1 防御策略一同源检测Origin/Referer Header Check这是一种“询问来源”的防御方式。服务器检查请求头中的Origin或Referer字段判断请求是否来自可信的源即自己的网站。Origin Header更可靠它告诉服务器请求发自哪个站点协议域名端口且不会被跨域请求携带除了IE11等特例。对于POST请求和跨域AJAX请求浏览器会自动添加。Referer Header信息更全包含了完整的路径但存在隐私泄露风险且用户可能禁用它。在HTTPS-HTTP的跳转中会被剥离。实施要点与坑不要单独依赖Referer如前所述它可能为空、被篡改在某些古老浏览器上或被策略阻止。实施逻辑优先检查Origin如果存在且合法则通过如果不存在如IE11或302重定向则降级检查Referer如果两者都不可用对于敏感操作应当拒绝或要求二次验证如输入密码。注意“空Referer”的合法场景用户直接从地址栏输入URL、从书签打开、或从本地文件打开网页时Referer可能为空。你需要根据业务场景判断是否允许。4.2 防御策略二CSRF Token同步器令牌模式这是目前最主流、最有效的防御方案前面High级别已经展示。最佳实践指南生成与存储使用密码学安全的随机数生成器如Java的java.security.SecureRandomPHP的random_bytes()生成足够长至少128位的Token。将Token与用户会话Session绑定存储。切勿将其输出到前端可全局访问的地方如全局JS变量。分发与携带对于需要防护的页面如表单在渲染时将Token放入表单的隐藏域。对于AJAX请求可以将Token放在页面的meta标签中由JS读取后添加到请求头如X-CSRF-TOKEN。不要放在Cookie里让JS读取这违背了同源策略的初衷。示例Thymeleaf模板form ... input typehidden th:name${_csrf.parameterName} th:value${_csrf.token} / ... /form或为AJAX设置Headervar token document.querySelector(meta[name_csrf]).getAttribute(content); var header document.querySelector(meta[name_csrf_header]).getAttribute(content); xhr.setRequestHeader(header, token);验证与销毁服务器端收到请求后从Session中取出Token与请求参数或Header中的Token进行比对。严格比较确保比对是恒定时间的constant-time comparison防止时序攻击。一次一用对于高度敏感的操作如交易、改密可以考虑每次使用后使Token失效使用后即焚并生成新的Token。但这会带来用户体验上的复杂度需权衡。验证失败处理立即使当前用户会话失效并记录安全日志因为这很可能是一次攻击尝试。分布式系统下的挑战在微服务或集群环境下用户的Session可能存储在后端的Redis等共享存储中。确保Token的生成、存储和验证都能在这个共享环境中正确访问。Token本身也可以设计成自包含的如JWT格式包含用户ID、时间戳和签名这样无需查询Session存储但需注意Token的撤销问题。4.3 防御策略三双重Cookie验证这是一种“利用攻击者拿不到Cookie”这一特点的简化方案。思路是让前端从Cookie中读取一个自定义的Token值如csrf_tokenv8g9e4ksfhw然后在发起请求时以参数或Header的形式将其带给后端后端验证Cookie中的值和参数中的值是否一致。优点实现简单前后端改动小无需Session存储。致命缺点Cookie可能被其他子域XSS攻击设置或修改。如果主域名a.com下设置了Cookie那么其子域blog.a.com如果存在XSS漏洞攻击者可以通过document.cookie来修改主域Cookie从而伪造Token。违背了“Cookie不应被前端脚本读取”的安全最佳实践。这增加了XSS攻击成功后窃取Token的风险虽然CSRF本身不依赖XSS但防护措施不应引入新风险。因此双重Cookie验证方案的应用场景有限通常只在内部系统、且能确保无XSS风险、同时追求快速上线的场景下作为临时方案。长期来看应迁移至标准的CSRF Token方案。4.4 防御策略四利用现代浏览器特性——SameSite Cookie这是从Cookie层面“釜底抽薪”的方案。通过设置Cookie的SameSite属性可以指示浏览器在跨站请求时不要发送此Cookie。SameSiteStrict最严格。任何跨站请求包括从其他网站点击链接过来都不会携带此Cookie。这能完全杜绝CSRF但可能影响用户体验比如从邮件链接点回网站用户需要重新登录。SameSiteLax默认值宽松模式。允许在跨站的安全顶层导航如点击链接中携带Cookie但禁止在跨站的POST请求或iframe加载等场景中携带。这能在安全性和用户体验间取得较好平衡。SameSiteNone必须与Secure属性一同使用即仅限HTTPS表示允许跨站携带。适用于需要跨站共享登录状态的第三方服务。设置方法服务端Set-Cookie: sessionidxxxx; Path/; HttpOnly; SameSiteLax注意事项SameSite是强大的CSRF缓解措施但不能作为唯一防线。因为旧版浏览器如部分老版本Safari、UC浏览器可能不支持。它应该与CSRF Token等其他措施结合使用形成纵深防御。如果你的应用需要嵌入在第三方iframe中如支付回调需要将相关Cookie设置为SameSiteNone; Secure。4.5 防御策略五增加用户交互与二次确认对于特别敏感的操作如转账、修改核心账户信息除了技术手段增加一层用户交互是最后的也是最有效的防线。重新认证在执行操作前要求用户再次输入登录密码或支付密码。验证码要求用户输入图片或短信验证码。这不仅能防CSRF还能防自动化脚本攻击。确认对话框提供清晰的操作确认提示让用户明确知道自己将要做什么。这些方法会牺牲一部分用户体验因此需要根据操作的风险等级来权衡使用。5. 开发中的避坑指南与最佳实践结合我多年开发和审计的经验以下是一些实实在在的避坑建议和最佳实践很多是文档里不会写的“血泪教训”。5.1 前端开发注意事项严格遵循RESTful规范GET请求只用于获取数据绝不用于执行任何会产生副作用的操作修改、删除、新增。这是防止Low级别CSRF最简单也最重要的一步。谨慎处理第三方资源与用户内容对于用户提交的HTML内容如富文本评论一定要做严格的过滤和转义防止其中嵌入恶意img、script或iframe标签。设置CSP内容安全策略Header限制脚本和外部资源的加载源。AJAX请求的安全头对于重要的AJAX请求除了携带CSRF Token还可以考虑设置自定义Header如X-Requested-With: XMLHttpRequest。虽然攻击者理论上也能伪造这个头但这增加了攻击复杂度。同时后端应验证该Header的存在。避免使用GET进行重定向不要使用window.location.href或a标签的GET请求来执行状态变更操作。例如a href/logout退出登录/a可能被攻击者利用img src/logout来让用户意外登出。退出登录应该用POST表单提交。5.2 后端开发注意事项框架优先使用成熟的Web开发框架如Spring Security、Django、Laravel、Express.js的csurf中间件等。它们通常内置了开箱即用、经过充分测试的CSRF防护机制。不要自己重复造轮子尤其是安全相关的轮子。Token生成与验证必须服务端完成Token的生成、存储、比对逻辑必须完全在服务端控制。前端只负责接收和回传。绝对不要将生成算法或密钥泄露到前端。区分“状态变更”与“数据查询”接口对所有会修改服务器状态写数据库、发邮件、改配置的接口无论其HTTP方法是什么即使是POST、PUT、DELETE都必须实施CSRF防护。对于纯数据查询的接口可以根据情况放宽。注意JSON API的防护对于接收application/json格式的APICSRF Token不能放在请求体中因为攻击者可以通过构造一个带有JSON体的表单来发起POST请求虽然复杂但可能。更安全的做法是将Token放在一个自定义的HTTP Header里如X-CSRF-Token因为浏览器同源策略默认禁止跨域站点设置自定义Header。防御“登录CSRF”CSRF不仅可以攻击已登录用户还可以攻击登录过程本身。攻击者可以用受害者的凭证通过CSRF登录到攻击者的账户从而窃取受害者之后在该网站上的隐私数据。防御方法是在登录表单中也加入CSRF Token并且在登录成功后务必使之前的会话失效并生成新的会话ID。5.3 测试与监控自动化测试将CSRF漏洞扫描纳入CI/CD流程。可以使用像OWASP ZAP、Burp Suite Professional的主动扫描功能或者专门针对CSRF的测试工具如CSRFTester进行定期扫描。代码审计在代码审查时重点关注所有处理POST、PUT、DELETE等方法的控制器Controller或路由Route检查是否都有CSRF防护校验。监控异常请求在网关或应用层日志中监控那些疑似CSRF的请求特征例如Content-Type为text/plain或application/x-www-form-urlencoded但Origin/Referer为空或为外域的敏感操作请求。这类请求不一定是攻击但值得安全团队关注和复查。6. 总结与个人体会走完了从原理到攻击再到防御的全程你会发现CSRF的攻防核心始终围绕着“请求的意图是否来自用户本人”这个问题展开。防御的本质就是为请求增加一个攻击者无法伪造的“身份凭证”。我个人在实际项目中的体会是防御CSRF没有银弹需要一套组合拳首选且必须的是CSRF Token它是当前最可靠、最通用的方案。在Spring Boot项目中只需添加spring-boot-starter-security依赖它就会默认开启CSRF防护省心省力。将SameSiteLax设为Cookie的默认策略。这几乎零成本地挡住了大部分由外站发起的CSRF攻击尤其是链接点击型的。对敏感操作实施二次验证。比如修改密码、转账、修改绑定邮箱强制要求输入当前密码或验证码。这是业务逻辑上的最后一道保险。永远不要忽视XSS。一个严重的XSS漏洞可以让所有基于Token和Cookie的CSRF防护形同虚设因为攻击者可以通过XSS直接窃取Token。安全是一个整体木桶的短板决定了它的容量。最后再分享一个给新手的快速自查清单当你开发一个新功能特别是涉及数据修改的接口时问自己三个问题1) 这个接口能用GET访问并执行操作吗绝对不能2) 我有没有为这个请求添加并验证CSRF Token3) 这个操作足够敏感吗是否需要用户二次确认养成这样的习惯就能在源头堵住很多安全漏洞。安全之路道阻且长。希望这篇超过五千字的详细拆解能帮你不仅看懂CSRF更能建立起实战级的攻防认知和防御习惯。记住最好的防御始于对攻击的深刻理解。