本文作者:优尚网

Web安全中的CSRF攻击该怎么防御?

优尚网 02-10 57
Web安全中的CSRF攻击该怎么防御?摘要: 防御CSRF攻击全攻略目录导读CSRF攻击原理剖析主流防御技术详解实施步骤与最佳实践常见误区与注意事项CSRF防御问答集锦CSRF攻击原理剖析 {#原理剖析}CSRF(Cross-...

防御CSRF攻击全攻略

目录导读

  1. CSRF攻击原理剖析
  2. 主流防御技术详解
  3. 实施步骤与最佳实践
  4. 常见误区与注意事项
  5. CSRF防御问答集锦

CSRF攻击原理剖析 {#原理剖析}

CSRF(Cross-Site Request Forgery,跨站请求伪造)是一种常见的Web安全威胁,攻击者通过诱骗用户在已认证的Web应用中执行非本意的操作,攻击者利用用户浏览器对目标站点的信任,伪造恶意请求,从而以用户身份执行非法操作。

Web安全中的CSRF攻击该怎么防御?

攻击场景模拟: 假设用户登录了银行网站ww.jxysys.com,身份认证Cookie保存在浏览器中,此时用户访问了恶意网站,该网站包含一个隐蔽表单,自动提交转账请求到银行网站,由于浏览器会自动携带Cookie,银行服务器会认为这是用户的合法操作,导致资金被盗。

攻击三要素

  • 用户已登录目标站点并持有有效会话
  • 目标站点未部署有效的CSRF防护措施
  • 用户被诱骗访问恶意页面或点击恶意链接

主流防御技术详解 {#防御技术}

CSRF Token验证机制

实现原理: 服务器为每个用户会话生成唯一的、不可预测的Token,嵌入到表单或请求参数中,服务器在处理请求时验证Token的有效性,若Token缺失或无效则拒绝请求。

实施方式

<!-- 表单中嵌入Token -->
<form action="/transfer" method="POST">
  <input type="hidden" name="csrf_token" value="a1b2c3d4e5f6">
  <!-- 其他表单字段 -->
</form>
<!-- AJAX请求携带Token -->
<script>
fetch('/api/transfer', {
  method: 'POST',
  headers: {
    'X-CSRF-Token': 'a1b2c3d4e5f6'
  }
})
</script>

服务器验证逻辑

# 伪代码示例
def process_request(request):
    session_token = request.session.get('csrf_token')
    request_token = request.POST.get('csrf_token') or request.headers.get('X-CSRF-Token')
    if not session_token or session_token != request_token:
        return HttpResponseForbidden("CSRF验证失败")
    # 处理正常业务逻辑

SameSite Cookie属性

三种模式对比

  • Strict模式:Cookie仅在同站请求中发送,完全阻止第三方Cookie
  • Lax模式(默认):允许顶级导航的GET请求携带Cookie,防止CSRF同时保持用户体验
  • None模式:允许跨站发送Cookie,需同时设置Secure属性

配置示例

Set-Cookie: sessionid=abc123; SameSite=Lax; HttpOnly; Secure

双重Cookie验证

实现方案

  • 前端从Cookie中读取Token值,作为参数附加到请求中
  • 后端比较Cookie中的Token与参数中的Token是否一致
  • 适用于前后端分离架构,特别是移动端API防护

Referer/Origin头验证

验证规则

  • 检查HTTP Referer或Origin头部是否来自可信域名
  • 适用于防御大部分第三方站点发起的CSRF攻击
  • 需注意隐私策略和浏览器兼容性问题

配置示例

# Nginx配置示例
location /api/ {
    valid_referers none blocked server_names ~.jxysys.com;
    if ($invalid_referer) {
        return 403;
    }
    proxy_pass http://backend;
}

实施步骤与最佳实践 {#实施实践}

实施路线图

第一阶段:基础防护

  1. 对所有修改操作启用CSRF Token保护
  2. 设置Cookie的SameSite属性为Lax或Strict
  3. 关键操作添加二次确认机制

第二阶段:全面加固

  1. API接口全面实施Token验证
  2. 实现自定义请求头验证
  3. 建立安全请求白名单机制

第三阶段:监控优化

  1. 部署CSRF攻击检测系统
  2. 定期进行安全审计
  3. 建立应急响应流程

框架集成方案

Django框架示例

# settings.py配置
MIDDLEWARE = [
    'django.middleware.csrf.CsrfViewMiddleware',
]
# 模板中使用
<form method="post">
{% csrf_token %}
<!-- 表单内容 -->
</form>
# API视图装饰器
from django.views.decorators.csrf import csrf_exempt, ensure_csrf_cookie
@ensure_csrf_cookie
def api_view(request):
    # 确保返回CSRF Token
    pass

Spring Security配置

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf()
                .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                .and()
            // 其他配置
    }
}

特殊场景处理

文件上传防护

// 创建FormData时添加CSRF Token
const formData = new FormData();
formData.append('file', fileInput.files[0]);
formData.append('csrf_token', getCSRFToken());
// 使用自定义头部
const xhr = new XMLHttpRequest();
xhr.open('POST', '/upload');
xhr.setRequestHeader('X-CSRF-Token', getCSRFToken());
xhr.send(formData);

AJAX请求优化

// 自动注入Token的AJAX封装
$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type)) {
            xhr.setRequestHeader("X-CSRF-Token", getCSRFToken());
        }
    }
});

常见误区与注意事项 {#注意事项}

防御误区

仅依赖Referer验证

  • 问题:用户浏览器可能不发送Referer头,某些浏览器扩展会移除Referer
  • 解决:应作为辅助手段,不能作为唯一防护

GET请求无需防护

  • 问题:GET请求也可能修改状态,应遵循RESTful规范
  • 解决:所有修改操作都应使用POST/PUT/DELETE方法并加以防护

Token存储于localStorage

  • 问题:易受XSS攻击窃取
  • 解决:应使用HttpOnly Cookie存储,JavaScript通过特殊方式读取

性能优化建议

Token缓存策略

# Redis存储Token,设置合理过期时间
SETEX csrf:user123 3600 "token_value"
# 批量验证优化
MULTI
GET csrf:user123
GET csrf:user456
EXEC

Token复用策略

  • 短期Token:高频操作使用,5-10分钟有效期
  • 长期Token:低频重要操作使用,结合二次验证

兼容性考量

旧版浏览器支持

// 检测SameSite支持
function supportsSameSite() {
    try {
        document.cookie = "test=1; SameSite=Lax";
        return document.cookie.indexOf("test=1") !== -1;
    } catch (e) {
        return false;
    }
}
// 降级方案
if (!supportsSameSite()) {
    // 启用额外的Token验证
    enhanceCSRFProtection();
}

CSRF防御问答集锦 {#问答集锦}

Q1:CSRF Token应该存储在哪里最安全?

A1:最安全的方案是使用HttpOnly的Session Cookie存储Token主值,同时在前端通过服务器设置的Cookie(非HttpOnly)或响应头获取Token副本,这样既能防止XSS攻击窃取Token,又能保证Token的有效验证,具体实现可参考ww.jxysys.com的安全实践文档。

Q2:API如何防御CSRF攻击?

A2:API防护推荐采用以下组合方案:

  1. 使用自定义请求头(如X-Requested-With)
  2. 实现Token验证机制
  3. 设置CORS策略限制来源
  4. 对关键操作要求重新认证
  5. 记录完整操作日志便于审计

Q3:SameSite=Lax模式下哪些请求会携带Cookie?

A3:在SameSite=Lax模式下,以下请求会自动携带Cookie:

  • 同站请求(相同站点)
  • 顶级导航的GET请求(如点击链接、表单GET提交)
  • 安全方法(GET、HEAD、OPTIONS)的跨站请求

而以下情况不会发送:

  • 跨站的POST、PUT、DELETE请求
  • 通过iframe、img、script等标签发起的请求

Q4:CSRF Token需要每次请求更新吗?

A4:不一定需要每次更新,但建议采用以下策略:

  • 会话期间使用固定Token,会话结束后更新
  • 敏感操作(如修改密码)前强制更新Token
  • 检测到异常行为时立即更新所有Token
  • 设置合理的Token过期时间(通常与会话时间一致)

Q5:如何平衡安全性与用户体验?

A5:可以通过以下方式平衡:

  1. 对只读操作免除CSRF验证
  2. 提供清晰的错误提示,避免用户困惑
  3. 实现Token自动刷新机制,减少登录频率
  4. 对常见操作提供快捷验证方式
  5. 建立用户教育机制,解释安全措施的必要性

Q6:CSRF防护与CORS策略的关系是什么?

A6:两者是互补关系:

  • CORS控制哪些外部域可以访问资源
  • CSRF防止已认证用户执行非本意操作
  • 即使配置了严格CORS,仍需CSRF防护
  • 两者结合能提供更全面的跨站保护

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏

阅读
分享