1. 项目概述从一次真实的渗透测试说起前段时间我参与了一个内部系统的安全评估项目。在常规的漏洞扫描和手动测试后系统看起来固若金汤常规的SQL注入、XSS似乎都被有效防御了。然而当我以普通用户身份登录在“修改邮箱”这个看似简单的功能点前停留时职业直觉告诉我这里可能有故事。我习惯性地打开了Burp Suite开始拦截请求。页面上有一个看起来随机的长字符串作为csrf_token参数随着表单一起提交。这很标准对吧几乎所有现代Web框架的默认配置都会这么做。但正是这种“标准”和“默认”往往隐藏着最容易被忽视的破绽。我决定把这个功能点当作一个微型靶场深入探究一下在Burp Suite这位“瑞士军刀”的辅助下CSRF跨站请求伪造的那些看似坚固的防御机制究竟有多少种方式可以被我们绕过。这不只是一个技术演练更是对开发者安全思维和防御策略深度的一次考验。CSRF攻击的本质在于攻击者诱骗已登录的用户浏览器向一个目标网站发送一个用户“不知情”但“已认证”的HTTP请求。而防御的核心就是让这个请求变得“不可预测”或“不可伪造”。最常见的盾牌就是CSRF Token同步令牌、双重Cookie验证如SameSite属性、验证码等。本篇文章我将以一次完整的“攻击者视角”实战带你深入这些防御机制的内核使用Burp Suite作为主要工具解析从信息收集、漏洞分析到最终绕过防御、完成攻击的完整链条。无论你是刚开始接触Web安全的新手还是想深化CSRF攻防理解的安全工程师相信这篇结合了工具实操、原理剖析和大量“踩坑”经验的解析都能给你带来实实在在的收获。2. 核心防御机制原理与Burp Suite分析准备在开始“绕过”之前我们必须彻底理解我们要面对的是什么。知己知彼百战不殆。CSRF的防御机制并非铁板一块每种方案都有其设计原理和潜在的薄弱环节。2.1 CSRF Token同步令牌机制深度拆解这是目前最主流、最被推荐的防御方式。其核心流程是服务器在用户会话建立后生成一个随机、不可预测的令牌Token将其存储在服务器端如Session中同时通过某种方式传递给客户端通常隐藏在表单的隐藏域或通过API响应返回。当客户端提交敏感请求如修改密码、转账时必须将这个Token一并提交。服务器收到请求后会校验提交的Token与服务器端存储的是否匹配且未过期。Burp Suite分析要点Token的生成与绑定使用Burp的Proxy拦截所有流量重点关注登录后的第一个GET请求如跳转到用户主页或表单页。Token可能出现在HTML表单的input typehidden namecsrf_token value...。HTTP响应头的某个自定义字段如X-CSRF-Token。JSON API的响应体中。 关键是要看这个Token是否与当前会话Session Cookie强绑定。用Burp的Repeater模块尝试用A用户的Cookie去请求B用户的表单页面看返回的Token是否不同。Token的提交与验证提交表单时拦截POST请求。Token通常作为请求参数csrf_tokenxxx或请求头X-CSRF-Token: xxx发送。用Repeater尝试删除Token参数。修改Token值为一个随机字符串。将A请求中的Token复制到B请求中使用如果B请求需要Token。 观察服务器的响应是返回一个明确的错误如“无效令牌”还是直接处理了请求明确的错误信息有助于我们理解验证逻辑。2.2 SameSite Cookie属性解析这是一个浏览器端的防御机制用于控制Cookie在跨站请求中是否会被发送。它有三个值Strict最严格浏览器只会在相同站点Same Site的请求中发送Cookie。这意味着从外部网站发起的请求如图片标签、表单提交都不会携带用户的认证Cookie从而从根本上杜绝CSRF。Lax默认值现代浏览器的默认行为。允许在顶级导航如点击链接且是安全如GET的请求中发送Cookie但阻止在跨站的POST请求或通过img、iframe等发起的请求中发送。NoneCookie可以在任何上下文中发送但必须同时设置Secure属性仅限HTTPS。Burp Suite分析要点在Proxy的历史记录或Repeater的响应详情中查看Set-Cookie头部。你会看到类似Set-Cookie: sessionidabc123; SameSiteLax; HttpOnly这样的信息。如果关键的身份认证Cookie如sessionid,JSESSIONID被设置为SameSiteStrict或Lax那么传统的通过第三方站点构造表单自动提交的CSRF攻击方式就会失效。但是这并非无懈可击我们后续会讨论绕过场景。2.3 其他辅助验证机制验证码在关键操作前要求用户输入验证码。这属于“用户交互”层面的防御强度很高但影响用户体验通常只用于极其敏感的操作如提现、修改密保邮箱。Referer/Origin校验服务器检查请求头中的Referer或Origin字段判断请求是否来源于本站。这种方式容易被绕过例如某些浏览器插件或配置可能不发送Referer或者攻击者可以寻找服务端校验逻辑的缺陷。自定义请求头通过JavaScript在发起请求时添加一个自定义Header如X-Requested-With: XMLHttpRequest。因为浏览器在发起跨站请求时默认不允许脚本添加自定义头遵循CORS策略所以这也能起到一定的防御作用。但这依赖于前端JavaScript的正确实现。实操心得在Burp中我习惯先进行“被动扫描”。用正常流程走一遍目标应用的关键功能登录、修改资料、添加好友、支付等让Burp记录下所有请求。然后在Target-Site map中右键点击目标主机选择“Compare site maps”对比不同会话下的请求差异这能快速帮你定位到哪些请求携带了动态变化的参数可能是Token以及Cookie的设置情况。这是信息收集阶段非常高效的一步。3. 靶场实战CSRF Token防御机制的四种绕过姿势现在我们进入实战环节。假设我们面对的是一个采用了CSRF Token防御的“修改用户邮箱”功能。我们的目标是在用户不知情的情况下构造一个恶意页面诱使用户访问后将其邮箱修改为攻击者控制的邮箱。靶场环境设定目标URLhttps://vuln-app.com/user/update_email正常请求POST /user/update_email HTTP/1.1 参数new_emailusernew.comcsrf_tokenserver_generated_random_stringToken来源访问GET /user/settings页面时HTML中返回。3.1 姿势一Token未绑定用户会话这是最经典的低级错误。虽然Token是随机的但服务器在验证时只检查Token是否存在且格式正确或者与一个全局的、非会话绑定的值进行比对。Burp实战步骤注册两个测试账号attacker和victim。用attacker账号登录访问设置页面用Burp拦截响应获取其CSRF Token记作Token_A。保持Burp开启用victim账号登录另一个浏览器或无痕窗口。在victim的会话中尝试提交修改邮箱请求。在Burp的Repeater中将请求中的csrf_token参数值替换为Token_A然后发送。观察结果如果服务器返回成功说明Token验证与用户会话无关。攻击者只需要获取任意一个有效Token甚至可以通过自己的账号获取就可以用于攻击所有用户。漏洞原理服务器端可能将Token存储在一个全局缓存或数据库中验证时只查询此Token是否存在而未检查Token关联的session_id。攻击者可以轻易获得一个有效Token。3.2 姿势二Token可预测或复用如果Token的生成算法存在缺陷或者Token的生命周期过长且可复用攻击者就有可能预测或重复使用Token。Burp实战步骤收集样本在Repeater中多次如10次请求GET /user/settings将每次返回的Token记录下来。分析模式将Token粘贴到文本分析工具或Burp的Sequencer模块中。观察Token是否是时间戳的简单编码如Base64编码的Unix时间戳是否是一个递增的序列是否包含用户ID等可预测信息测试复用用一个获取到的Token在Repeater中多次提交同一个修改邮箱的POST请求间隔一段时间。看Token是否在一次使用后即失效这是应有的行为还是可以多次使用。利用SequencerBurp的Sequencer是分析随机性的神器。捕获一个生成Token的请求/响应将其中的Token参数加载到Sequencer中进行“手动配置”并开始分析。它会给出该Token的熵值、字符分布等统计信息帮助判断其随机性是否足够。如果随机性很差就可能存在预测风险。漏洞原理使用不安全的随机数生成器如rand()、基于时间戳的简单算法或者没有实现Token的一次性One-Time使用机制。注意即使Token本身是随机的如果它通过GET请求的参数传递例如/action?csrf_tokenxxx那么这个Token可能会泄露在浏览历史、服务器日志、Referer头中从而被攻击者窃取。Burp可以帮你轻松发现这种错误实践。3.3 姿势三验证逻辑缺陷——Token可缺失或为空有时候服务器的验证逻辑存在分支缺陷。例如它可能只验证POST请求中的Token而对GET请求的相同操作不做验证这本身也是不安全的因为敏感操作不应使用GET。Burp实战步骤正常拦截一个带Token的POST请求在Repeater中发送确认成功。在Repeater中尝试以下变体并发送将csrf_token参数完全删除。将csrf_token参数的值设为空字符串csrf_token。将请求方法从POST改为GET并将参数移到URL中/user/update_email?new_emailattackerevil.comcsrf_token同时尝试带空Token或不带Token。观察服务器的响应。如果任何一种变体返回了成功或重定向到了成功页面那么这里就存在逻辑漏洞。漏洞原理后端代码可能存在如下的错误校验# 错误示例只检查参数是否存在未检查其值 if ‘csrf_token‘ in request.POST: # 进行验证 pass else: # 可能出于“兼容性”考虑允许某些特殊情况跳过 if request.method ‘GET‘: process_request() # 危险或者验证函数在Token为空时错误地返回了验证通过。3.4 姿势四跨域Token泄漏与提取高级这是一种需要结合其他漏洞如XSS或不当配置的绕过方式。思路是虽然攻击者无法从第三方网站直接读取目标站点的Token受同源策略保护但如果目标站点存在允许跨域请求的宽松CORS策略或者存在JSONP接口回调函数泄露敏感信息攻击者就有可能窃取到Token。Burp实战步骤探测CORS策略在Repeater中向目标敏感端点如/api/get_token或/user/settings发送一个请求并添加Origin头Origin: https://evil.com。观察响应头中是否包含Access-Control-Allow-Origin: https://evil.com或Access-Control-Allow-Origin: *。如果存在并且Access-Control-Allow-Credentials: true那么来自evil.com的脚本就可以携带用户的Cookie发起跨域请求并读取响应从而拿到Token。探测JSONP端点寻找返回数据时使用回调函数的接口例如/api/user_info?callbackprocessData。尝试修改callback参数如果服务器未对回调函数名做严格过滤可能造成数据泄露。虽然现代应用较少但在一些老系统中仍可能存在。结合XSS如果目标站点存在一个存储型XSS漏洞攻击者可以注入一段JavaScript该脚本在受害者浏览器中执行时可以读取同一站点下的Token因为同源然后将其发送到攻击者控制的服务器。这是CSRF Token防御被XSS“从内部攻破”的典型场景。漏洞原理Access-Control-Allow-Origin: *加上Access-Control-Allow-Credentials: true是一个危险的组合。它意味着任何网站都可以通过前端脚本发起携带凭证Cookie的跨域请求来读取此接口的数据。如果这个接口恰好返回了CSRF Token那么防御就形同虚设。4. 针对SameSite Cookie与双重验证的绕过思路当Token防御被加固后我们可能会遇到结合了SameSite Cookie或二次确认的防御。4.1 绕过SameSite Lax限制SameSiteLax是当前浏览器的默认行为它阻止了在跨站POST请求中发送Cookie但允许在顶级导航的GET请求中发送。绕过手法利用302跳转攻击者可以在自己的恶意站点上设置一个指向目标敏感操作的GET请求链接例如a href”https://vuln-app.com/user/delete_account?confirm1“点击抽奖/a。如果删除账户的操作错误地使用了GET方法且仅依赖Cookie认证那么用户点击链接后浏览器会发起一个跨站的GET请求并且因为这是顶级导航Lax策略下的Cookie会被发送请求得以执行。寻找GET型敏感操作这就是为什么绝对不要用GET方法执行写操作增删改的核心原因。用Burp扫描整个站点关注所有GET请求特别是那些带有明显操作语义的参数如?actiondeleteid1,?amount100toattacker。如果找到这就是一个潜在的CSRF漏洞且不受SameSiteLax影响。Burp辅助排查使用Burp的Scanner进行主动扫描它通常能识别出使用不安全方法如GET进行状态更改的端点。4.2 绕过双重验证验证码、二次密码对于要求输入验证码或二次密码的操作传统的CSRF难以直接绕过因为需要用户交互。但攻击思路可以转变界面伪装Clickjacking - 点击劫持虽然不能绕过验证码但可以诱骗用户“帮助”完成验证。攻击者创建一个恶意页面通过iframe透明层覆盖在目标网站的功能页面上。用户以为自己点击的是恶意页面上的“按钮”如“观看视频”实际上点击的是下方透明iframe中的“确认修改”按钮和验证码输入区域。这需要目标页面未设置有效的X-Frame-Options或Content-Security-Policyframe-ancestors指令来防止被嵌入。逻辑绕过验证码或二次密码的校验逻辑可能存在缺陷。例如验证码一次有效多次使用用Burp的Repeater重放带有验证码的请求看是否可重复成功。验证码与操作分离先在一个请求中提交验证码获取一个“临时凭证”再用另一个请求凭“临时凭证”执行操作。如果攻击者能通过CSRF触发获取“临时凭证”的请求可能不需要验证码然后再用另一个CSRF或结合其他手段使用这个凭证就可能完成攻击。验证码可空或默认值类似Token的逻辑缺陷发送空验证码或一个像0000这样的默认值试试。Burp实战对于验证码重点关注其session绑定。用两个不同的Burp会话或两个浏览器同时操作看A会话获取的验证码能否在B会话中使用。同时测试验证码的失效策略时间、次数。5. 利用Burp Suite高效构造与测试CSRF攻击向量手动分析漏洞后我们需要构造攻击证明PoC。Burp Suite提供了强大的工具来自动化和辅助这个过程。5.1 使用Engagement tools-Generate CSRF PoC这是Burp最直接的功能。当你拦截或从历史记录中找到一条目标请求例如修改邮箱的POST请求时右键点击它选择Engagement tools-Generate CSRF PoC。Burp会自动生成一个HTML表单包含了原请求的所有参数包括Token如果你在测试未验证Token的场景需要手动在Burp中删掉Token参数再生成。关键调整自动提交脚本生成的PoC默认包含一个JavaScript脚本在页面加载时自动提交表单。这对于演示漏洞非常有效。隐藏iframe技巧为了更隐蔽你可以修改PoC将表单放在一个不可见的iframe中提交避免页面跳转引起用户警觉。处理重定向如果操作成功后服务器返回302重定向你可能需要在PoC中添加target”_blank”或使用iframe来避免离开恶意页面。测试将生成的HTML代码保存为.html文件在浏览器中打开确保浏览器已登录目标网站观察操作是否被执行。务必在授权测试的环境中进行5.2 使用Intruder进行Token暴力破解与枚举测试如果怀疑Token存在可预测性Intruder模块是你的不二之选。定位参数将目标请求发送到Intruder。选择攻击类型对于Token猜测通常使用“Sniper”或“Battering ram”模式将csrf_token参数标记为Payload位置。配置Payload简单列表如果你通过信息收集猜测Token可能是时间戳如1625097600可以生成一个时间范围列表作为Payload。自定义迭代器如果Token有固定格式如用户ID_时间戳_MD5可以使用“迭代器”组合多个Payload集来生成猜测值。从文件加载如果你通过其他途径如信息泄露获取了一批可能的Token可以将其导入。设置重定向由于CSRF攻击通常会导致状态改变建议在Intruder的Options标签页中将“Redirections”设置为“Always”。这样Burp会自动跟随重定向让你能看到最终的操作结果页面。结果分析发起攻击后根据HTTP状态码、响应长度和内容来筛选成功的请求。一个成功的CSRF攻击请求其响应可能与初始的“无效Token”错误响应截然不同。5.3 使用Scanner进行自动化CSRF漏洞探测Burp的主动扫描引擎能够自动识别潜在的CSRF漏洞。配置扫描在Target-Site map中右键点击你的目标主机或分支选择“Actively scan this branch”。关注报告扫描完成后查看Dashboard或Target-Site map中的问题列表。Burp通常会标记出“Cross-site request forgery”问题。理解局限性自动扫描器主要通过检查请求中是否缺少常见的反CSRF令牌参数如csrf_token,authenticity_token来推断它无法理解复杂的业务逻辑和Token绑定关系。因此扫描器报告的可能漏洞需要手动复核用我们前面讲的方法而扫描器没报的也不代表绝对安全。它只是一个高效的初筛工具。6. 防御加固建议与安全开发备忘作为攻击的另一方面我们更应该思考如何构建难以绕过的防御。以下是一些给开发者的核心建议你可以将其视为一份安全检查清单1. 正确实施CSRF Token强随机性使用密码学安全的随机数生成器如Java的java.security.SecureRandomPython的os.urandom或secrets.token_urlsafe。会话绑定Token必须与用户会话唯一关联。存储在服务器端Session中。一次性使用每个Token应在验证后立即失效。对于高敏感操作可以考虑每个请求使用新Token。安全传输Token应通过安全通道HTTPS传输。避免通过URL参数GET传递应放在表单隐藏域或自定义HTTP头中。同源校验可以考虑验证请求的Origin或Referer头作为辅助手段但不能作为唯一依赖。2. 善用SameSite Cookie属性对于身份认证Cookie至少设置为SameSiteLax。对于仅用于会话管理且无需在第三方上下文使用的Cookie可考虑SameSiteStrict。设置HttpOnly属性防止XSS窃取Cookie。设置Secure属性确保仅通过HTTPS传输。3. 敏感操作强制使用POST等非幂等方法严格遵守HTTP语义。GET请求用于获取资源不应产生副作用Side Effects。所有写操作创建、更新、删除必须使用POST、PUT、PATCH、DELETE方法。4. 增加用户交互屏障对于关键操作如转账、修改密码、解绑设备强制要求输入登录密码、支付密码或验证码进行二次确认。注意实现逻辑确保验证码与当前操作、当前会话强绑定且一次有效。5. 实施额外的安全头部X-Frame-Options: DENY或Content-Security-Policy: frame-ancestors ‘none‘来有效防御点击劫持从而保护二次验证环节不被透明层覆盖。谨慎配置CORS。除非必要不要设置Access-Control-Allow-Origin: *且Allow-Credentials: true。应明确指定可信的源。6. 定期安全审计与测试将CSRF测试纳入常规安全测试流程。使用Burp Suite等工具进行手动和自动化的测试。进行代码审计重点检查Token生成、存储、验证的逻辑以及敏感操作的接口定义。在我多年的测试经验中最坚固的防御往往是“深度防御”Defense in Depth——不依赖单一机制。例如“CSRF Token SameSiteLax Cookie 敏感操作强制POST”的组合能极大地提高攻击门槛。同时保持对安全动态的关注因为浏览器安全策略和攻击技术都在不断演进。例如随着Chrome等浏览器逐步将SameSiteLax设为默认许多旧的CSRF攻击方式会自然失效但这绝不意味着开发者可以高枕无忧逻辑漏洞和配置错误永远存在而这正是安全测试者需要深耕的地方。