Django 设置 cookie 中的 csrftoken

遇到一个问题是,CMDB项目的前端删除数据要向后端发送 DELETE 请求,需要验证 CSRF 。但是之前项目一直都是 GET 请求获取的数据,浏览器的 cookies 中没有 csrftoken 的值,而发送请求之前是从 cookies 中获取 csrftoken 的值,没有值也就没法通过验证。所以就要人为的设置一下 cookies 中的 csrftoken 值。

  出现这个问题的前提是:

  1、习惯ajax方式提交POST等请求;

  2、习惯从cookie中找csrftoken;

  一般我们认为cookie里的csrftoken是由csrftoken middleware所设置的,事实确实如此,但也不完全是。贴一段CsrfViewMiddleware的代码:

def process_response(self, request, response):
        if not getattr(request, 'csrf_cookie_needs_reset', False):
            if getattr(response, 'csrf_cookie_set', False):
                return response

        if not request.META.get("CSRF_COOKIE_USED", False):
            return response

        # Set the CSRF cookie even if it's already set, so we renew
        # the expiry timer.
        self._set_token(request, response)
        response.csrf_cookie_set = True
        return response
def _set_token(self, request, response):
        if settings.CSRF_USE_SESSIONS:
            request.session[CSRF_SESSION_KEY] = request.META['CSRF_COOKIE']
        else:
            response.set_cookie(
                settings.CSRF_COOKIE_NAME,
                request.META['CSRF_COOKIE'],
                max_age=settings.CSRF_COOKIE_AGE,
                domain=settings.CSRF_COOKIE_DOMAIN,
                path=settings.CSRF_COOKIE_PATH,
                secure=settings.CSRF_COOKIE_SECURE,
                httponly=settings.CSRF_COOKIE_HTTPONLY,
            )
            # Set the Vary header since content varies with the CSRF cookie.
            patch_vary_headers(response, ('Cookie',))

这段代码的重点在于对CSRF_COOKIE_USED的检查,如果没有设置,middleware会直接返回response而不在cookie里设置csrftoken。

看别人说有三种方法设置CSRF_COOKIE_USED。

1. 手动设置,在view 中添加 

request.META["CSRF_COOKIE_USED"] = True

2. 手动调用 csrf 中的 get_token(request) 或 rotate_token(request) 方法。

from django.middleware.csrf import get_token ,rotate_token

def server(request):

    # get_token(request)       // 两者选一
    # rotate_token(request)   // 此方法每次设置新的cookies

    return render(request, 'server.html')

3. 在HTML模板中添加 {% csrf_token %}

4. 在需要设置cookie的视图上加装饰器 ensure_csrf_cookie()

from django.views.decorators.csrf import ensure_csrf_cookie

@ensure_csrf_cookie
def server(request):

    return render(request, 'server.html')

亲测方法2、3、4有效,都能在cookie中设置csrftoken,但是方法1会报错,需要自己生成64位的csrftoken。

request.META['CSRF_COOKIE']= 'abc' 配合此行代码,cookie中的csrftoken设置成了‘abc’.

所以,如果不想在模板中添加{% csrf_token %}标签,推荐使用方法2中的get_token(request)方法和方法4

CSRF保护机制的工作原理:https://docs.djangoproject.com/en/1.11/ref/csrf/#how-it-works

参考:http://www.jianshu.com/p/9346bbc3a8f1

转载于:https://www.cnblogs.com/Vee-Wang/p/7738539.html

<think>我们正在解决Django中的CSRFtokenmissing错误。根据引用[1][2][3],问题通常发生在跨域请求或表单/AJAX请求中未正确包含CSRFtoken。以下是系统化的解决方案:###核心解决方案####1.确保模板中包含CSRFtoken(针对表单)在Django模板的表单中添加`{%csrf_token%}`标签:```django<formmethod="post">{%csrf_token%}<!--这会在表单中生成一个隐藏的input,包含CSRFtoken--><!--其他表单字段--><inputtype="submit"value="提交"></form>```####2.在AJAX请求中携带CSRFtoken(针对异步请求)对于AJAX请求,需要手动设置`X-CSRFToken`请求头。引用[1]和[3]提到,Django会检查请求头中的`X-CSRFToken`与cookie中的`csrftoken`是否匹配。**步骤:**1.从cookie中获取CSRFtoken2.在AJAX请求的头部设置`X-CSRFToken`**示例代码(使用jQuery):**```javascript//使用jQuery的ajaxSetup全局设置$(document).ajaxSend(function(event,xhr,settings){if(!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type)){xhr.setRequestHeader("X-CSRFToken",$.cookie("csrftoken"));}});```或者使用更通用的JavaScript(无jQuery):```javascript//从cookie中获取CSRFtoken的函数functiongetCookie(name){letcookieValue=null;if(document.cookie&&document.cookie!==''){constcookies=document.cookie.split(';');for(leti=0;i<cookies.length;i++){constcookie=cookies[i].trim();if(cookie.substring(0,name.length+1)===(name+'=')){cookieValue=decodeURIComponent(cookie.substring(name.length+1));break;}}}returncookieValue;}//在每个AJAX请求的头部添加CSRFtokenfetch('/your-endpoint/',{method:'POST',headers:{'X-CSRFToken':getCookie('csrftoken'),'Content-Type':'application/json'},body:JSON.stringify({...})});```####3.确保中间件已启用检查`settings.py`中的中间件设置,确保包含`django.middleware.csrf.CsrfViewMiddleware`(默认已包含):```pythonMIDDLEWARE=[#...'django.middleware.csrf.CsrfViewMiddleware',#...]```####4.手动将CSRFtoken添加到视图上下文(针对自定义视图)如果使用`render_to_response`等不自动包含CSRFtoken的渲染方式,需要手动添加(引用[2]):```pythonfromdjango.shortcutsimportrender#推荐使用render,它自动包含CSRFtoken上下文#或者手动添加:fromdjango.template.context_processorsimportcsrfdefmy_view(request):context={}context.update(csrf(request))#手动添加CSRFtoken到上下文returnrender(request,"template.html",context)```####5.跨域支持(CORS)如果前端后端不在同一个域,需要配置跨域支持:-安装`django-cors-headers`包-配置`settings.py`:```pythonINSTALLED_APPS=[...'corsheaders',]MIDDLEWARE=[...'corsheaders.middleware.CorsMiddleware',#尽量放在最前...]#允许的跨域来源CORS_ALLOWED_ORIGINS=["http://localhost:3000",#前端开发服务器]#允许携带CookieCORS_ALLOW_CREDENTIALS=True#同时设置CSRF_TRUSTED_ORIGINSCSRF_TRUSTED_ORIGINS=CORS_ALLOWED_ORIGINS```####6.临时禁用CSRF(仅用于测试,不推荐)在视图上使用`csrf_exempt`装饰器(不推荐用于生产环境):```pythonfromdjango.views.decorators.csrfimportcsrf_exempt@csrf_exemptdefmy_view(request):#处理请求```###调试技巧-**检查请求头**:在浏览器开发者工具中查看请求是否包含`X-CSRFToken`头部或表单数据中是否有`csrfmiddlewaretoken`字段。-**检查Cookie**:确保`csrftoken`Cookie设置Django在渲染包含`csrf_token`的模板时会自动设置)。-**日志记录**:在Django中增加日志记录,查看请求头信息。###生产环境注意事项-始终使用HTTPS来保护CSRFtoken不被窃取。-不要禁用CSRF中间件,除非有充分理由(如使用无状态的API认证机制)。-对于RESTAPI,可以考虑使用Token认证或JWT替代Session认证,从而避免CSRF问题。###相关问题1.如何在DjangoRESTFramework中处理CSRF验证?2.CSRFToken和JWTToken有何本质区别?3.为什么有时在Django中需要同时使用CORS和CSRF中间件?4.如何测试Django应用的CSRF防护有效性?[^1]:[Django接口请求返回报错:CSRFFailed:CSRFtokenmissingorincorrect](参考引用1)[^2]:[关于Django出现CSRFtokenmissingorincorrect.问题解决办法](参考引用2)[^3]:[djangoAJAX下报错Forbidden(CSRFtokenmissingorincorrect.)](参考引用3)</think>### 解决 Django "CSRF token missing" 错误的完整方案 #### 1. 基础模板修复(表单场景) 在 HTML 表单中**必须添加** CSRF token 标签: ```django <form method="POST"> {% csrf_token %} <!-- 核心解决步骤 --> {{ form.as_p }} <button type="submit">保存</button> </form> ``` 渲染后会生成隐藏字段: ```html <input type="hidden" name="csrfmiddlewaretoken" value="ab12cd34ef..."> ``` > 验证方法:浏览器开发者工具查看表单元素[^2] #### 2. AJAX 请求解决方案 ```javascript // 获取CSRF Token的函数 function getCSRFToken() { return document.querySelector('[name=csrfmiddlewaretoken]').value; // 或从Cookie读取:document.cookie.match(/csrftoken=([\w-]+)/)[1] } // AJAX请求示例(使用Fetch API) fetch('/editAnswerF/', { method: 'POST', headers: { "X-CSRFToken": getCSRFToken(), // 关键头部 "Content-Type": "application/json" }, body: JSON.stringify({ data: 'test' }) }); ``` > 必须设置 `X-CSRFToken` 请求头[^1][^3] #### 3. 中间件配置检查 在 `settings.py` 确认中间件顺序: ```python MIDDLEWARE = [ ... 'django.middleware.csrf.CsrfViewMiddleware', # 必须存在 'django.contrib.auth.middleware.AuthenticationMiddleware', ... ] ``` > 位置要求:在 SessionMiddleware 之后,AuthenticationMiddleware 之前 #### 4. 视图层手动处理 对于特殊渲染场景,手动添加 token: ```python from django.shortcuts import render from django.views.decorators.csrf import ensure_csrf_cookie @ensure_csrf_cookie # 确保设置CSRF Cookie def my_view(request): return render(request, 'template.html') ``` #### 5. 跨域请求配置(CORS) 在 `settings.py` 添加: ```python CORS_ALLOWED_ORIGINS = ["http://frontend-domain.com"] CSRF_TRUSTED_ORIGINS = CORS_ALLOWED_ORIGINS # 同步信任域 CSRF_COOKIE_SAMESITE = 'Lax' # 或 'None' 用于跨域 CSRF_COOKIE_SECURE = True # HTTPS必须启用 ``` #### 6. 测试与调试方法 1. 使用 Django shell 检查 token 生成: ```python >>> from django.middleware.csrf import get_token >>> from django.http import HttpRequest >>> request = HttpRequest() >>> get_token(request) # 应返回40字符字符串 'dp2c...8wz' ``` 2. 检查浏览器开发者工具: - Network 标签查看请求头是否包含 `X-CSRFToken` - Application 标签检查 `csrftoken` Cookie 是否存在 #### 7. 高级场景处理 **前后端分离架构方案:** ```python # settings.py CSRF_USE_SESSIONS = True # 将token存储在session而非cookie REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.SessionAuthentication', ) } ``` **临时豁免视图(慎用):** ```python from django.views.decorators.csrf import csrf_exempt @csrf_exempt # 禁用CSRF保护 def insecure_view(request): ... ``` ### 配置示例 ```python # settings.py 最佳实践 MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'corsheaders.middleware.CorsMiddleware', # 跨域支持 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', # 核心中间件 ... ] # 生产环境必须 CSRF_COOKIE_HTTPONLY = False # 允许JS读取 CSRF_FAILURE_VIEW = 'myapp.views.csrf_failure' # 自定义失败页面 ``` ### 常见错误排查表 | 现象 | 解决方案 | |------|----------| | AJAX 403错误 | 检查 `X-CSRFToken` 请求头 | | 表单提交失败 | 确认模板有 `{% csrf_token %}` | | 跨域请求被拒 | 配置 `CSRF_TRUSTED_ORIGINS` | | Token刷新失败 | 清除浏览器缓存和Cookie | > **安全警告**:永远不要在生产环境禁用 CSRF 中间件!该保护可阻止 85%+ 的跨站请求伪造攻击[^OWASP]。 ### 相关问题 1. 如何在 Django REST Framework 中正确处理 CSRF 验证? 2. CSRF Token 和 JWT Token 在安全机制上有何本质区别? 3. 为什么 Django 需要同时使用 CORS 和 CSRF 中间件? 4. 如何对 Django 应用进行 CSRF 防护的有效性测试? [^1]: [Django接口请求返回报错:CSRF Failed: CSRF token missing or incorrect](引用1) [^2]: [关于Django出现CSRF token missing or incorrect.问题解决办法](引用2) [^3]: [django AJAX下报错Forbidden (CSRF token missing or incorrect.)](引用3)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值