Ajax 请求如何加上 CSRF 防护
在 Ajax 请求中加上 CSRF 防护 是非常重要的,特别是在现代 Web 应用(如使用 jQuery、Axios、Fetch 的前后端分离项目)中。下面是从原理、实现方法、代码示例到不同框架下的用法。
一、CSRF Token 在 Ajax 中的处理原理
在传统表单中,CSRF token 是通过隐藏字段提交的。而在 Ajax 中:
- 前端:需将 CSRF Token 加入请求 header 或请求 body;
- 后端:需从 header 或 body 中提取并验证 token;
- 通常由后端渲染页面时注入 token 到 HTML,再由 JavaScript 读取使用。
二、实现方式汇总
| 方法 | 说明 | 安全性 |
|---|---|---|
| 自定义 header(推荐) | 将 token 写入 Ajax 请求 header | ⭐⭐⭐⭐⭐ |
| 请求 body | 适用于 POST 请求带 form-data/json | ⭐⭐⭐⭐ |
| Cookie + header 双 token(SPA/REST) | 防御 CSRF + XSS | ⭐⭐⭐⭐⭐ |
三、CSRF Token 在页面中的注入方式
方法 1:后端渲染注入到 meta 标签
<meta name="csrf-token" content="<?php echo $_SESSION['csrf_token']; ?>">
方法 2:注入到 JavaScript 变量
<script>
window.csrfToken = "<?php echo $_SESSION['csrf_token']; ?>";
</script>
四、jQuery 示例:自动添加 CSRF Token
// 获取 token
const token = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
// 全局设置 Ajax 请求头
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': token
}
});
然后你就可以安全发送 POST 请求了:
$.post('/api/update-profile', {
name: 'John'
}, function (response) {
console.log('响应:', response);
});
五、原生 Fetch 示例
const token = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
fetch('/api/update-profile', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': token
},
body: JSON.stringify({ name: 'Jane' })
})
.then(res => res.json())
.then(data => console.log(data));
六、Axios 示例(推荐用于 Vue/React)
import axios from 'axios';
axios.defaults.headers.common['X-CSRF-TOKEN'] = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
axios.post('/api/update-profile', { name: 'Jane' })
.then(response => console.log(response.data));
七、后端 PHP 中验证 Ajax 请求的 CSRF Token
session_start();
$csrf_token_header = $_SERVER['HTTP_X_CSRF_TOKEN'] ?? '';
if (!hash_equals($_SESSION['csrf_token'], $csrf_token_header)) {
http_response_code(403);
echo json_encode(['error' => 'CSRF 验证失败']);
exit;
}
✅ 注意:
X-CSRF-TOKEN是常用自定义 header 名,可自由定义为如X-XSRF-TOKEN。
八、各主流框架的 Ajax CSRF 配置方式
🔸 Laravel
<!-- layout.blade.php -->
<meta name="csrf-token" content="{{ csrf_token() }}">
JS:
axios.defaults.headers.common['X-CSRF-TOKEN'] = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
Laravel 会自动验证
X-CSRF-TOKENheader 或_token字段。
🔸 Symfony
使用 CsrfTokenManager 生成令牌,手动验证:
$token = $request->headers->get('X-CSRF-TOKEN');
if (!$csrfTokenManager->isTokenValid(new CsrfToken('action_id', $token))) {
throw new AccessDeniedHttpException('CSRF token invalid');
}
🔸 Yii2
开启 CSRF:
'request' => [
'enableCsrfValidation' => true,
'csrfParam' => '_csrf',
],
JS:
let csrfToken = $('meta[name=csrf-token]').attr("content");
$.ajaxSetup({
data: { _csrf: csrfToken }
});
📚 权威参考资料
小结:Ajax 防 CSRF 最佳实践
| 步骤 | 推荐做法 |
|---|---|
| 1️⃣ 页面注入 token | 用 meta 或 JS 全局变量 |
| 2️⃣ 前端带上 token | 使用 header X-CSRF-TOKEN |
| 3️⃣ 后端验证 token | 与 Session 或 Cookie 中 token 比对 |
| 4️⃣ 验证失败处理 | 返回 403,记录日志 |
更多详细内容,请关注其他相关文章!