CSRF攻击与防御详解
字数 904 2025-11-04 20:48:20
CSRF攻击与防御详解
一、知识点描述
CSRF(Cross-Site Request Forgery,跨站请求伪造)是一种恶意攻击,攻击者诱骗已登录受信任网站的用户在不知情的情况下执行非本意的操作。与XSS利用用户对网站的信任不同,CSRF利用网站对用户浏览器的信任。
二、攻击原理详解
1. 攻击前提条件
- 用户已登录目标网站(存在有效会话Cookie)
- 用户访问了攻击者构造的恶意页面
- 目标网站没有有效的CSRF防护措施
2. 典型攻击场景示例
假设银行网站转账接口为:
POST /transfer HTTP/1.1
Host: bank.com
Cookie: sessionid=user_session_cookie
Content-Type: application/x-www-form-urlencoded
to_account=攻击者账户&amount=1000
攻击者构造的恶意页面:
<!-- 恶意页面隐藏在第三方网站 -->
<body onload="document.forms[0].submit()">
<form action="https://bank.com/transfer" method="POST">
<input type="hidden" name="to_account" value="攻击者账户">
<input type="hidden" name="amount" value="1000">
</form>
</body>
3. 攻击执行流程
- 用户登录bank.com,会话Cookie保存在浏览器
- 用户访问攻击者构造的恶意页面
- 浏览器自动提交隐藏表单,携带用户的合法Cookie
- 银行服务器验证Cookie有效,执行转账操作
三、防御措施详解
1. 验证Referer/Origin头部
- 原理:检查请求来源是否在白名单内
- 实现方式:
def check_referer(request):
referer = request.headers.get('Referer')
origin = request.headers.get('Origin')
# 允许来自bank.com的请求
if referer and 'bank.com' in referer:
return True
if origin and origin == 'https://bank.com':
return True
return False
- 局限性:某些浏览器可能不发送Referer,存在被篡改风险
2. CSRF Token防护(推荐方案)
- 原理:在表单中嵌入随机令牌,服务器验证令牌有效性
服务端实现步骤:
import secrets
class CSRFTokenMiddleware:
def generate_token(self):
return secrets.token_urlsafe(32)
def verify_token(self, request_token, session_token):
return secrets.compare_digest(request_token, session_token)
# 在渲染表单时注入Token
def render_transfer_form(request):
token = request.session.get('csrf_token')
if not token:
token = generate_token()
request.session['csrf_token'] = token
return render_template('form.html', csrf_token=token)
客户端表单示例:
<form action="/transfer" method="POST">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<input type="text" name="to_account">
<input type="number" name="amount">
<button type="submit">转账</button>
</form>
服务端验证逻辑:
def transfer_handler(request):
if request.method == 'POST':
form_token = request.POST.get('csrf_token')
session_token = request.session.get('csrf_token')
if not verify_token(form_token, session_token):
return HttpResponse('CSRF验证失败', status=403)
# 执行转账逻辑
process_transfer(request)
3. SameSite Cookie属性
- 原理:控制Cookie的发送范围,防止跨站请求携带Cookie
- 三种模式:
- Strict:完全禁止跨站携带Cookie
- Lax:允许安全方法(GET)的跨站请求
- None:不限制(需要配合Secure属性)
设置示例:
Set-Cookie: sessionid=abc123; SameSite=Lax; Secure; HttpOnly
4. 双重Cookie验证
- 原理:在请求参数和Cookie中都包含令牌,服务器验证一致性
// 前端自动添加Token参数
fetch('/api/transfer', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': getCookie('csrf_token')
},
body: JSON.stringify(data)
})
四、最佳实践总结
- 关键操作使用POST请求:避免通过GET请求修改数据
- CSRF Token为核心防护:对状态修改操作强制验证Token
- 合理设置SameSite属性:会话Cookie建议设置为SameSite=Lax
- 敏感操作二次验证:重要操作要求输入密码或短信验证
- 防御深度化:结合多种防护措施形成纵深防御
通过理解CSRF的攻击原理和系统学习防御方案,可以有效保护Web应用免受此类攻击威胁。