环境

Window 7

Python2.7

Django1.4.1

sqlite3

问题

在使用Django搭建好测试环境后,写了一个提交POST表单提交留言的测试页面。

如图:

填写表单,点击“提交留言”按钮提交到服务器,却出现

Forbidden (403)

CSRF verification failed. Request aborted.

由于之前使用GET方式提交表单内容测试均正常,就以为这个问题估计是配置问题没细看后边的帮助提示直接在网上搜索解决方案。

一搜索发现相关网页很多,看来大家都遇到过这个问题,想着应该很快能解决。

解决方案1:失败

在settings.py的MIDDLEWARE_CLASSES加入

'django.middleware.csrf.CsrfResponseMiddleware',

最终settings.py MIDDLEWARE_CLASSES 配置部分的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    # add
    'django.middleware.csrf.CsrfResponseMiddleware',
    # add end
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    # Uncomment the next line for simple clickjacking protection:
    # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
)

保存,重新加载http://127.0.0.1/comment/add页面提交留言测试。

但在打开页面时出现500错误

赶紧看了一下控制台,发现如下错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Traceback (most recent call last):
  File "D:\Python27\lib\wsgiref\handlers.py", line 85, in run
    self.result = application(self.environ, self.start_response)
  File "D:\Python27\lib\site-packages\django\contrib\staticfiles\handlers.py", l
ine 67, in __call__
    return self.application(environ, start_response)
  File "D:\Python27\lib\site-packages\django\core\handlers\wsgi.py", line 219, i
n __call__
    self.load_middleware()
  File "D:\Python27\lib\site-packages\django\core\handlers\base.py", line 51, in
 load_middleware
    raise exceptions.ImproperlyConfigured('Middleware module "%s" does not defin
e a "%s" class' % (mw_module, mw_classname))
ImproperlyConfigured: Middleware module "django.middleware.csrf" does not define
 a "CsrfResponseMiddleware" class
[12/Sep/2012 11:00:35] "GET /comment/add/ HTTP/1.1" 500 59

大致的意思是我刚才在settings.py的MIDDLEWARE_CLASSES内添加的

'django.middleware.csrf.CsrfResponseMiddleware',

这个模块找不到,当时就有点郁闷了。网上一大堆都说是添加这个模块解决问题的,现在我本机上添加这个模块以后却提示没有找到模块?

为此,我重新把Django重新安装了一遍还是提示找不到模块。我只好到官网去看看手册,才发现Django新版已去掉这个模块。而我的Django正好是最新版本1.4只好放弃这个方案!

解决方案2:失败

在视图里使用@csrf_protect修饰

于是我在views.py文件里的add函数前加了@csrf_protect修饰符,如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Create your views here.
# coding=utf-8
from django.shortcuts import render_to_response
import datetime
 
@csrf_protect
def add(request):
    dict={}
    if request.method=="POST":
        comment=request.POST.get('comment','')
        submit_time=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        dict.setdefault('comment',comment)
        dict.setdefault('submit_time',submit_time)
    return render_to_response("comment/add.html",dict)

打开留言页面发现又有一个错误提示

NameError at /comment/add/

name 'csrf_protect' is not defined

提示找不到我刚才添加的修饰符@csrf_protect,应该是没有导入相关模块的问题,于是在我的视图views.py头部添加了一句代码导入相关模块

from django.views.decorators.csrf import csrf_protect

保存文件,重新打开网页,错误已清除。心中一阵大喜,以为OK了。谁知提交留言以后还是提示

Forbidden (403)

CSRF verification failed. Request aborted.

有点急了,只好继续搜索其它解决方案

解决方案3:失败

在模板页的from表单标签内添加{% csrf_token %}

添加以后的代码如下

重新打开页面测试,依旧提示:

Forbidden (403)

CSRF verification failed. Request aborted.

有点火大了!

解决方案4:成功

一番折腾不能解决问题,于是只好冷静的查看错误页面的提示帮助。

第一个提示表示浏览器要开启cookie,我的是IE9浏览器,毋庸置疑默认是开启的。

第三个与第四个方案我都已测试过,唯独第二个方案我没有仔细研究。问题会不会在哪里呢?于是到官网文档寻找

The view function uses RequestContext for the template, instead of Context.

这句英文大致的意思是要在视图里使用RequestContext这个方法,最终在官网文档找到了以下解决方案

在return render_to_response函数里加入context_instance=RequestContext(request),代码如下:

return render_to_response("comment/add.html",dict,context_instance=RequestContext(request))

重新运行网页,又提示新的错误

NameError at /comment/add/

global name 'RequestContext' is not defined

提示找不到RequestContext,估计是我没有导入RequestContext模块,于是在把

from django.shortcuts import render_to_response

改写成

from django.shortcuts import render_to_response,RequestContext

视图整体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Create your views here.
# coding=utf-8
from django.shortcuts import render_to_response, RequestContext
import datetime
from django.views.decorators.csrf import csrf_protect
 
@csrf_protect
def add(request):
    dict={}
    if request.method=="POST":
        comment=request.POST.get('comment','')
        submit_time=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        dict.setdefault('comment',comment)
        dict.setdefault('submit_time',submit_time)
    return render_to_response("comment/add.html",dict,context_instance=RequestContext(request))

重新运行网页正常,提交留言终于成功了

回顾优化

虽然折腾了半天才解决,但还是感觉有点糊里糊涂的。根据之前报错最后一条提示信息

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.

大致意思是如果settings.py的MIDDLEWARE_CLASSES里不开启CsrfViewMiddleware那么就必须要在视图里使用@csrf_protect模块修饰方法。我看看MIDDLEWARE_CLASSES里的设置,代码如下:

1
2
3
4
5
6
7
8
9
MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    # Uncomment the next line for simple clickjacking protection:
    # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
)

默认我的MIDDLEWARE_CLASSES已经给我开启了CsrfViewMiddleware这个模块。按照提示帮助,我可以把视图views.py里的修饰模块去掉应该也可以,于是注释了@csrf_protect修饰符与包含模块语句,最终代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Create your views here.
# coding=utf-8
from django.shortcuts import render_to_response, RequestContext
import datetime
# from django.views.decorators.csrf import csrf_protect
 
# @csrf_protect
def add(request):
    dict={}
    if request.method=="POST":
        comment=request.POST.get('comment','')
        submit_time=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        dict.setdefault('comment',comment)
        dict.setdefault('submit_time',submit_time)
    return render_to_response("comment/add.html",dict,context_instance=RequestContext(request))

测试成功!

什么是CSRF

问题是解决了,但我不禁回想为什么在Django里提交POST表单要配置那么麻烦(其实也不麻烦,但对新手来说就不一样了),于是搜索关键字看看,得知它是一种跨站请求伪造,黑客可以利用这个攻击站点。 而Django里的使用这个机制就是防止CSRF模式攻击,原理大致是当你打开页面的时候产生一个csrftokey种下cookie,然后当你提交表单 时会把本地cookie里的csrftokey值给提交服务器,服务器判断只有有效的csrftokey值才处理请求。

既然这样,我就查看了一下cookie信息,发现果真种了一个csrftokey值

右键HTML页面查看源代码,发现{% csrf_token %}位置替换成了一个input隐藏值

input隐藏标签值与cookie里的csrftoken值一致。

于是我做了一个测试,在from表单里把{% csrftoken %}标签直接替换成如上图的input标签,name与value保持一致,提交留言的时候服务器正常处理,测试成功。

不使用CSRF验证

Django提供了POST表单使用CSRF验证功能,感觉还是挺不错的。但在Django里能不能像普通的Form表单一样不使用CSRF验证功能呢?答案是肯定可以的。

1、我在settings.py的MIDDLEWARE_CLASSES把'django.middleware.csrf.CsrfViewMiddleware'注释

2、移出FROM表单里的{% csrf_token %}标记

3、不导入RequestContext模块,并把render_to_response()里的context_instance=RequestContext(request)去掉

重新运行网页测试提交留言正常。至此,应该可以判断出上边1步骤里的'django.middleware.csrf.CsrfViewMiddleware'语句开启了CSRF验证功能,默认是开启的,注释以后就关闭CSRF验证POST表单提交功能了。

支持一下(195)
 

python, Django csrf token的问题的更多相关文章

  1. django CSRF token missing or incorrect

    django 异步请求时提示403 按照一般情况权限问题,python文件没有问题,仔细看了下response里有一句 CSRF token missing or incorrect.这个肯定是因为安 ...

  2. pythonのdjango CSRF简单使用

    一.简介 django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成.而对于django中设置防跨站请求伪造功 ...

  3. django csrf token添加

    #views.py from django.shortcuts import render_to_response, RequestContext from django.views.decorato ...

  4. Python - Django - CSRF

    CSRF 攻击: 把 settings.py 中的 csrf 注释掉 正规网站: 创建修改密码页面 password.html: <!DOCTYPE html> <html lang ...

  5. Django中csrf token验证原理

    我多年没维护的博客园,有一篇初学Django时的笔记,记录了关于django-csrftoekn使用笔记,当时几乎是照抄官网的使用示例,后来工作全是用的flask.博客园也没有维护.直到我的博客收到了 ...

  6. Django后台post请求中的csrf token

    使用Requests库操作自己的Django站点,post登陆admin页面返回403,serverlog显示csrf token not set. csrf token是get登陆页面时服务器放在c ...

  7. django rest framework csrf failed csrf token missing or incorrect

    django rest framework csrf failed csrf token missing or incorrect REST_FRAMEWORK = { 'DEFAULT_AUTHEN ...

  8. 对于 前端请求Django 后端服务出现403 Forbidden (CSRF token missing or incorrect.) 问题的解析

    Django中使用ajax post向後臺傳送資料時403 Forbidden (CSRF token missing or incorrect.):的解決辦法 在Django中使用ajax post ...

  9. 使用Ajax (put delete ) django原生CBV 出现csrf token解决办法

    原因 django原生CBV中对于 Ajax put 或 delete 请求进行封装时,会把请求数据放在 request.body里, 所以获取不到csrf token 方式一: 关闭csrf 中间件 ...

随机推荐

  1. 【转】每天一个linux命令(49):at命令

    原文网址:http://www.cnblogs.com/peida/archive/2013/01/05/2846152.html 在windows系统中,windows提供了计划任务这一功能,在控制 ...

  2. GitHub + circleCI 自动构建/自动部署 应用

    GitHub + circleCI 自动构建/自动部署, 这里略过了单元测试,以部署 laravel 应用为例子 比起 gitlab + ansible + genkins 操作起来节省了很多硬件资源 ...

  3. java正则表达式学习

    1.简单认识正则: public class Test { public static void main(String[] args) { //简单认识正则 p("abc".ma ...

  4. Win CE 5.0 增加电池电量显示

    摘自 http://blog.csdn.net/li0531/article/details/8818243 同时只在右上角显示一个 Label 控件,因此代码量精简了很多. [DllImport(& ...

  5. shell 4注释

    单行注释 每一行加一个#号. #shell #!/bin/sh echo "#" #轻轻的我走了 #正如我轻轻的来 #我挥一挥衣袖 #不带走一片云彩 echo "#&qu ...

  6. PHP 序列化变量的 4 种方法

    摘自: PHP 序列化变量的 4 种方法 http://www.iteye.com/news/25668

  7. Tcprstat测试mysql响应时间

    Tcprstat测试mysql响应时间 一.tcprstat工具安装与使用 tcprstat 是一个基于 pcap 提取 TCP 应答时间信息的工具,通过监控网络传输来统计分析请求的响应时间. 使用方 ...

  8. 长短时记忆网络(LSTM)

    长短时记忆网络 循环神经网络很难训练的原因导致它的实际应用中很处理长距离的依赖.本文将介绍改进后的循环神经网络:长短时记忆网络(Long Short Term Memory Network, LSTM ...

  9. unity3d工程下的data file作用

    projectData文件夹中的data file: 1. Player settings – globalgamemanagers and globalgamemanagers.assets fil ...

  10. Out 与 Ref 关键字的区别

    相同点:既可以通过值也可以通过引用传递参数.通过引用传递参数允许函数成员更改参数的值,并保持该更改.若要通过引用传递参数, 可使用ref或out关键字.ref和out这两个关键字都能够提供相似的功效, ...