CSRF 失败:CSRF 令牌丢失或不正确

Posted

技术标签:

【中文标题】CSRF 失败:CSRF 令牌丢失或不正确【英文标题】:CSRF Failed: CSRF token missing or incorrect 【发布时间】:2014-12-25 16:16:10 【问题描述】:

我正在使用 Django 1.7 和 django-rest-framework。

我创建了一个 API,它返回一些 JSON 数据,并将其放入我的 settings.py

REST_FRAMEWORK = 
    'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.AllowAny',),
    'DEFAULT_RENDERER_CLASSES': (
    #   'rest_framework.renderers.XMLRenderer',
    'rest_framework.renderers.JSONRenderer',
    #   'rest_framework.renderers.BrowsableAPIRenderer',
    )

当我进行 GET 调用时,它会返回所有数据,但是当我尝试使用 PUT/PATCH 时,我会得到:

--------Response Headers---------
Status Code: 403
Date: Wed, 29 Oct 2014 18:51:42 GMT
Vary: Cookie
Server: WSGIServer/0.1 Python/2.7.8
Allow: GET, POST, PUT, PATCH, HEAD, OPTIONS
X-Frame-Options: SAMEORIGIN
Content-Type: application/json
---------------------------------

--------Response Body-----------
"detail": "CSRF Failed: CSRF token missing or incorrect."
---------------------------------

这仅在我登录时发生,如果我是匿名的,我可以正确 PUT/PATCH。

我已尝试使用@csrf_exempt,但出现错误,我已将rest_framework.permissions.AllowAny 包含在设置中...

我不知道发生了什么。有谁知道是什么问题?

【问题讨论】:

【参考方案1】:

当您使用SessionAuthentication 时,您使用的是 Django 的身份验证,这通常需要检查 CSRF。 Django REST Framework 强制执行此操作,仅针对 SessionAuthentication,因此您必须在 X-CSRFToken 标头中传递 CSRF 令牌。

Django documentation 提供了有关使用 jQuery 检索 CSRF 令牌并在请求中发送它的更多信息。 CSRF 令牌保存为一个名为 csrftoken 的 cookie,您可以从 HTTP 响应中检索它,具体取决于所使用的语言。

如果您无法检索 CSRF cookie,这通常表明您不应该使用 SessionAuthentication。我建议根据您的需要查看TokenAuthentication 或OAuth 2.0。

【讨论】:

我知道我应该在通过身份验证时提供 CSRF 令牌,但是,实际上我正在使用 .NET Windows 窗体应用程序与此 API 通信,它通过 HTTPRequest 和 HTTPResponse 方法进行 GET 调用,我不知道在这种情况下如何获得 CSRF 令牌,我没有使用 AJAX 或 html 表单。 编辑 .NET 应用程序接收 JSON 格式的纯文本,并返回相同的内容 你没事,我可以使用 cookie 处理 csrftoken 并将其放回标头数据中,这样我就可以在登录时进行 PUT/PATCH 调用。谢谢! @AlexLordMordor 你能解释一下你的解决方案吗?以及为什么当您是登录用户时它不起作用,但以匿名方式起作用。 (我有完全相同的问题) 当您使用 SessionAuthentication 时,默认情况下 django 需要两个“密钥”,其中一个可以在登录用户处于活动状态时在 cookie 中找到,另一个是 csrf-token,如果他们这样做的话不匹配,然后引发错误,因此,有像 @Kevin 这样的文档说要以正确的方式进行身份验证。 另一种实现方式可以在这篇文章中找到:blog.kevinastone.com/…,在“插曲:AngularJS + CSRF 保护”部分。在这种情况下使用 AngularJS【参考方案2】:

这就是我为解决它所做的,我在表单中包含了 csrf 令牌,并在加载文档时使用 jquery/javascrip 得到了这样的 csrf 令牌

var $crf_token = $('[name="csrfmiddlewaretoken"]').attr('value');

将其包含在 jquery 标头中,如下所示

 $.ajax(
            type: "POST",
            url: "/api/endpoint/",
            data: newEndpoint,
            headers:"X-CSRFToken": $crf_token,
            success: function (newEnd) 
                console.log(newEnd);
                add_end(newEnd);
            ,
            error: function () 
                alert("There was an error")
            
        );

【讨论】:

这行得通。如果有人想知道,$crf_token 的值来自基本身份验证登录期间拾取的 csrftoken cookie。【参考方案3】:

我认为这是一个 cookie 问题。

永久解决方案:如果您使用的是 Postman,首先,通过单击“X”清除现有的 cookie。然后添加正确的cookie。

临时解决方案(用于调试):在您的 settings.py 中试试这个:

'DEFAULT_AUTHENTICATION_CLASSES': [
    # 'rest_framework.authentication.SessionAuthentication',
    'rest_framework.authentication.BasicAuthentication',
]

【讨论】:

清除 cookie 解决了我的问题【参考方案4】:

1- 搜索 Cookie 标头

2- 将 csrftoken 与 sessionid 分开

3- 添加 X-CSRFToken=..the csrftoken that you extract in step 2.. 见下文

4- 再次发帖

【讨论】:

【参考方案5】:

我们遇到了这个问题,结果证明是 Postman 的错。他们自动发送csrftokensessionid 默认值,我们没有在标头中传递这些值。按照本教程帮助解决了这个问题:https://avilpage.com/2019/02/django-tips-csrf-token-postman-curl.html

【讨论】:

【参考方案6】:

解决此错误的最简单方法,我在here 上找到。它非常适合我。

步骤:

继承 SessionAuthentication 类:

from rest_framework.authentication import SessionAuthentication, BasicAuthentication 

class CsrfExemptSessionAuthentication(SessionAuthentication):

    def enforce_csrf(self, request):
        return  # To not perform the csrf check previously happening

然后在您创建的 APIView 中,执行以下操作:

class Object(APIView):
    authentication_classes = (CsrfExemptSessionAuthentication, BasicAuthentication)

    def post(self, request, format=None):

这将使您保持登录状态,并且您的 CSRF 令牌将不再检查此 APIView。

【讨论】:

你已经向 CSRF 攻击敞开了大门。【参考方案7】:

我遇到了类似的问题,我已经将我的网址包装在 csrf_exempt 方法下 -

from django.views.decorators.csrf import csrf_exempt

url(r'^api/v1/some-resource$', csrf_exempt(SomeApiView.as_view())),

【讨论】:

【参考方案8】:

对我有用的最简单的解决方案是:

在 AJAX POST 调用的标头中添加 CSRF 令牌,这可以通过包含这一行代码来完成

headers:  "X-CSRFToken": 'csrf_token' ,

这行应该加在success上面

【讨论】:

【参考方案9】:

从 cookie 中获取令牌:

function readCookie(name) 
    var nameEQ = name + "=";
    var ca = document.cookie.split(';');
    for(var i=0;i < ca.length;i++) 
        var c = ca[i];
        while (c.charAt(0)==' ') c = c.substring(1,c.length);
        if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
    
    return null;


var csrftoken = readCookie('csrftoken');

在标头 POST 请求中发送令牌:

  this.$http.post(server,params: foo: 'bar', headers: "X-CSRFToken":csrftoken ).then(function (response) 
            this.response = response.data;
        ,
        function (response) 
            console.log(response);
        );

【讨论】:

这是唯一有实际代码的有效答案。【参考方案10】:

我遇到了类似的问题,我用csrf_exempt 包装了视图,但仍然遇到错误。结果发现我弄错了 URL,所以它被解析为“未找到”回调(CSRF 并没有豁免),因此在我被告知 URL 错误之前抛出了一个异常。

【讨论】:

对我来说,我只是忘记在我的 URL 中添加结尾的“/”。就像@kokociel 所说,这个问题与 CSRF 无关,而是 URL 没有解析到我的任何端点。【参考方案11】:
// USING AJAX TO UPDATE DATABASE THROUGH REST API
function getCookie(name) 
    var cookieValue = null;
    if (document.cookie && document.cookie !== '') 
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) 
            var cookie = jQuery.trim(cookies[i]);
            if (cookie.substring(0, name.length + 1) === (name + '=')) 
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            
        
    
    return cookieValue;


var csrftoken = getCookie('csrftoken');

function csrfSafeMethod(method) 
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));


$.ajaxSetup(
    beforeSend: function (xhr, settings) 
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) 
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        
    
);

【讨论】:

【参考方案12】:

这发生在我使用邮递员测试 rest-auth 注册时 发生这种情况是因为邮递员发送了错误的标头,一些旧的 cookie 和错误的内容类型,我认为这是某种错误,或者我错了

解决方案:所以我禁用了默认标题

手动输入的内容类型和json正文(POST请求)

然后重新启用所需的标头

【讨论】:

【参考方案13】:

当您在 Apache 服务器上托管 django 网站时。 带有 TokenAuthentication 和 SessionAuthentication 的 Django REST 框架将得到 ​​p>

CSRF 失败:CSRF 令牌丢失或不正确

要修复这个打开的 Apache 配置文件 - httpd.conf 添加以下行:

WSGIPassAuthorization On

【讨论】:

【参考方案14】:

在settings.py文件中

INSTALLED_APPS = [
...
...
...
...
'rest_framework.authtoken',
...
]

REST_FRAMEWORK = 
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.TokenAuthentication',
    ),


在项目 urls.py 中

from rest_framework.authtoken import views

urlpatterns = [
    ....
    path('api-token-auth/',views.obtain_auth_token,name='api-token-auth')

]

打开终端

$ pip3 install httpie
$ python3 manage.py createsuperuser # if not created
$ http POST http://localhost:8000/api-token-auth/ username="username" password = "password"   # You will get token key (Just copy it) ex:a243re43fdeg7r4rfgedwe89320

您的令牌密钥也将自动保存在您的数据库中

转到邮递员标题(如示例) 例如:screenshot from postman ,where and how to paste accessed toke

然后插入你的令牌密钥。

You can take reference to get token key from this video

【讨论】:

【参考方案15】:

我在 postman 中测试 API 时遇到了同样的问题,我通过在 Postman 中为该请求清理缓存解决了这个问题。

【讨论】:

【参考方案16】:

django1.8 python2.7


    "detail": "CSRF Failed: CSRF token missing or incorrect."

我通过使用其他 http 方法来修复它; 哦,我又面对了,这次是因为我粘贴了,有一些看不见的字符

【讨论】:

Here are a few tips on how to make your answer great

以上是关于CSRF 失败:CSRF 令牌丢失或不正确的主要内容,如果未能解决你的问题,请参考以下文章

Django --CSRF 令牌丢失或不正确

Django - CSRF 令牌丢失或不正确

Django - 403 禁止。 CSRF 令牌丢失或不正确

Django 表单中的 CSRF 令牌丢失或不正确

Django Rest Framework,ajax POST 工作,但 PATCH 抛出 CSRF 失败:CSRF 令牌丢失或不正确

Django:CSRF 令牌丢失或不正确。 / 避免 % csrf_token %