禁止访问(403)CSRF验证失败,请求被中止。失败原因:源检查失败,不匹配任何受信任的来源。

75

帮助

失败原因:

Origin checking failed - https://praktikum6.jhoncena.repl.co does not match any trusted origins.

通常情况下,这会在发生真正的跨站点请求伪造或Django的CSRF机制未正确使用时发生。对于POST表单,您需要确保:

Your browser is accepting cookies.
The view function passes a request to the template’s render method.
In the template, there is a {% csrf_token %} template tag inside each POST form that targets an internal URL.
If you are not using CsrfViewMiddleware, then you must use csrf_protect on any views that use the csrf_token template tag, as well as those that accept the POST data.
The form has a valid CSRF token. After logging in in another browser tab or hitting the back button after a login, you may need to reload the page with the form, because the token is rotated after a login.

因为您在Django设置文件中将DEBUG设置为True,所以您正在查看此页面的帮助部分。将其更改为False,只会显示最初的错误消息。

您可以使用CSRF_FAILURE_VIEW设置自定义此页面。

5个回答

178

检查你是否在使用Django 4.0。我曾经使用的是3.2版本,但在升级到4.0版本后出现了这个问题。

如果你正在使用4.0版本,那么这是我的解决方法。将这行代码添加到你的settings.py中。在3.2版本中并不需要,但现在如果没有它,我无法POST包含CSRF的表单。

CSRF_TRUSTED_ORIGINS = ['https://*.mydomain.com','https://*.127.0.0.1']

检查这行代码是否需要更改,例如如果你需要用http替换https

原因是在4.0版本中增加了对origin头的检查。

https://docs.djangoproject.com/en/4.0/ref/settings/#csrf-trusted-origins

在Django 4.0中更改:

旧版本中不执行Origin头检查


1
先生,我正在尝试从本地主机:300(ReactJS)向Django发出请求,并且我已经添加了CSRF_TRUSTED_ORIGINS = ['http://localhost:3000/'],但它仍然显示 Forbidden (Origin checking failed - http://localhost:3000 does not match any trusted origins.): /api/login/ ,您能帮我解决这个问题吗? - faijan memon
3
如果我已经使用ALLOWED_HOSTS设置从环境变量中获取值,那么将CSRF_TRUSTED_ORIGINS设置为相同的值是否有任何不合适之处?例如os.getenv('ALLOWED_HOSTS').split(',') - pspahn
这可能适用于某些情况,但并不是唯一的解决方案。请参见下面Chris的答案。(SECURE_PROXY_SSL_HEADER - Michael Herrmann
1
只有在实际进行跨域请求时才应这样做(即从 site.example.com 的页面提交表单到 api.example.com)。如果您不尝试执行此操作(罕见情况),则很可能是“SECURE_PROXY_SSL_HEADER”设置,如另一个答案所述。 - Kenny Loveall
我看到那个问题已经解决了,非常感谢你,兄弟。 - undefined

50

2022年3月更新:

如果您的Django版本"4.x.x":

python -m django --version

// 4.x.x

然后,如果错误如下所示:

起源检查失败-https://example.com不匹配任何受信任的起源。

将此代码添加到"settings.py"中:

CSRF_TRUSTED_ORIGINS = ['https://example.com']

根据您的情况,您遇到了以下错误:

起源检查失败 - https://praktikum6.jhoncena.repl.co 与任何受信任的来源都不匹配。

因此,您需要在您的“settings.py”中添加此代码:

CSRF_TRUSTED_ORIGINS = ['https://praktikum6.jhoncena.repl.co']

2
只有在实际进行跨域请求时(即从site.example.com的页面向api.example.com提交表单),才应该执行此操作。如果您没有尝试执行此(罕见)操作,则很可能是另一个答案中所述的SECURE_PROXY_SSL_HEADER设置。 - Kenny Loveall

49

来源和主机是同一域名

如果像我一样,当来源和主机是同一域名时出现错误。

可能是因为:

  1. 您正在通过HTTPS提供django应用程序,
  2. 您的django应用程序在代理后面,例如Nginx,
  3. 您忘记在您的settings.py中设置SECURE_PROXY_SSL_HEADER,例如SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') 和/或
  4. 您忘记在服务器配置中设置标头,例如对于Nginx:proxy_set_header X-Forwarded-Proto https;

在这种情况下:

  • 由于1,客户端浏览器的来源标头将是https://www.example.com
  • 由于2、3和4,request.is_secure()返回False
  • 这意味着由于django.middleware.csrf的第285行(将https://www.example.comhttp://www.example.com进行比较),_origin_verified()返回False
    def _origin_verified(self, request):
        request_origin = request.META["HTTP_ORIGIN"]
        try:
            good_host = request.get_host()
        except DisallowedHost:
            pass
        else:
            good_origin = "%s://%s" % (
                "https" if request.is_secure() else "http",
                good_host,
            )
            if request_origin == good_origin:
                return True

在更改此设置之前,请确保阅读https://docs.djangoproject.com/en/4.0/ref/settings/#secure-proxy-ssl-header中的警告!


4
实际上,这个答案是修复此错误的正确方法。它解决了两个问题,一个是CSRF检查,另一个是request.is_secure()值,在这种情况下应该返回True。通过更新CSRF_TRUSTED_ORIGINS,您可以解决它,但我认为这是一种hack方法,只解决了这个问题。 - Akshay Pratap Singh
1
这是大多数情况下的正确答案。即使您没有运行Web主机,像fly.io这样的部署平台也会发送这些标头给您的应用程序。 - Nils
但是如果我们想要在HTTP上使登录表单生效呢? - Conor
在NGINX中进行以下设置后,它对我起作用了:add_header P3P 'CP="ALL DSP COR PSAa PSDa OUR NOR ONL UNI COM NAV"'; - jesus.saad
我花了一周的时间来解决这个问题。这个答案解决了它。现在我可以删除@csrf_exempt了! - tumultous_rooster
1
这是正确的答案。但我建议将set_proxy_header X-Forwarded-Proto https;替换为set_proxy_header X-Forwarded-Proto $scheme;。这是一个更通用的解决方案 - 一个nginx服务器部分可以同时处理http和https流量。 - undefined

0

您可能因为在Proxmox上使用容器而出现此错误。
如果您的https域名通过内部http连接由Proxmox路由,那么您将会遇到此错误。

域名(https)=> Proxmox =>(http)=>带有Django的容器:CSRF ERROR

我曾经遇到过这个错误,并通过在我的CT上创建和签署证书来更改了通过Proxmox路由到我的容器的路由方式,以便通过https内部连接进行。

域名(hhtps)=> Proxmox =>(https)=>带有Django的容器

自此,Django上的CSRF错误消失了。


0
如果有人在使用.env,你必须使用env.list()
.env中,必须像这样设置CSRF来源。
CSRF_TRUSTED_ORIGINS=one.example.com two.example.com

并且可以在 settings.py 中像这样访问它

CSRF_TRUSTED_ORIGINS = env.list('CSRF_TRUSTED_ORIGINS')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接