如何在React Redux Saga应用中实现CSRF防护?
嘿,在React Redux Saga项目里实现CSRF防护其实挺直观的,核心是和后端配合好,同时在Saga处理请求的环节把必要的Token带上。我给你拆解几个关键步骤,一步步来:
第一步:先让后端配置好CSRF Token的生成与传递
CSRF防护的前提是后端能生成并传递Token给前端,常见的做法有两种:
- Cookie存储:后端在用户首次访问时,把Token放在一个非HttpOnly的Cookie里(比如
XSRF-TOKEN),这样前端能读取到。同时要设置好Cookie的SameSite属性(推荐Strict或Lax),防止跨站滥用。 - 响应头传递:后端在API响应的头里返回Token(比如
X-CSRF-Token),前端可以从响应头中提取。
第二步:前端写个工具函数获取CSRF Token
不管后端用哪种方式传递,你都需要一个函数来拿到Token。比如针对Cookie的情况:
// 从Cookie中提取XSRF Token的工具函数 const getCsrfToken = () => { const cookieMatch = document.cookie.match(/XSRF-TOKEN=([^;]+)/); return cookieMatch ? cookieMatch[1] : null; };
如果是从响应头拿,就可以在首次请求后把Token存在全局状态(比如Redux store)里,后续直接从store取。
第三步:在Redux Saga的请求中带上Token
接下来就是在Saga发起请求时,把Token放到请求头里。这里分两种常用的请求库来举例:
用原生Fetch的情况
import { call, put } from 'redux-saga/effects'; function* submitFormSaga(action) { try { const csrfToken = getCsrfToken(); // 发起POST请求,在headers里带上Token const response = yield call(fetch, '/api/submit-form', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-XSRF-TOKEN': csrfToken // 这里的头名要和后端约定好,比如有的后端用X-CSRF-Token }, body: JSON.stringify(action.payload) }); if (!response.ok) throw new Error('请求失败'); const result = yield call([response, 'json']); yield put({ type: 'SUBMIT_FORM_SUCCESS', payload: result }); } catch (error) { yield put({ type: 'SUBMIT_FORM_FAILURE', error: error.message }); } }
用Axios的情况
更省心的方式是给Axios设置请求拦截器,全局自动带上Token:
import axios from 'axios'; import { call, put } from 'redux-saga/effects'; // 创建Axios实例 const apiClient = axios.create({ baseURL: '/api', }); // 添加请求拦截器,自动注入CSRF Token apiClient.interceptors.request.use((config) => { const csrfToken = getCsrfToken(); if (csrfToken) { config.headers['X-XSRF-TOKEN'] = csrfToken; } return config; }); // 在Saga里使用这个实例 function* fetchUserSaga() { try { const response = yield call(apiClient.get, '/user/profile'); yield put({ type: 'FETCH_USER_SUCCESS', payload: response.data }); } catch (error) { yield put({ type: 'FETCH_USER_FAILURE', error: error.message }); } }
第四步:处理Token无效或过期的情况
如果后端返回403状态码(说明CSRF验证失败),你可以在Saga里捕获这个错误,做相应的处理:
function* submitFormSaga(action) { try { // ... 正常请求逻辑 } catch (error) { if (error.response?.status === 403) { // 可以尝试重新获取Token(比如调用后端的刷新Token接口) yield call(refreshCsrfToken); // 然后重试当前请求 yield put(action); } else { yield put({ type: 'SUBMIT_FORM_FAILURE', error: error.message }); } } } // 示例:重新获取CSRF Token的Saga function* refreshCsrfToken() { yield call(fetch, '/api/refresh-csrf-token', { method: 'GET' }); }
几个关键注意事项
- 不要把Token存在localStorage:XSS攻击可以轻松窃取localStorage里的内容,而存在非HttpOnly的Cookie里,配合SameSite属性,安全性更高。
- 后端必须验证Token:前端带Token只是一半,后端要对比请求头里的Token和Cookie里的Token是否一致,这才是防护的核心。
- 跨域场景要额外配置:如果你的前端和后端是跨域的,要确保后端允许携带Cookie(设置
Access-Control-Allow-Credentials: true),同时前端请求要加上credentials: 'include'(Fetch)或withCredentials: true(Axios)。
内容的提问来源于stack exchange,提问作者Prakash
相关产品推荐
相关产品推荐

