Django CSRF Coo​​kie设置不正确 [英] Django CSRF cookie not set correctly

查看:286
本文介绍了Django CSRF Coo​​kie设置不正确的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更新7-18:



这是我的代理服务器的nginx配置:

  server {
listen 80;
server_name blah.com; #blah is intentional

access_log /home/cheng/logs/access.log;
error_log /home/cheng/logs/error.log;

location / {
proxy_pass http://127.0.0.1:8001;
}

location / static {
alias / home / cheng / diandi / staticfiles;
}

location / images {
alias / home / cheng / diandi / images;
}

client_max_body_size 10M;
}

这里是 nginx.conf

 用户www-data; 
worker_processes 4;
pid /var/run/nginx.pid;

events {
worker_connections 768;
#multi_accept on;
}

http {

##
#基本设置
##

sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;

include /etc/nginx/mime.types;
default_type application / octet-stream;

##
#日志设置
##

access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;

##
#Gzip设置
##

gzip_disablemsie6;

#启用Gzip压缩。
gzip on;

#为HTTP / 1.0和HTTP / 1.1启用压缩。
gzip_http_version 1.1;

#压缩级别(1-9)。
#5是大小和cpu使用之间的一个完美的折衷,提供大约
#75%减少大多数ascii文件(几乎相同的9级)。
gzip_comp_level 5;

#不要压缩任何已经很小,不太可能收缩的东西
#如果在所有(默认是20字节,这是坏的,通常导致
# gzip后的较大文件)。
gzip_min_length 256;

#甚至对通过代理连接到我们的客户端压缩数据,
#由Via标头(CloudFront需要)标识。
gzip_proxied any;

#当客户端的Accept-Encoding能力报头变化时,告诉代理缓存gzip和正常版本的资源

#避免了一个非gzip能力的客户端(这是非常罕见的
#今天)显示乱码,如果他们的代理给他们gzip版本的问题。
gzip_vary on;

#压缩标记有以下MIME类型之一的所有输出。
gzip_types
application / atom + xml
application / javascript
application / json
application / rss + xml
application / vnd.ms-fontobject
application / x-font-ttf
application / x-web-app-manifest + json
application / xhtml + xml
application / xml
application / x-javascript
font / opentype
image / svg + xml
image / x-icon
text / css
text / plain
text / javascript
text / js
text / x-component;

include /etc/nginx/conf.d/*.conf;
include / etc / nginx / sites-enabled / *;
}






更新7-15:



将代码复制到linux机器时,我只是替换了原始的源代码文件,但没有删除旧的.pyc文件,我认为这不会造成麻烦






以下是查看代码:

  from django.contrib.auth import authenticate,登录
从django.http import HttpResponseRedirect
从django.core.urlresolvers导入反向
从django.shortcuts import render

def login_view(request):
if request.method =='POST':
username = request.POST ['username']
password = request。 POST ['password']
user = authenticate(username = username,password = password)
next_url = request.POST ['next']
如果用户不是None:
如果user.is_active:
登录(请求,用户)
如果next_url:
返回HttpResponseRedirect(next_url)
return HttpResponseRedirect(reverse('diandi:list'))
else:
form = {'errors':True}
return render(request,'registration / login.html',{'form':form})


form = {'errors':False}
return render(request,'registration / login.html',{'form':form})






我有一个 CSRF cookie not set error from Django,但这不是因为我忘了在我的模板中包含 {%csrf_token%}



这是我观察到的:



访问登录页面#1尝试



请求头内, cookie 值为:

  csrftoken = yNG8ZmSI4tr2xTLoE9bys8JbSuu9SD34; 

在模板中:

 < input type =hiddenname =csrfmiddlewaretokenvalue =9CVlFSxOo0xiYykIxRmvbWyN5iEUHnPB> 



在Chrome上安装的Cookie插件中,实际的csrf cookie值设置为:

  9CVlFSxOo0xiYykIxRmvbWyN5iEUHnPB 



< h2>访问登录页面#2 try:

请求头 值为:

  csrftoken = 9CVlFSxOo0xiYykIxRmvbWyN5iEUHnPB; 

在模板中:

 < input type =hiddenname =csrfmiddlewaretokenvalue =Y534sU40S8iTubSVGjjh9KQl0FXesVsC> 



在Chrome上安装的Cookie插件中,实际的csrf cookie值设置为:

  Y534sU40S8iTubSVGjjh9KQl0FXesVsC 



< h2>模式

从上面的例子可以看出,请求头中的cookie值与实际的 csrfmiddlewaretoken 在形式和实际的cookie值被设置。



当前请求的cookie值匹配下一个请求标头的 Cookie值。






这里是我的`settings.py的一部分:

  DJANGO_APPS =(
'django.contrib.admin'
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',


THIRD_PARTY_APPS =(
'compressor',
'crispy_forms',
'django_extensions'
'floppyforms',
'multiselectfield',
'admin_highcharts',


LOCAL_APPS =(
'diandi_project',
'uer_application',


INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS

MIDDLEWARE_CLASSES =(
'django.middleware.security.SecurityMiddleware' ,
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
' django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django。 middleware.clickjacking.XFrameOptionsMiddleware',


TEMPLATES = [
{
'BACKEND':'django.template.backends.django.DjangoTemplates',
'DIRS':[str(ROOT_DIR.path('templates'))],
'APP_DIRS':True,
'OPTIONS':{
'context_processors':[
'django.template.context_processors.media',
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth .context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]

我使用 Django 1.9.5 python 2.7.10



一个解决方案





我删除了 djdt csrftoken 之外的所有Cookie,然后页面工作。



这里是请求中上面的图片的cookie值,这个限制可以防止csrftoken被进一步设置。

  Cookie:PSTM = 1466561622; BIDUPSID = 6D0DDB8084625F2CEB7B9D0F14F93391; BAIDUID = 326150BF5A6DFC69B6CFEBD67CA7A18B:FG = 1; BDSFRCVID = Fm8sJeC62leqR8bRqWS1u8KOKg9JUZOTH6ao6BQjXAcTew_mbPF_EG0PJOlQpYD-hEb5ogKK0mOTHvbP; H_BDCLCKID_SF = tJPqoCtKtCvbfP0k-tcH244HqxbXq-r8fT7Z0lOnMp05EnnjKl5M3qKOqJraJJ585Gbb5tOhaKj-VDO_e6u-e55LjaRh2PcM2TPXQ458K4__Hn7zep0aqJtpbt-qJjbOfmQBbfoDQCTDfho5b63JyTLqLq5nBT5Ka26WVpQEQM5c8hje-4bMXPkkQN3T-TJQL6RkKTCyyx3cDn3oyToVXp0njGoTqj-eJbA8_CtQbPoHHnvNKCTV-JDthlbLetJyaR3lWCnbWJ5TMCo1bJQCe-DwKJJgJRLOW2Oi0KTFQxccShPC-TP-Ll_qW-Q2LPQfXKjabpQ73l02VhcOhhQ2Wf3DM-oat4RMW20jWl7mWPQDVKcnK4-Xj533DHjP; BDUSS = 5TNmRvZnh2eUFXZDA5WXI5UG1HaXYwbzItaWt3SW5adjE1Nn5XbUVoWHZuYXBYQVFBQUFBJCQAAAAAAAAAAAEAAAC0JtydAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO8Qg1fvEINXSU; Hm_lvt_a7708f393bfa27123a1551fef4551f7a = 1468229606; Hm_lpvt_a7708f393bfa27123a1551fef4551f7a = 1468229739; BDRCVFR [feWj1Vr5u3D] = I67x6TjHwwYf0; BDRCVFR [dG2JNJb_ajR] = mk3SLVN4HKm; BDRCVFR [-pGxjrCMryR] = mk3SLVN4HKm; cflag = 15%3A3; H_PS_PSSID = 1424_20515_13289_20536_20416_19861_14994_11792; csrftoken = xUgSHybzHeIwusN0GvMgB1ATeRrPgcV1 

由于现在的网站功能,所有我有五个饼干,上述:



解决方案

这里是问题:您不能拥有包含字符'['或']'的cookie



在@ Todor的链接后发现了解决方案,然后我发现了这个 SO post 。基本上,在python 2.7.x中有一个错误,它不会解析带有']'值的cookie。错误修复在2.7.10。



我认为只要确认这个问题就好了。所以我挖通了所有的cookie,发现一个与下面的键/值:

 键:BDRCVFR [feWj1Vr5u3D] 
val:I67x6TjHwwYf0


$ b $ p

所以我在本地插入以下cookie并提交到服务器:

 键:test 
val:BDRCVFR [feWj1Vr5u3D]

登录页面工作,这意味着2.7.10确实修复了错误。



但是我意识到,括号中的键名实际上不在值中,所以我做了以下测试:

 键:[
val:I67x6TjHwwYf0

  key:] 
val:I67x6TjHwwYf0

登录过程和django显示:

  CSRF cookie未设置

因此,django或其依赖的python库不能正确解析名称中带有方括号的Cookie。如果任何人知道我应该提交这个错误,请让我知道(django或python)。



我要感谢大家谁留下了评论OP:@raphv ,@trinchet,@Phillip,@YPCrumble,@PeterBrittain和@Todor。非常感谢您与我一起调试。






更新:2016年7月20日



这个bug在Django 1.10中修复,只需要等待发布



更新:2016年7月19日



由于这篇文章的结果,我提交了错误报告给Django。我们将看看是否会在将来的版本中修复。


Update 7-18:

Here is my nginx config for the proxy server:

server {
    listen 80;
    server_name blah.com; # the blah is intentional

    access_log /home/cheng/logs/access.log;     
    error_log /home/cheng/logs/error.log;       

    location / {
        proxy_pass http://127.0.0.1:8001;         
    }

    location /static {
        alias /home/cheng/diandi/staticfiles;  
    }

    location /images {
        alias /home/cheng/diandi/images;
    }

    client_max_body_size 10M;
}

Here is nginx.conf:

user www-data;
worker_processes 4;
pid /var/run/nginx.pid;

events {
        worker_connections 768;
        # multi_accept on;
}

http {

        ##
        # Basic Settings
        ##

        sendfile on;
        tcp_nopush on;
        tcp_nodelay on;
        keepalive_timeout 65;
        types_hash_max_size 2048;

        include /etc/nginx/mime.types;
        default_type application/octet-stream;

        ##
        # Logging Settings
        ##

        access_log /var/log/nginx/access.log;
        error_log /var/log/nginx/error.log;

        ##
        # Gzip Settings
        ##

        gzip_disable "msie6";

        # Enable Gzip compressed.
        gzip on;

        # Enable compression both for HTTP/1.0 and HTTP/1.1.
        gzip_http_version  1.1;

        # Compression level (1-9).
        # 5 is a perfect compromise between size and cpu usage, offering about
        # 75% reduction for most ascii files (almost identical to level 9).
        gzip_comp_level    5;

        # Don't compress anything that's already small and unlikely to shrink much
        # if at all (the default is 20 bytes, which is bad as that usually leads to
        # larger files after gzipping).
        gzip_min_length    256;

        # Compress data even for clients that are connecting to us via proxies,
        # identified by the "Via" header (required for CloudFront).
        gzip_proxied       any;

        # Tell proxies to cache both the gzipped and regular version of a resource
        # whenever the client's Accept-Encoding capabilities header varies;
        # Avoids the issue where a non-gzip capable client (which is extremely rare
        # today) would display gibberish if their proxy gave them the gzipped version.
        gzip_vary          on;

        # Compress all output labeled with one of the following MIME-types.
        gzip_types
                application/atom+xml
                application/javascript
                application/json
                application/rss+xml
                application/vnd.ms-fontobject
                application/x-font-ttf
                application/x-web-app-manifest+json
                application/xhtml+xml
                application/xml
                application/x-javascript
                font/opentype
                image/svg+xml
                image/x-icon
                text/css
                text/plain
                text/javascript
                text/js
                text/x-component;

        include /etc/nginx/conf.d/*.conf;
        include /etc/nginx/sites-enabled/*;
}


Update 7-15:

When copying code to the linux machines, I simply replaced the original source code file but didn't delete the old .pyc files which I don't think will cause trouble right?


Here is the view code:

from django.contrib.auth import authenticate, login
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from django.shortcuts import render

def login_view(request):
    if request.method == 'POST':
        username = request.POST['username']
        password = request.POST['password']
        user = authenticate(username=username, password=password)
        next_url = request.POST['next']
        if user is not None:
            if user.is_active:
                login(request, user)
                if next_url:
                    return HttpResponseRedirect(next_url)
                return HttpResponseRedirect(reverse('diandi:list'))
        else:
            form = {'errors': True}
            return render(request, 'registration/login.html', {'form': form})

    else:
        form = {'errors': False}
        return render(request, 'registration/login.html', {'form': form})


I got one of those CSRF cookie not set error from Django, but this is not because I forgot to include the {% csrf_token %} in my template.

Here is what I observed:

Access login page #1 try

Inside the Request Header, the cookie value is:

csrftoken=yNG8ZmSI4tr2xTLoE9bys8JbSuu9SD34;

In the template:

<input type="hidden" name="csrfmiddlewaretoken" value="9CVlFSxOo0xiYykIxRmvbWyN5iEUHnPB">

In a cookie plugin that I installed on chrome, the actual csrf cookie value is set to:

9CVlFSxOo0xiYykIxRmvbWyN5iEUHnPB

Access login page #2 try:

Inside the Request Header, the cookie value is:

csrftoken=9CVlFSxOo0xiYykIxRmvbWyN5iEUHnPB;

In the template:

<input type="hidden" name="csrfmiddlewaretoken" value="Y534sU40S8iTubSVGjjh9KQl0FXesVsC">

In a cookie plugin that I installed on chrome, the actual csrf cookie value is set to:

Y534sU40S8iTubSVGjjh9KQl0FXesVsC

The pattern

As you can see from the examples above, the cookie value inside the Request Header differs from the actual csrfmiddlewaretoken in the form and the actual cookie value being set.

The cookie value of the current request matches the next request header's cookie value.


To help debugging, here is a portion of my `settings.py:

DJANGO_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
)

THIRD_PARTY_APPS = (
    'compressor',
    'crispy_forms',
    'django_extensions',
    'floppyforms',
    'multiselectfield',
    'admin_highcharts',
)

LOCAL_APPS = (
    'diandi_project',
    'uer_application',
)

INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS

MIDDLEWARE_CLASSES = (
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
)

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [str(ROOT_DIR.path('templates'))],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.media',
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

I am using Django 1.9.5 and python 2.7.10.

One "solution"

I have encountered this problem before, I can clear all my browser cookies and the site will function properly. But this problem will eventually come up again, so I am really hoping someone can help me out (I probably just made a really dumb mistake somewhere).

Update

Originally, I thought I made some mistakes while overriding the django.contrib.auth.view page, so I wrote my own login page handler and it still causes the issue.

Here is the core part of my login template:

{% block content %}
...

                <form method="post" action="{% url 'login' %}">
                    {% csrf_token %}

                    <div class="form-group">
                        <label for="username">username</label>
                        <input type="text" class="form-control" id="id_username" name="username">
                    </div>
                    <div class="form-group">
                        <label for="password">password</label>
                        <input type="password" class="form-control" id="id_password" name="password">
                    </div>

                    <input type="submit" class="btn btn-default" value="login" />
                    <input type="hidden" id="next" name="next" value="" />
                </form>

...

{% endblock %}

On the Linux machines, I have a nginx server setup as a reverse proxy which direct request on port 80 to 8001, and I am running the server using ./manage runserver localhost:8001 This is the only difference I can think of in terms of setup. Otherwise, all of the source code and settings file are identical.


I started deleting cookies but not all of them, this is what I see before deleting them:

I deleted all the cookies other than djdt and csrftoken, then the page worked. Could the deleted cookies somehow go over some limit which prevent the csrftoken which is further down the list from being set?

Here is the cookie value of the image above in the request header:

Cookie:PSTM=1466561622; BIDUPSID=6D0DDB8084625F2CEB7B9D0F14F93391; BAIDUID=326150BF5A6DFC69B6CFEBD67CA7A18B:FG=1; BDSFRCVID=Fm8sJeC62leqR8bRqWS1u8KOKg9JUZOTH6ao6BQjXAcTew_mbPF_EG0PJOlQpYD-hEb5ogKK0mOTHvbP; H_BDCLCKID_SF=tJPqoCtKtCvbfP0k-tcH244HqxbXq-r8fT7Z0lOnMp05EnnjKl5M3qKOqJraJJ585Gbb5tOhaKj-VDO_e6u-e55LjaRh2PcM2TPXQ458K4__Hn7zep0aqJtpbt-qJjbOfmQBbfoDQCTDfho5b63JyTLqLq5nBT5Ka26WVpQEQM5c8hje-4bMXPkkQN3T-TJQL6RkKTCyyx3cDn3oyToVXp0njGoTqj-eJbA8_CtQbPoHHnvNKCTV-JDthlbLetJyaR3lWCnbWJ5TMCo1bJQCe-DwKJJgJRLOW2Oi0KTFQxccShPC-tP-Ll_qW-Q2LPQfXKjabpQ73l02VhcOhhQ2Wf3DM-oat4RMW20jWl7mWPQDVKcnK4-Xj533DHjP; BDUSS=5TNmRvZnh2eUFXZDA5WXI5UG1HaXYwbzItaWt3SW5adjE1Nn5XbUVoWHZuYXBYQVFBQUFBJCQAAAAAAAAAAAEAAAC0JtydAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO8Qg1fvEINXSU; Hm_lvt_a7708f393bfa27123a1551fef4551f7a=1468229606; Hm_lpvt_a7708f393bfa27123a1551fef4551f7a=1468229739; BDRCVFR[feWj1Vr5u3D]=I67x6TjHwwYf0; BDRCVFR[dG2JNJb_ajR]=mk3SLVN4HKm; BDRCVFR[-pGxjrCMryR]=mk3SLVN4HKm; cflag=15%3A3; H_PS_PSSID=1424_20515_13289_20536_20416_19861_14994_11792; csrftoken=xUgSHybzHeIwusN0GvMgB1ATeRrPgcV1

Since the site functions now, all I have are five cookies instead of 14 like the image above:

解决方案

Here is the issue: You cannot have a cookie which key contains either the character '[' or ']'

I discovered the solution following @Todor's link, then I found out about this SO post. Basically there was a bug in python 2.7.x that does not parse cookies with ']' in the value. The bug was fixed in 2.7.10.

I thought it would be good to just confirm this issue. So I dug through all of the cookies and found one with the following key/value:

key: BDRCVFR[feWj1Vr5u3D]
val: I67x6TjHwwYf0

So I inserted the following cookie locally and submitted to the server:

key: test
val: BDRCVFR[feWj1Vr5u3D]

The login page worked, which means 2.7.10 indeed fixed the bug.

But then I realized that the square brackets are actually in the key name not in the value, so I did the following tests:

key: [
val: I67x6TjHwwYf0

and

key:]
val: I67x6TjHwwYf0

Both cookies break the login process and django displays:

CSRF cookie not set

So either django or a python library it relies on cannot parse cookies with square brackets in names properly. If anybody knows where I should submit this bug please let me know (django or python).

I would like to thank everybody who left a comment in the OP: @raphv, @trinchet, @Phillip, @YPCrumble, @PeterBrittain and @Todor. Thank you guys so much for debugging with me!


Update: July 20, 2016

This bug is fixed in Django 1.10, just have to wait for the release

Update: July 19, 2016

I filed a bug report to Django as the result of this post. We will see if it will be fixed in future releases.

这篇关于Django CSRF Coo​​kie设置不正确的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆