您现在的位置是:网站首页 > 前端框架中的 CSRF 防护文章详情
前端框架中的 CSRF 防护
陈川
【
前端安全
】
18796人已围观
6139字
CSRF 攻击的基本原理
CSRF(Cross-Site Request Forgery)跨站请求伪造是一种常见的Web安全威胁。攻击者诱导用户在已认证的Web应用中执行非预期的操作。这种攻击利用了Web应用对用户浏览器的信任机制,通过伪造请求让用户在不知情的情况下提交恶意请求。
典型的CSRF攻击流程:
- 用户登录可信网站A,并在本地保存了认证信息(如Cookie)
- 用户在不登出网站A的情况下访问恶意网站B
- 网站B包含针对网站A的恶意请求
- 用户的浏览器自动携带网站A的认证信息发送请求
- 网站A服务器认为这是用户的合法操作
// 恶意网站可能包含的代码
<img src="https://bank.com/transfer?to=hacker&amount=10000" width="0" height="0">
前端框架的CSRF防护机制
现代前端框架提供了多种内置机制来防范CSRF攻击,这些机制通常与后端配合使用形成完整防护。
1. 自动CSRF Token管理
主流框架如Angular、React等支持自动处理CSRF Token。以Angular为例:
// Angular HttpClient会自动处理名为XSRF-TOKEN的Cookie
// 并在后续请求中添加X-XSRF-TOKEN头
// 后端设置Cookie
Set-Cookie: XSRF-TOKEN=abc123; Path=/; Secure; HttpOnly
// 前端请求自动添加
GET /api/data HTTP/1.1
Host: example.com
X-XSRF-TOKEN: abc123
2. 双重Cookie验证
这种方案要求前端在Cookie和请求头中都携带Token:
// 前端实现示例
function setCSRFCookie() {
const token = generateToken();
document.cookie = `CSRF-TOKEN=${token}; Path=/; Secure`;
return token;
}
// 发送请求时
fetch('/api/data', {
method: 'POST',
headers: {
'X-CSRF-TOKEN': getCookie('CSRF-TOKEN'),
'Content-Type': 'application/json'
},
body: JSON.stringify({...})
});
3. SameSite Cookie属性
现代浏览器支持SameSite Cookie属性,可以有效防止CSRF:
// 后端设置
Set-Cookie: sessionid=xyz123; Path=/; Secure; HttpOnly; SameSite=Strict
SameSite有三种模式:
- Strict:完全禁止第三方Cookie
- Lax:允许部分安全请求(如导航)携带Cookie
- None:允许所有跨站Cookie(必须同时设置Secure)
各框架具体实现方案
React中的CSRF防护
React本身不提供CSRF防护,但可以轻松集成各种方案:
// 使用axios拦截器添加CSRF Token
import axios from 'axios';
axios.interceptors.request.use(config => {
const token = document.cookie
.split('; ')
.find(row => row.startsWith('XSRF-TOKEN='))
?.split('=')[1];
if (token) {
config.headers['X-XSRF-TOKEN'] = token;
}
return config;
});
// 组件中使用
function TransferForm() {
const handleSubmit = async (e) => {
e.preventDefault();
await axios.post('/api/transfer', {...});
};
return (
<form onSubmit={handleSubmit}>
{/* 表单内容 */}
</form>
);
}
Vue中的CSRF防护
Vue可以与各种HTTP库配合实现防护:
// 使用vue-resource
Vue.http.interceptors.push((request, next) => {
const token = getCookie('XSRF-TOKEN');
if (token) {
request.headers.set('X-XSRF-TOKEN', token);
}
next();
});
// 或者在Vue 3中使用axios
app.config.globalProperties.$http = axios.create({
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
});
Angular的CSRF防护
Angular提供了开箱即用的支持:
// app.module.ts
import { HttpClientModule, HttpClientXsrfModule } from '@angular/common/http';
@NgModule({
imports: [
HttpClientModule,
HttpClientXsrfModule.withOptions({
cookieName: 'XSRF-TOKEN',
headerName: 'X-XSRF-TOKEN'
})
]
})
export class AppModule {}
// 组件中使用
this.http.post('/api/data', payload).subscribe(...);
高级防护策略
1. 可验证的请求来源
检查Origin和Referer头部:
// 后端中间件示例(Node.js)
app.use((req, res, next) => {
const origin = req.get('Origin');
const referer = req.get('Referer');
if (!isValidOrigin(origin) || !isValidReferer(referer)) {
return res.status(403).send('Invalid request source');
}
next();
});
2. 一次性Token
每次请求使用不同的Token:
// 前端获取Token
async function getCSRFToken() {
const response = await fetch('/api/csrf-token');
const { token } = await response.json();
return token;
}
// 使用Token
async function makeRequest(payload) {
const token = await getCSRFToken();
const response = await fetch('/api/data', {
method: 'POST',
headers: {
'X-CSRF-TOKEN': token
},
body: JSON.stringify(payload)
});
return response.json();
}
3. 自定义请求头
添加非标准头部的防护:
// 前端设置
fetch('/api/data', {
method: 'POST',
headers: {
'X-Custom-Header': 'value',
'X-Requested-With': 'XMLHttpRequest'
}
});
// 后端验证
if (!req.headers['x-requested-with']) {
return res.status(403).send('Missing required header');
}
实际应用中的注意事项
1. Token的存储与传输
- 避免将Token存储在localStorage中
- 确保Token通过安全通道传输(HTTPS)
- 为敏感操作使用短期有效的Token
// 不安全的做法
localStorage.setItem('csrfToken', token);
// 正确的做法
document.cookie = `CSRF-TOKEN=${token}; Path=/; Secure; SameSite=Strict`;
2. API设计原则
- RESTful API应区分安全和非安全端点
- 对状态修改操作强制使用CSRF防护
- 为不同功能使用不同的Token
// API路由示例
router.post('/api/transfer', csrfProtection, transferController);
router.get('/api/transactions', transactionController); // 不需要CSRF
3. 与认证机制的配合
CSRF防护应与认证方案协同工作:
// JWT + CSRF组合方案
// 1. 登录成功后返回JWT和CSRF Token
{
"token": "jwt.xyz.123",
"csrfToken": "abc123"
}
// 2. 前端存储
localStorage.setItem('token', data.token);
document.cookie = `CSRF-TOKEN=${data.csrfToken}; Secure; HttpOnly`;
// 3. 后续请求
fetch('/api/data', {
headers: {
'Authorization': `Bearer ${localStorage.getItem('token')}`,
'X-CSRF-TOKEN': getCookie('CSRF-TOKEN')
}
});
测试与验证
1. 自动化测试方案
使用测试工具验证CSRF防护:
// 使用Jest测试CSRF防护
describe('CSRF Protection', () => {
it('should reject requests without CSRF token', async () => {
const response = await request(app)
.post('/api/data')
.expect(403);
});
it('should accept requests with valid CSRF token', async () => {
const csrfToken = await getCSRFToken();
const response = await request(app)
.post('/api/data')
.set('X-CSRF-TOKEN', csrfToken)
.expect(200);
});
});
2. 手动验证步骤
- 检查页面是否包含CSRF Token
- 验证Token是否随请求发送
- 尝试伪造请求测试防护效果
- 检查SameSite Cookie设置
<!-- 检查表单中的Token -->
<form>
<input type="hidden" name="_csrf" value="token123">
</form>
与其他安全措施的协同
1. 内容安全策略(CSP)
CSP可以限制外部资源加载,辅助CSRF防护:
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self' 'unsafe-inline'">
2. CORS策略
合理的CORS配置可以防止某些CSRF变种:
// Express CORS配置
app.use(cors({
origin: ['https://trusted.com'],
methods: ['GET', 'POST'],
allowedHeaders: ['X-CSRF-TOKEN']
}));
3. 速率限制
对敏感操作添加速率限制:
// 登录尝试限制
app.post('/login',
rateLimit({ windowMs: 15*60*1000, max: 5 }),
loginController
);
上一篇: 双重提交 Cookie 方案
下一篇: 自动化检测与工具推荐