Django CSRF验证在POST请求时失败:引用检查失败-无引用

kgqe7b3p  于 2023-01-14  发布在  Go
关注(0)|答案(3)|浏览(154)

我的Django网站是HTTPS格式的,当我尝试从脚本向网站发布数据时,我收到了这个错误:"referer检查失败-没有referer"。这似乎是一个CSRF的问题,但我不知道如何解决它。
示例:

import requests
r = requests.post('https://mywebsite/mypage', data = {'key':'value'})
print r.text

输出如下:

[...]

<p>Reason given for failure:</p>
<pre>
Referer checking failed - no Referer.
</pre>

<p>In general, this can occur when there is a genuine Cross Site Request Forgery, or when
<a
href="https://docs.djangoproject.com/en/1.8/ref/csrf/">Django's
CSRF mechanism</a> has not been used correctly.  For POST forms, you need to
ensure:</p>

<ul>
<li>Your browser is accepting cookies.</li>

<li>The view function passes a <code>request</code> to the template's <a
href="https://docs.djangoproject.com/en/dev/topics/templates/#django.template.backends.base.Template.render"><code>render</code></a>
method.</li>

<li>In the template, there is a <code>{% csrf_token
%}</code> template tag inside each POST form that
targets an internal URL.</li>

<li>If you are not using <code>CsrfViewMiddleware</code>, then you must use
<code>csrf_protect</code> on any views that use the <code>csrf_token</code>
template tag, as well as those that accept the POST data.</li>

</ul>

[...]

在发送POST数据之前,我需要给我的头文件传递一个引用者吗?这会很不方便?或者我应该为这个页面禁用CSRF吗?
谢谢

hwamh0ep

hwamh0ep1#

AFAIK,这是CSRF的目的,避免发布来自未知来源的数据。你需要csrf令牌来发布django动态生成的数据。

lb3vh1jj

lb3vh1jj2#

升级Django可能会修复缺少Referer的错误。
从Django 4.0(发行说明)开始,后端会先检查Origin头文件,然后再回退到Referer头文件(源代码):

  1. CsrfViewMiddleware根据当前主机和CSRF_TRUSTED_ORIGINS设置验证Origin标头(如果浏览器提供)。这可以防止跨子域攻击。
    1.此外,对于HTTPS请求,如果没有提供Origin报头,CsrfViewMiddleware会执行严格的引用检查。这意味着即使子域可以设置或修改您的域中的Cookie,它也不能强制用户向您的应用发布,因为该请求不会来自您自己的确切域。
ycggw6v2

ycggw6v23#

您可能正在运行反向代理,例如nginx proxy_pass127.0.0.1:8000
在这种情况下,Django希望跨站伪造保护令牌匹配主机名127.0.0.1,但它们将来自一个普通域(例如example.com)。
| 预期来源|实际来源|
| - ------|- ------|
| http://127.0.0.1|https://example.com|
HTTP反向代理(example.com:80-〉localhost:3000)是在NodeJS应用程序中使用nginx的常用方法,但它在Django中并不适用
| 面向客户端的URL|服务器代理URL|
| - ------|- ------|
| https://example.com|http://127.0.0.1:3000|
最好通过Unix套接字运行Django,而不是通过端口(example.com:80-〉<socket>)。
| 面向客户端的URL|服务器代理URL|
| - ------|- ------|
| https://example.com|unix:/运行/示例. com. sock|
下面是如何使用Django、Gunicorn和nginx实现这一点:
假设你有一个Django项目根目录,其中包含一个系统文件夹(settings.pywsgi.py所在的文件夹):

export DJANGO_PROJECT_PATH=/path/to/django/root
export DJANGO_SETTING_FOLDER=system

首先,请确保您安装了Gunicorn,并且使用的是虚拟环境:

cd $DJANGO_PROJECT_PATH
source .venv/bin/activate  # <- Use a virtual environment
pip3 install gunicorn  # <- install Gunicorn in the venv

这将启动Django项目,类似于运行python3 manage.py runserver,只是你可以监听Unix套接字上的请求:

$DJANGO_PROJECT_PATH/.venv/bin/gunicorn  \
    --workers=3 \
    --access-logfile - \
    --bind unix:/run/example.com.sock \  # <- Socket
    --chdir=$DJANGO_PROJECT_PATH/ \
    $DJANGO_SETTING_FOLDER.wsgi:application

然后使用nginx创建一个HTTP代理,通过gunicon创建的套接字传递来自客户端的HTTP请求:
/etc/nginx/sites-enabled/example.com

server {
    listen 80;
    listen [::]:80;
    server_name example.com;

    # serve static files directly through nginx
    location /static/ {
        autoindex off;
        root /path/to/django/root;
    }

    # serve user-uploaded files directly through nginx
    location /media/ {
        autoindex off;
        root  /path/to/django/root;
    } 

    # You can do fun stuff like aliasing files from other folders
    location /robots.txt {
        alias /path/to/django/root/static/robots.txt;
    }

    # here is the proxy magic
    location / {
        include proxy_params;
        proxy_pass http://unix:/run/example.com.sock;  # <- the socket!
    }
}

确保重新启动nginx:

sudo service restart nginx

在这一切之后,你的csrf令牌应该与你的网站域名相匹配,你就可以登录并提交表单了。

相关问题