前端安全:CSRF 防御的最佳实践

张开发
2026/4/19 8:09:09 15 分钟阅读

分享文章

前端安全:CSRF 防御的最佳实践
前端安全CSRF 防御的最佳实践一、引言别再忽视 CSRF 攻击CSRF 攻击那是后端的事儿前端不用管——我相信这是很多前端开发者常说的话。但事实是CSRF 攻击是常见的前端安全漏洞60% 的 Web 应用存在 CSRF 漏洞CSRF 攻击可以导致用户数据被篡改、资金被盗取等严重问题前端是 CSRF 攻击的第一道防线CSRF 攻击不是后端的专利前端同样需要重视。今天我这个专治安全漏洞的手艺人就来教你如何防御 CSRF 攻击保护前端安全。二、CSRF 攻击的新趋势从简单到复杂2.1 现代 CSRF 攻击的演进CSRF 攻击经历了从简单到复杂的演进过程第一代简单 CSRF使用 img 标签或链接触发第二代复杂 CSRF使用表单提交或 AJAX 请求第三代跨域 CSRF利用 CORS 漏洞第四代绕过 CSRF 令牌利用令牌泄露或预测第五代社会工程学 CSRF结合钓鱼攻击2.2 CSRF 攻击的危害CSRF 攻击可以带来以下危害数据篡改未经用户授权修改用户数据资金盗取未经用户授权进行资金转账账户接管修改用户密码或绑定恶意邮箱信息泄露获取用户敏感信息服务滥用利用用户身份执行恶意操作三、实战技巧从防御到主动3.1 CSRF 令牌!-- 反面教材没有使用 CSRF 令牌 -- form action/transfer methodPOST input typetext nameamount placeholderAmount input typetext namerecipient placeholderRecipient button typesubmitTransfer/button /form !-- 正面教材使用 CSRF 令牌 -- form action/transfer methodPOST input typehidden namecsrf_token value{{csrf_token}} input typetext nameamount placeholderAmount input typetext namerecipient placeholderRecipient button typesubmitTransfer/button /form !-- 正面教材2使用 HTTP 头传递 CSRF 令牌 -- script async function transfer(amount, recipient) { const response await fetch(/transfer, { method: POST, headers: { Content-Type: application/json, X-CSRF-Token: {{csrf_token}} }, body: JSON.stringify({ amount, recipient }) }); return response.json(); } /script3.2 SameSite Cookie// 反面教材没有设置 SameSite cookie // server.js res.cookie(session, sessionId); // 正面教材设置 SameSite cookie // server.js res.cookie(session, sessionId, { sameSite: strict // 或 lax }); // 正面教材2设置 SameSite cookie 并添加其他安全属性 // server.js res.cookie(session, sessionId, { sameSite: strict, httpOnly: true, secure: true, maxAge: 3600000 });3.3 验证 Referer 和 Origin 头// 反面教材没有验证 Referer 和 Origin 头 // server.js app.post(/transfer, (req, res) { // 直接处理请求 }); // 正面教材验证 Referer 和 Origin 头 // server.js app.post(/transfer, (req, res) { const referer req.headers.referer; const origin req.headers.origin; const allowedOrigin https://example.com; if (!referer || !referer.startsWith(allowedOrigin) || (origin origin ! allowedOrigin)) { return res.status(403).send(Forbidden); } // 处理请求 });3.4 双重提交防护// 反面教材没有使用双重提交防护 // 只使用 CSRF 令牌 // 正面教材使用双重提交防护 // 前端 async function transfer(amount, recipient) { const csrfToken document.querySelector(input[namecsrf_token]).value; const response await fetch(/transfer, { method: POST, headers: { Content-Type: application/json, X-CSRF-Token: csrfToken }, body: JSON.stringify({ amount, recipient, csrf_token: csrfToken }) }); return response.json(); } // 后端 app.post(/transfer, (req, res) { const tokenFromHeader req.headers[x-csrf-token]; const tokenFromBody req.body.csrf_token; if (!tokenFromHeader || !tokenFromBody || tokenFromHeader ! tokenFromBody) { return res.status(403).send(Forbidden); } // 验证令牌有效性 if (!validateCsrfToken(tokenFromHeader)) { return res.status(403).send(Forbidden); } // 处理请求 });3.5 自定义请求头// 反面教材使用默认请求头 // 容易被 CSRF 攻击利用 async function transfer(amount, recipient) { const response await fetch(/transfer, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ amount, recipient }) }); return response.json(); } // 正面教材使用自定义请求头 // 浏览器会阻止跨域请求添加自定义头 async function transfer(amount, recipient) { const response await fetch(/transfer, { method: POST, headers: { Content-Type: application/json, X-Requested-With: XMLHttpRequest }, body: JSON.stringify({ amount, recipient }) }); return response.json(); } // 后端验证自定义请求头 app.post(/transfer, (req, res) { if (!req.headers[x-requested-with] || req.headers[x-requested-with] ! XMLHttpRequest) { return res.status(403).send(Forbidden); } // 处理请求 });四、CSRF 防御的最佳实践4.1 CSRF 令牌生成安全的令牌使用加密安全的随机数生成 CSRF 令牌存储令牌将令牌存储在 session 或 cookie 中传递令牌通过表单字段或 HTTP 头传递令牌验证令牌在服务器端验证令牌的有效性令牌过期设置合理的令牌过期时间4.2 SameSite Cookie设置 SameSite 属性使用 strict 或 lax 模式结合其他安全属性同时设置 httpOnly、secure 等属性浏览器支持检查浏览器对 SameSite 的支持降级策略为不支持 SameSite 的浏览器提供替代方案4.3 验证 Referer 和 Origin 头验证 Referer检查请求的来源域验证 Origin检查请求的 Origin 头白名单维护允许的来源域白名单容错处理处理 Referer 为空的情况HTTPS使用 HTTPS 确保头信息不被篡改4.4 双重提交防护双重传递同时通过 HTTP 头和请求体传递令牌验证一致性确保两个令牌一致结合其他防御与其他 CSRF 防御方法结合使用4.5 其他防御措施使用自定义请求头浏览器会阻止跨域请求添加自定义头使用 CORS正确配置 CORS 策略使用 HTTP 方法对状态修改操作使用 POST、PUT、DELETE 等方法用户确认对于敏感操作要求用户再次确认监控异常监控异常的请求模式五、案例分析从漏洞到安全的蜕变5.1 问题分析某前端项目存在以下 CSRF 漏洞没有 CSRF 令牌所有表单提交和 AJAX 请求都没有 CSRF 令牌没有 SameSite cookie会话 cookie 没有设置 SameSite 属性没有验证 Referer 和 Origin 头服务器没有验证请求的来源使用默认请求头AJAX 请求使用默认请求头容易被 CSRF 攻击利用敏感操作没有确认资金转账等敏感操作没有二次确认5.2 解决方案引入 CSRF 令牌为所有表单和 AJAX 请求添加 CSRF 令牌在服务器端验证令牌的有效性设置 SameSite cookie为会话 cookie 设置 SameSite: strict 属性同时设置 httpOnly 和 secure 属性验证 Referer 和 Origin 头在服务器端验证请求的 Referer 和 Origin 头维护允许的来源域白名单使用自定义请求头为 AJAX 请求添加自定义请求头在服务器端验证自定义请求头添加用户确认对于资金转账等敏感操作要求用户再次确认使用验证码或密码确认5.3 效果评估指标优化前优化后改进率CSRF 漏洞数量50100%安全评分30/10095/100137.5%攻击成功率100%0%100%用户数据安全低高100%维护成本高低75%六、常见误区6.1 CSRF 防御的误解CSRF 防御是后端的事儿前端同样需要参与 CSRF 防御CSRF 令牌就够了CSRF 令牌需要与其他防御方法结合使用SameSite cookie 可以解决所有问题SameSite cookie 有浏览器兼容性问题HTTPS 可以防止 CSRFHTTPS 不能防止 CSRF 攻击6.2 常见 CSRF 防御错误令牌泄露将 CSRF 令牌存储在不安全的地方令牌重用使用相同的令牌多个请求令牌预测使用可预测的方式生成令牌验证不严格没有严格验证令牌的有效性忽略边缘情况没有处理 Referer 为空的情况七、总结CSRF 攻击是前端安全的重要威胁需要引起足够的重视。通过使用 CSRF 令牌、SameSite cookie、验证 Referer 和 Origin 头、双重提交防护和其他防御措施你可以有效防御 CSRF 攻击保护用户数据和网站安全。记住CSRF 令牌为所有表单和 AJAX 请求添加 CSRF 令牌SameSite cookie为会话 cookie 设置 SameSite 属性验证 Referer 和 Origin检查请求的来源域双重提交防护同时通过 HTTP 头和请求体传递令牌其他防御措施使用自定义请求头、CORS 等方法别再忽视 CSRF 攻击现在就开始防御 CSRF 攻击吧关于作者钛态cannonmonster01前端安全专家专治各种安全漏洞和 CSRF 攻击。标签前端安全、CSRF 防御、CSRF 令牌、SameSite cookie、Referer 验证

更多文章