React+Django项目安全咨询:CORS配置与CSRF防护疑问
嘿,我来帮你拆解这几个前后端分离场景下的常见问题,都是实际生产中容易踩坑的点,逐个给你说清楚:
1. 生产环境允许所有CORS是否安全?
绝对不安全!
当你设置CORS_ALLOW_ALL_ORIGINS = True时,意味着任何域名的网站都可以向你的Django API发送跨域请求——这就相当于把你的API完全暴露给了互联网上的所有站点。恶意网站可以诱导你的用户访问,然后通过JS调用你的API执行敏感操作(比如修改用户数据、提交恶意内容),或者窃取用户的敏感数据。
正确的做法是在生产环境中严格指定允许的前端域名,比如你的React站点部署在https://your-app.com,就在Django的settings.py里配置:
CORS_ALLOWED_ORIGINS = [ "https://your-app.com", # 如果有测试环境域名也可以加上,比如 "https://staging.your-app.com" ]
这样只有你的前端站点能合法调用API,把风险降到最低。
2. 不使用Django模板系统时,站点是否默认具备CSRF防护?
答案是没有有效的CSRF防护。
Django的CSRF防护默认依赖两个点:
- 模板中通过
{% csrf_token %}生成的隐藏表单字段,或者 - 前端从Cookie中读取
csrftoken并在请求头中传递X-CSRFToken
但如果你完全不用Django模板,前端(React)没法直接获取到CSRF token,也不会自动在请求中携带它。这时候Django的CSRF中间件会拦截所有修改型请求(POST/PUT/DELETE等),但前端如果没传token,要么请求被拒绝,要么你不得不关闭CSRF防护——这就等于完全放弃了CSRF防御。
所以不用模板的情况下,默认的CSRF防护是无效的,需要手动配置前后端配合才能生效。
3. React + Django架构下如何防范CSRF?
按照以下步骤配置,就能在前后端分离场景下实现有效的CSRF防护:
第一步:确保Django的CSRF中间件启用
打开settings.py,确认django.middleware.csrf.CsrfViewMiddleware在MIDDLEWARE列表中(默认已经启用,不要删除它)。
第二步:配置Django的CSRF相关设置
根据生产环境的情况调整这些参数:
# 允许前端域名读取CSRF Cookie(如果需要JS读取的话) CSRF_COOKIE_HTTPONLY = False # 默认是True,设为False允许前端JS访问Cookie # 跨域场景下设置SameSite为None,同时开启Secure(HTTPS下) CSRF_COOKIE_SAMESITE = "None" CSRF_COOKIE_SECURE = True # 信任你的前端域名,允许它发送CSRF请求 CSRF_TRUSTED_ORIGINS = [ "https://your-app.com", ]
第三步:前端获取并传递CSRF Token
前端需要从Cookie中读取csrftoken,然后在发送修改型请求时把它放到请求头X-CSRFToken中。
比如用React + Axios的话,可以全局配置拦截器自动处理:
import axios from 'axios'; import Cookies from 'js-cookie'; // 可以用这个库方便读取Cookie // 全局配置Axios axios.defaults.xsrfCookieName = 'csrftoken'; axios.defaults.xsrfHeaderName = 'X-CSRFToken'; axios.defaults.withCredentials = true; // 允许携带Cookie // 或者手动设置请求头的方式: const csrfToken = Cookies.get('csrftoken'); axios.post('/api/your-endpoint/', data, { headers: { 'X-CSRFToken': csrfToken, }, withCredentials: true, });
如果用原生Fetch API:
const csrfToken = document.cookie.split('; ').find(row => row.startsWith('csrftoken=')).split('=')[1]; fetch('/api/your-endpoint/', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': csrfToken, }, credentials: 'include', // 携带Cookie body: JSON.stringify(data), });
可选:自定义API接口返回CSRF Token
如果你不想让前端读取Cookie,也可以写一个简单的Django视图来返回CSRF Token:
from django.http import JsonResponse from django.middleware.csrf import get_token def get_csrf_token(request): token = get_token(request) return JsonResponse({'csrfToken': token})
然后前端调用这个接口获取token,再放到请求头里——这种方式适合不想让前端访问Cookie的场景。
内容的提问来源于stack exchange,提问作者Tinyik

