跨站请求伪造(CSRF):原理、攻击与防御全解析

目录

引言:为何登录银行后浏览一个论坛可能让资金被盗?

第一章:CSRF的本质与核心概念

什么是CSRF?

核心特征:

与其他攻击的区别:

第二章:CSRF的攻击原理与流程

攻击三要素:

经典攻击流程:

浏览器自动携带Cookie的机制:

第三章:CSRF的攻击类型与技术实现

[1. GET型CSRF](#1. GET型CSRF)

[2. POST型CSRF](#2. POST型CSRF)

[3. 复杂CSRF(JSON/XML)](#3. 复杂CSRF(JSON/XML))

第四章:真实世界CSRF攻击案例

[案例1:GitHub CSRF漏洞(2018)](#案例1:GitHub CSRF漏洞(2018))

[案例2:Netflix CSRF(2013)](#案例2:Netflix CSRF(2013))

案例3:YouTube点赞/订阅CSRF

案例4:路由器CSRF攻击

第五章:CSRF防御的完整方案

防御层1:令牌验证(最有效方案)

同步令牌模式

双重Cookie验证

[防御层2:SameSite Cookie属性](#防御层2:SameSite Cookie属性)

三种模式:

防御层3:来源验证

检查Referer/Origin头部

防御层4:自定义请求头

防御层5:用户交互验证

重新认证

CAPTCHA验证

二次确认

第六章:现代框架的CSRF防护

[1. Django的CSRF中间件](#1. Django的CSRF中间件)

[2. Spring Security的CSRF防护](#2. Spring Security的CSRF防护)

[3. Express.js的csurf中间件](#3. Express.js的csurf中间件)

[4. React + 现代API的防护](#4. React + 现代API的防护)

第七章:CSRF检测与测试方法

手动测试流程:

自动化测试工具:

测试注意事项:

第八章:特殊场景与边缘案例

[1. 子域CSRF攻击](#1. 子域CSRF攻击)

[2. 登录CSRF](#2. 登录CSRF)

[3. JSON CSRF与CORS](#3. JSON CSRF与CORS)

[4. 混合内容与协议降级](#4. 混合内容与协议降级)

第九章:CSRF防护最佳实践总结

必须实施的措施:

推荐增强措施:

按风险等级分层防护:

技术栈特定建议:

传统Web应用(服务端渲染):

SPA单页应用:

移动应用/原生应用:

第十章:未来趋势与演进

[1. SameSite Cookie的普及](#1. SameSite Cookie的普及)

[2. 基于机制而非令牌的新方案](#2. 基于机制而非令牌的新方案)

[3. 联邦学习与行为分析](#3. 联邦学习与行为分析)

[4. WebAuthn与无密码认证](#4. WebAuthn与无密码认证)

[5. 标准化协议增强](#5. 标准化协议增强)

结论:CSRF在2024年的现状


引言:为何登录银行后浏览一个论坛可能让资金被盗?

想象一个场景:您刚刚登录了网上银行,在另一个标签页打开了一个看似正常的论坛。论坛中隐藏着一张图片,当您的浏览器加载它时,悄无声息地向银行发送了一个转账请求。因为您已经登录,银行认为这是您的合法操作------资金就这样不翼而飞。这就是CSRF攻击的典型危害:利用用户已建立的信任会话,在用户不知情的情况下执行恶意操作。


第一章:CSRF的本质与核心概念

什么是CSRF?

跨站请求伪造(CSRF,也写作XSRF) 是一种Web安全漏洞,攻击者诱使已认证用户在不知情、未授权的情况下,以该用户的身份执行非本意的操作。

核心特征:

  1. 利用已建立的信任 :浏览器与目标网站间的有效会话

  2. 用户无感知:攻击发生在后台,用户可能完全不知情

  3. 请求来自合法用户:目标网站看到的是真实用户的合法请求

  4. 攻击者无需获取响应:通常只关心请求是否成功执行

与其他攻击的区别:

特性 CSRF XSS
目标 利用用户的身份执行操作 在用户浏览器执行脚本
所需条件 用户已登录目标站点 网站存在可注入点
攻击者视角 关注请求执行 关注脚本执行结果
典型危害 转账、改密、发帖 窃取Cookie、键盘记录

第二章:CSRF的攻击原理与流程

攻击三要素:

  1. Cookie-based会话:目标网站使用Cookie管理会话

  2. 无防伪验证:关键操作不验证请求来源

  3. 可预测请求:攻击者能构造出有效请求

经典攻击流程:

text

复制代码
1. 用户登录银行网站(example-bank.com)
   → 获得会话Cookie:sessionid=abc123

2. 用户访问攻击者控制的恶意网站
   → 页面包含隐藏表单或自动提交脚本

3. 浏览器自动发送请求到银行
   → 携带用户的合法Cookie:sessionid=abc123

4. 银行验证Cookie有效
   → 执行转账操作,资金转到攻击者账户

浏览器自动携带Cookie的机制:

http

复制代码
# 登录时银行设置Cookie
Set-Cookie: sessionid=abc123; Domain=.example-bank.com; Path=/

# 之后所有向example-bank.com的请求都会自动包含
Cookie: sessionid=abc123

第三章:CSRF的攻击类型与技术实现

1. GET型CSRF

最简单直接的攻击方式,通常通过<img><iframe>等标签自动触发。

示例攻击代码:

html

复制代码
<!-- 恶意网站中的隐藏图片 -->
<img src="https://example-bank.com/transfer?to=attacker&amount=10000" 
     width="0" height="0" alt="">

<!-- 或通过iframe -->
<iframe src="https://example-bank.com/delete-account" 
        style="display:none;"></iframe>

特点:

  • 利用浏览器自动加载资源的特性

  • 用户只需访问恶意页面即可触发

  • 适用于执行幂等操作(如查询、删除)

2. POST型CSRF

通过表单自动提交实现,可发送更多数据。

示例攻击代码:

html

复制代码
<!-- 隐藏表单 + 自动提交脚本 -->
<form id="csrf-form" 
      action="https://example-bank.com/transfer" 
      method="POST"
      style="display:none;">
  <input type="hidden" name="to" value="attacker">
  <input type="hidden" name="amount" value="10000">
  <input type="hidden" name="currency" value="USD">
</form>

<script>
  document.getElementById('csrf-form').submit();
</script>

3. 复杂CSRF(JSON/XML)

现代API常用JSON格式,需要特殊处理。

技术难点: 简单表单无法直接发送JSON
绕过方法:

html

复制代码
<script>
  // 通过Fetch API发送JSON请求
  fetch('https://api.example.com/update-profile', {
    method: 'PUT',
    credentials: 'include',  // 携带Cookie
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      email: 'attacker@evil.com',
      is_admin: true
    })
  });
</script>

条件限制:

  • 需要CORS配置允许恶意网站

  • 或通过Flash等插件绕过限制(已逐渐淘汰)


第四章:真实世界CSRF攻击案例

案例1:GitHub CSRF漏洞(2018)

  • 漏洞点:仓库设置页面

  • 攻击方式:恶意页面诱导用户点击后,自动修改仓库设置

  • 危害:攻击者可获取仓库控制权

  • 修复:GitHub增加了CSRF令牌验证

案例2:Netflix CSRF(2013)

  • 漏洞:账户添加配送地址功能

  • 攻击:通过CSRF添加攻击者地址到用户账户

  • 利用:获取用户物理地址信息,可能用于社会工程学攻击

案例3:YouTube点赞/订阅CSRF

  • 历史漏洞:早期YouTube通过简单GET请求处理订阅操作

  • 攻击代码

    html

    复制代码
    <img src="https://youtube.com/subscribe?channel=attacker_channel">
  • 影响:用户访问恶意页面后自动订阅攻击者频道

案例4:路由器CSRF攻击

最具破坏性的应用场景之一:

html

复制代码
<!-- 重置路由器为出厂设置 -->
<form action="http://192.168.1.1/reset" method="POST">
  <input type="hidden" name="confirm" value="true">
</form>
<script>document.forms[0].submit();</script>

<!-- 修改DNS设置 -->
<form action="http://192.168.1.1/set-dns" method="POST">
  <input type="hidden" name="dns1" value="8.8.8.8">
  <input type="hidden" name="dns2" value="8.8.4.4">
</form>

后果: 完全控制局域网流量,可进行中间人攻击。


第五章:CSRF防御的完整方案

防御层1:令牌验证(最有效方案)

同步令牌模式

python

复制代码
# 服务器端生成令牌
def generate_csrf_token(user_session):
    token = random_string(32)
    session['csrf_token'] = token
    return token

# 在表单中嵌入
<form action="/transfer" method="POST">
  <input type="hidden" name="csrf_token" 
         value="{{ csrf_token }}">
  <!-- 其他字段 -->
</form>

# 服务器验证
def validate_csrf(request):
    token_in_session = session.get('csrf_token')
    token_in_request = request.form.get('csrf_token')
    return token_in_session == token_in_request
双重Cookie验证

javascript

复制代码
// 前端设置自定义请求头
fetch('/api/transfer', {
  method: 'POST',
  headers: {
    'X-CSRF-Token': getCookie('csrf_token')
  }
});

// 服务器验证
app.post('/api/transfer', (req, res) => {
  const tokenInCookie = req.cookies.csrf_token;
  const tokenInHeader = req.headers['x-csrf-token'];
  
  if (tokenInCookie && tokenInCookie === tokenInHeader) {
    // 请求合法
  } else {
    // 拒绝请求
  }
});

防御层2:SameSite Cookie属性

三种模式:

http

复制代码
# 严格模式 - 完全禁止跨站携带
Set-Cookie: sessionid=abc123; SameSite=Strict

# 宽松模式 - GET请求可跨站携带(推荐平衡方案)
Set-Cookie: sessionid=abc123; SameSite=Lax

# 无限制 - 默认行为,不推荐
Set-Cookie: sessionid=abc123; SameSite=None; Secure

SameSite=Lax的实际效果:

  • ✅ 允许:从其他网站点击链接、GET表单提交

  • ❌ 阻止:跨站POST表单提交、Fetch API请求

防御层3:来源验证

检查Referer/Origin头部

python

复制代码
def check_referer(request):
    referer = request.headers.get('Referer')
    origin = request.headers.get('Origin')
    
    # 允许来自同一源站或受信任源
    allowed_origins = ['https://example.com', 'https://trusted.example.com']
    
    if origin in allowed_origins:
        return True
    
    # 验证Referer
    if referer and referer.startswith('https://example.com/'):
        return True
        
    return False

局限性:

  • 某些浏览器可能不发送Referer

  • 用户可能禁用Referer

  • 从HTTPS到HTTP的请求不包含Referer

防御层4:自定义请求头

原理: 利用CORS的简单请求/预检请求机制

javascript

复制代码
// 所有敏感请求添加自定义头
axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

// 或使用自定义头
fetch('/api/sensitive-action', {
  headers: {
    'X-Custom-Header': 'csrf-protection'
  }
});

优势:

  • 浏览器对非简单请求会发送预检请求

  • 攻击者无法通过简单HTML表单添加自定义头

防御层5:用户交互验证

重新认证
  • 关键操作前要求重新输入密码

  • 示例:转账、修改邮箱、修改密码

CAPTCHA验证
  • 在执行敏感操作前要求完成人机验证

  • 有效但影响用户体验

二次确认

javascript

复制代码
// 前端确认
if (confirm('确认要转账10000元吗?')) {
  // 发送请求
}

第六章:现代框架的CSRF防护

1. Django的CSRF中间件

python

复制代码
# settings.py
MIDDLEWARE = [
    'django.middleware.csrf.CsrfViewMiddleware',
]

# 模板中使用
<form method="post">
  {% csrf_token %}
  <!-- 表单字段 -->
</form>

# AJAX请求
const csrftoken = document.querySelector('[name=csrfmiddlewaretoken]').value;
fetch('/api/endpoint', {
  method: 'POST',
  headers: {
    'X-CSRFToken': csrftoken
  }
});

2. Spring Security的CSRF防护

java

复制代码
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf()  // 默认启用CSRF保护
            .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
    }
}

// Thymeleaf模板中自动添加令牌
<form th:action="@{/transfer}" method="post">
    <input type="hidden" name="_csrf" th:value="${_csrf.token}"/>
</form>

3. Express.js的csurf中间件

javascript

复制代码
const csrf = require('csurf');
const csrfProtection = csrf({ cookie: true });

// 应用中间件
app.use(csrfProtection);

// 获取令牌
app.get('/form', (req, res) => {
  res.render('form', { csrfToken: req.csrfToken() });
});

// 验证令牌
app.post('/process', csrfProtection, (req, res) => {
  // 只有有效CSRF令牌能到达这里
});

4. React + 现代API的防护

javascript

复制代码
// 使用HTTP-only Cookie + 双重提交
import axios from 'axios';

// 从Cookie读取CSRF令牌(需服务器设置为非HTTP-only)
function getCsrfToken() {
  return document.cookie
    .split('; ')
    .find(row => row.startsWith('csrf_token='))
    ?.split('=')[1];
}

// 设置拦截器
axios.interceptors.request.use(config => {
  if (['post', 'put', 'patch', 'delete'].includes(config.method)) {
    config.headers['X-CSRF-Token'] = getCsrfToken();
  }
  return config;
});

第七章:CSRF检测与测试方法

手动测试流程:

  1. 识别敏感操作

    • 用户资料修改

    • 密码/邮箱变更

    • 金融交易

    • 管理操作

  2. 检查防护机制

    http

    复制代码
    # 检查响应头
    Set-Cookie: sessionid=xxx; HttpOnly; Secure; SameSite=Strict
    
    # 检查表单中的CSRF令牌
    <input type="hidden" name="csrf_token" value="...">
  3. 构造攻击POC

    html

    复制代码
    <!-- 简单GET请求测试 -->
    <img src="https://target.com/delete?id=123">
    
    <!-- POST请求测试 -->
    <form action="https://target.com/transfer" method="POST" id="csrf">
      <input type="hidden" name="amount" value="1000">
      <input type="hidden" name="to" value="attacker">
    </form>
    <script>document.getElementById('csrf').submit();</script>

自动化测试工具:

  • Burp Suite Professional:CSRF扫描器

  • OWASP ZAP:自动CSRF检测

  • CSRF Tester浏览器扩展:手动生成测试用例

测试注意事项:

  1. 会话状态:测试时需保持有效登录会话

  2. 令牌复杂性:检查令牌是否可预测或复用

  3. API端点:RESTful API也需要CSRF防护

  4. 移动端/桌面应用:检查不同客户端的防护一致性


第八章:特殊场景与边缘案例

1. 子域CSRF攻击

场景: app.example.comuser.example.com 共享Cookie
攻击:evil.example.com发起的攻击可能成功
防御: 严格设置Cookie的Domain和Path属性

2. 登录CSRF

原理: 攻击者先让用户登录攻击者账户
危害: 用户数据泄露给攻击者
示例:

html

复制代码
<form action="https://target.com/login" method="POST">
  <input type="hidden" name="username" value="attacker">
  <input type="hidden" name="password" value="attacker_pass">
</form>
<script>document.forms[0].submit();</script>

3. JSON CSRF与CORS

现代挑战:

javascript

复制代码
// 恶意网站
fetch('https://api.target.com/update', {
  method: 'POST',
  credentials: 'include',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ "admin": true })
});

防护方案:

  • 严格CORS策略

  • 要求自定义请求头

  • 验证Content-Type

4. 混合内容与协议降级

HTTPS → HTTP的CSRF

  • 现代浏览器已加强防护

  • 但仍需确保全站HTTPS


第九章:CSRF防护最佳实践总结

必须实施的措施:

  1. 关键操作使用POST/PUT/DELETE而非GET

  2. 为会话Cookie设置SameSite属性(至少Lax)

  3. 实施CSRF令牌验证(同步令牌模式)

  4. 敏感操作要求重新认证

推荐增强措施:

  1. 🌟 双重提交Cookie模式:前后端分离架构的优选

  2. 🌟 自定义请求头验证:结合CORS预检请求

  3. 🌟 操作日志与异常监控:及时发现攻击尝试

  4. 🌟 定期安全测试:包括CSRF专项测试

按风险等级分层防护:

操作风险等级 防护措施
高风险 (转账、改密) CSRF令牌 + SameSite=Strict + 重新认证
中风险 (发帖、评论) CSRF令牌 + SameSite=Lax
低风险 (查询、浏览) SameSite=Lax(可选)

技术栈特定建议:

传统Web应用(服务端渲染):
  • 框架内置的CSRF中间件

  • 每个表单包含CSRF令牌

  • SameSite Cookie + HttpOnly

SPA单页应用:
  • 双重Cookie验证模式

  • 令牌存储在非HTTP-only Cookie中

  • 通过拦截器自动附加到请求

  • 严格CORS配置

移动应用/原生应用:
  • 使用Bearer Token而非Cookie

  • 每个请求携带访问令牌

  • 令牌存储在安全存储区


第十章:未来趋势与演进

1. SameSite Cookie的普及

  • Chrome 80+默认将无SameSite标记的Cookie视为Lax

  • 推动全行业采用SameSite属性

2. 基于机制而非令牌的新方案

  • Origin-Based防护:严格验证请求来源

  • 用户交互证明:要求用户交互(如点击)后才允许敏感操作

3. 联邦学习与行为分析

  • 分析用户正常行为模式

  • 检测异常请求时序和来源

4. WebAuthn与无密码认证

  • 生物识别/硬件密钥认证

  • 从根本上改变身份验证模型

5. 标准化协议增强

  • 新的HTTP头部提案

  • 浏览器内置防护机制强化


结论:CSRF在2024年的现状

CSRF作为经典的Web安全漏洞,在防护措施日益完善的今天,大规模自动化攻击已大幅减少。但并未消失:

  1. 防护不完全的遗留系统仍然存在风险

  2. 新型API和架构可能引入新的攻击面

  3. 用户教育缺失导致社交工程结合CSRF仍然有效

最核心的防御哲学仍然是:

"Never trust a request just because it comes with a valid session cookie."

在现代Web开发中,CSRF防护应作为基础安全基线的一部分,而不是事后考虑。通过框架内置防护、安全配置和深度防御策略,可以以较低成本实现强大的CSRF防护,保护用户免受这种"隐秘而危险"的攻击。

相关推荐
差点GDP1 小时前
模拟请求测试 Fake Rest API Test
前端·网络·json
刘一说2 小时前
Nacos 权限控制详解:从开源版 v2.2+ 到企业级安全实践
spring boot·安全·spring cloud·微服务·nacos·架构·开源
buyutang_2 小时前
Linux 网络编程:深度理解网络字节序与主机字节序、大端字节序与小端字节序
linux·运维·网络
姓蔡小朋友2 小时前
Redis网络I/O模型
网络·数据库·redis
量子物理学3 小时前
openssl自建CA并生成自签名SSL证书
网络·网络协议·ssl
成空的梦想3 小时前
除了加密,它还能验明正身:SSL如何防范网络钓鱼?
网络·https·ssl
honsor4 小时前
精准监测 + 实时传输!网络型温湿度传感器,筑牢环境数据管理防线
网络·物联网
专家大圣5 小时前
远程调式不复杂!内网服务器调试用对工具很简单
运维·服务器·网络·内网穿透·cpolar
飞飞传输6 小时前
选对国产FTP服务器,筑牢数据传输安全防线,合规高效双达标
大数据·运维·安全