You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django Rest Framework跨域场景下防XSS/CSRF的认证方案咨询

跨域DRF+React的API安全方案与实践

一、JWT的XSS防护与http-only Cookie适配方案

把JWT存到http-only cookie里确实是防XSS的最优解,不用纠结前端拿不到token没法加Authorization头——后端可以直接从cookie中读取token做认证,浏览器会自动在跨域请求中携带符合条件的cookie,只要做好跨域和CSRF配置就行。

后端DRF配置步骤

  1. CORS与CSRF基础配置
    安装django-cors-headers,在settings.py中添加:

    INSTALLED_APPS = [
        # ...其他应用
        'corsheaders',
    ]
    
    MIDDLEWARE = [
        'corsheaders.middleware.CorsMiddleware',  # 放在CommonMiddleware之前
        'django.middleware.common.CommonMiddleware',
        # ...其他中间件
    ]
    
    # 允许的前端域名,禁止使用*
    CORS_ALLOWED_ORIGINS = [
        "https://your-frontend-domain.com",
        "http://localhost:3000",  # 开发环境
    ]
    CORS_ALLOW_CREDENTIALS = True  # 允许跨域携带cookie
    
    # 信任前端域名,支持CSRF验证
    CSRF_TRUSTED_ORIGINS = [
        "https://your-frontend-domain.com",
        "http://localhost:3000",
    ]
    
  2. 自定义JWT认证类
    让DRF从cookie中读取access token,替代默认的Authorization头读取逻辑:

    from rest_framework_simplejwt.authentication import JWTAuthentication
    from django.http import HttpRequest
    
    class CookieJWTAuthentication(JWTAuthentication):
        def authenticate(self, request: HttpRequest):
            token = request.COOKIES.get('access_token')
            if not token:
                return None
            try:
                validated_token = self.get_validated_token(token)
                user = self.get_user(validated_token)
                return (user, validated_token)
            except Exception:
                return None
    

    在settings.py中设置默认认证类:

    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': [
            'your_app.path.to.CookieJWTAuthentication',
        ],
    }
    
  3. 登录/刷新视图修改
    登录成功后把token写入http-only cookie,而非返回给前端存储:

    from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
    from rest_framework.response import Response
    
    class CustomTokenObtainPairView(TokenObtainPairView):
        def post(self, request, *args, **kwargs):
            response = super().post(request, *args, **kwargs)
            # 设置access token cookie
            response.set_cookie(
                key='access_token',
                value=response.data['access'],
                httponly=True,
                secure=True,  # 生产环境开启HTTPS后启用
                samesite='Strict',  # 限制跨站携带,降低CSRF风险
                max_age=3600  # 和token有效期保持一致,比如1小时
            )
            # 设置refresh token cookie
            response.set_cookie(
                key='refresh_token',
                value=response.data['refresh'],
                httponly=True,
                secure=True,
                samesite='Strict',
                max_age=7*24*3600  # 7天有效期
            )
            # 删除响应体中的token,避免前端存储
            del response.data['access']
            del response.data['refresh']
            return response
    
    class CustomTokenRefreshView(TokenRefreshView):
        def post(self, request, *args, **kwargs):
            # 从cookie中取refresh token
            request.data['refresh'] = request.COOKIES.get('refresh_token')
            response = super().post(request, *args, **kwargs)
            # 更新access token cookie
            response.set_cookie(
                key='access_token',
                value=response.data['access'],
                httponly=True,
                secure=True,
                samesite='Strict',
                max_age=3600
            )
            del response.data['access']
            return response
    

    最后把这两个视图添加到项目的urls.py中。

前端React处理

  1. 全局配置请求携带cookie
    用axios的话,在项目入口文件设置:

    import axios from 'axios';
    axios.defaults.withCredentials = true;
    
  2. CSRF Token处理
    对POST/PUT/DELETE等状态修改请求,必须携带X-CSRFToken头:

    // 从cookie中提取CSRF token
    function getCsrfToken() {
        const value = `; ${document.cookie}`;
        const parts = value.split(`; csrftoken=`);
        if (parts.length === 2) return parts.pop().split(';').shift();
    }
    
    // 发送请求示例
    async function submitData(data) {
        try {
            const response = await axios.post('/api/your-endpoint/', data, {
                headers: {
                    'X-CSRFToken': getCsrfToken()
                }
            });
            return response.data;
        } catch (error) {
            console.error(error);
        }
    }
    

二、API安全最佳实践

  • XSS防护

    • React默认会转义用户输入,禁止使用dangerouslySetInnerHTML渲染不可信内容
    • 敏感数据(token、用户隐私信息)必须存带有http-only、secure、same-site属性的cookie
    • 配置内容安全策略(CSP),限制页面加载的资源来源,比如在后端返回Content-Security-Policy响应头
  • CSRF防护

    • 所有状态修改请求必须验证CSRF token,GET请求不做任何状态修改操作
    • 给cookie设置SameSite=Strict或Lax,减少跨站请求携带cookie的风险
    • 确保CSRF token和用户会话绑定,避免复用
  • JWT相关

    • 缩短access token有效期(1小时以内),用refresh token定期刷新
    • refresh token同样存http-only cookie,并且支持用户注销时即时失效(可将refresh token存入数据库,刷新时验证有效性)
    • JWT payload不要存敏感信息,因为payload是base64编码,可直接解码查看
  • 跨域与传输安全

    • 严格限制CORS_ALLOWED_ORIGINS,绝不使用*
    • 生产环境强制启用HTTPS,防止数据明文传输
    • 配置HSTS头,强制浏览器用HTTPS访问站点
  • 其他防护

    • 给API添加速率限制,防止暴力破解或批量请求攻击
    • 定期更新DRF、React及依赖包,修复已知安全漏洞
    • 对用户输入做服务器端校验,不要只依赖前端验证

三、dj-rest-auth使用经验

核心配置要点

  1. 安装依赖:dj-rest-auth依赖django-allauth,需同时安装,然后在INSTALLED_APPS中添加:

    INSTALLED_APPS = [
        # ...其他应用
        'rest_framework',
        'rest_framework.authtoken',
        'dj_rest_auth',
        'django.contrib.sites',
        'allauth',
        'allauth.account',
        'allauth.socialaccount',
    ]
    SITE_ID = 1
    
  2. 跨域适配:和前面JWT的配置一致,开启CORS_ALLOW_CREDENTIALS,配置CSRF_TRUSTED_ORIGINS,前端请求需携带withCredentials和X-CSRFToken

常见问题解决

  • 邮箱验证失效:检查EMAIL_BACKEND配置,开发环境可用django.core.mail.backends.console.EmailBackend输出到控制台,生产环境配置SMTP服务;确保ACCOUNT_EMAIL_VERIFICATION设置正确(比如mandatory强制验证)
  • 跨域请求被拒:确认CORS_ALLOWED_ORIGINS包含前端准确域名,CSRF_TRUSTED_ORIGINS也要同步添加
  • 自定义用户模型适配:如果用了自定义User,必须在settings.py中设置AUTH_USER_MODEL = 'your_app.YourUser',必要时需自定义allauth的适配器来适配用户字段

优势与注意事项

  • 自带登录、注册、密码重置、邮箱验证、第三方OAuth登录等功能,节省开发时间
  • 如果要把token存http-only cookie,需要自定义登录视图,逻辑和前面的JWT处理类似,将响应体中的token写入cookie并删除响应体中的内容
  • 文档虽全面,但部分配置需结合django-allauth的文档一起查看,初期可能会有混淆

内容的提问来源于stack exchange,提问作者webdeveloper

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 13:35:01