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

我的CSRF实现是否正确?基于Django+React/Redux的疑问

Django CSRF验证机制疑问解答

问题描述

我正在开发一个前端为业务界面、后端基于Django的网站,目前对Django的CSRF验证存在疑问:

每个请求都需要CSRF token,实际上是两个:一个由Cookie自动设置,另一个需作为POST参数提供。因此我开发了一个API接口用于返回token,再用该token发起其他请求。但这感觉像是守卫没密码不让进,却会主动告知密码,这样的机制到底能起到什么作用?

注:我是新手,希望这个问题不会太幼稚。

核心原理:防跨站伪造请求

你觉得这个机制矛盾,本质是没搞懂CSRF攻击的逻辑——攻击者是利用用户已登录目标站点的状态,诱导用户访问恶意页面,借助浏览器自动携带Cookie的特性,伪造用户身份发起非法请求。

举个实际场景:你登录了银行网站,浏览器里存着银行的登录Cookie,这时不小心点开钓鱼网站,它会偷偷向银行的转账接口发POST请求,浏览器会自动带上你的银行Cookie,如果银行没做CSRF验证,就会把这个请求当成你发起的,执行转账操作。

而Django的CSRF机制就是从根源上切断这种攻击:

  1. 服务器给合法访问的用户浏览器设置一个CSRF Cookie,这个Cookie会在用户访问站点时自动被浏览器携带
  2. 同时要求所有POST请求必须携带和Cookie中一致的CSRF token(可以放在POST参数里,也可以放在X-CSRFToken请求头中)

恶意站点为什么拿不到这个有效token?因为浏览器的同源策略:恶意站点的JS代码既读不到你目标站点的Cookie,也没法通过跨域AJAX请求获取目标站点返回的token(跨域请求默认不携带Cookie,就算配置了携带,恶意站点也无法读取响应里的token内容)。

你写的initialize接口是GET请求,只有当用户浏览器已经携带了合法的会话Cookie(也就是用户已经登录过,或者至少访问过你的站点,服务器已经给它分配了CSRF Cookie),才能拿到对应的有效token。恶意站点完全没法模拟这个场景,因为它拿不到用户的Cookie,自然也没法通过这个接口获取能通过验证的token。

代码优化建议

其实Django已经内置了更简便的处理方式,你不需要自己写initialize接口来返回token:

  • 如果是服务端渲染模板,直接在表单里用{% csrf_token %}标签,Django会自动把token注入到页面中,前端可以直接从DOM中获取
  • 如果是单页应用,也可以直接读取浏览器Cookie里的csrftoken字段,不用专门发请求。比如在React里可以通过解析document.cookie来提取这个值,省去initializeCsrf函数的编写

附上你的代码

Django后端代码

def initialize(request):
    """
    页面首次加载时由前端调用,返回所有POST请求需要的csrf_token(本接口用GET请求),以及当前请求关联的登录用户名。
    """
    data = dict()
    data['csrf_token'] = get_token(request)
    data['logged_in_user_name'] = auth.get_user(request).get_username()
    
    return HttpResponse(json.dumps(data), status = status.HTTP_200_OK)

React/Redux前端代码

var csrfToken = null as null | string; 

/**
 * 从服务器获取POST请求所需的CSRF token,同时获取登录用户名并更新到状态中。
 * 
 * @param dispatch 用于分发action更新store的函数。
 */
export async function initializeCsrf(dispatch: Dispatch)
{
    if (csrfToken)
    {
        return csrfToken;
    }
    
    try
    {
        const response = await fetch(`${Ernots.APIURLPrefix}initialize`,
        {
            method: 'GET',
            mode: 'cors',
            credentials: 'include',
        });

        var json = await response.json();
        csrfToken = json.csrf_token;
        
        dispatch(loginActions.setLoggedInUserName(json.logged_in_user_name));
        dispatch(requestActions.setBackendUnreachable(false));        
        return csrfToken;
    }
    catch(e)
    {
        dispatch(requestActions.setBackendUnreachable(true));
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 23:10:36