python, Django csrf token的问题
环境
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", line 67, in __call__ return self.application(environ, start_response) File "D:\Python27\lib\site-packages\django\core\handlers\wsgi.py", line 219, in __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 define 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-8from django.shortcuts import render_to_responseimport datetime@csrf_protectdef 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-8from django.shortcuts import render_to_response, RequestContextimport datetimefrom django.views.decorators.csrf import csrf_protect@csrf_protectdef 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-8from django.shortcuts import render_to_response, RequestContextimport datetime# from django.views.decorators.csrf import csrf_protect# @csrf_protectdef 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表单提交功能了。
python, Django csrf token的问题的更多相关文章
- django CSRF token missing or incorrect
django 异步请求时提示403 按照一般情况权限问题,python文件没有问题,仔细看了下response里有一句 CSRF token missing or incorrect.这个肯定是因为安 ...
- pythonのdjango CSRF简单使用
一.简介 django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成.而对于django中设置防跨站请求伪造功 ...
- django csrf token添加
#views.py from django.shortcuts import render_to_response, RequestContext from django.views.decorato ...
- Python - Django - CSRF
CSRF 攻击: 把 settings.py 中的 csrf 注释掉 正规网站: 创建修改密码页面 password.html: <!DOCTYPE html> <html lang ...
- Django中csrf token验证原理
我多年没维护的博客园,有一篇初学Django时的笔记,记录了关于django-csrftoekn使用笔记,当时几乎是照抄官网的使用示例,后来工作全是用的flask.博客园也没有维护.直到我的博客收到了 ...
- Django后台post请求中的csrf token
使用Requests库操作自己的Django站点,post登陆admin页面返回403,serverlog显示csrf token not set. csrf token是get登陆页面时服务器放在c ...
- django rest framework csrf failed csrf token missing or incorrect
django rest framework csrf failed csrf token missing or incorrect REST_FRAMEWORK = { 'DEFAULT_AUTHEN ...
- 对于 前端请求Django 后端服务出现403 Forbidden (CSRF token missing or incorrect.) 问题的解析
Django中使用ajax post向後臺傳送資料時403 Forbidden (CSRF token missing or incorrect.):的解決辦法 在Django中使用ajax post ...
- 使用Ajax (put delete ) django原生CBV 出现csrf token解决办法
原因 django原生CBV中对于 Ajax put 或 delete 请求进行封装时,会把请求数据放在 request.body里, 所以获取不到csrf token 方式一: 关闭csrf 中间件 ...
随机推荐
- php登陆绑定手机验证码使用阿里大于接口
https://doc.alidayu.com/doc2/index.htm 一条0.045 元 新注册送10块
- 测试开发系列之Python开发mock接口(一)
什么是mock接口呢,举个栗子,你在一家电商公司,有查看商品.购物.支付.发 货.收获等等等一大堆功能,你是一个测试人员,测测测,测到支付功能的时候,你就要调用第三方支付接口了,真实支付,直接扣你支付 ...
- Elasticsearch 知识点
Elasticsearch 知识点 table th:first-of-type { width: 200px; } table th:nth-of-type(2) { } 功能 curl命令 运行 ...
- stylus 知识点
循环的范围可以用两个小数点..表示,如(1..10)就是从1到10,并且包括1和10 for in 的循环范围写法: for index in 1 2 3 等价于: $li_length = 3 fo ...
- Net分布式系统整体框架
Net分布式系统之一:系统整体框架介绍 一.设计目的 从事.Net平台开发系统已有8年多了,一直思考搭建.Net分布式系统架构.基于window平台搭建的大型分布式系统不多,之前了解过myspace. ...
- 转-使用 CefSharp 在 C# App 中嵌入 Chrome 浏览器
使用 CefSharp 在 C# App 中嵌入 Chrome 浏览器 2016-09-23 分类:.NET开发.编程开发.首页精华0人评论 分享到:更多3 本文由码农网 – 小峰原创翻译,转载 ...
- theme为dialog的Activity如何充满全屏
转自:http://blog.csdn.net/fzh0803/article/details/9787615 分类: android_点滴记录2013-08-06 10:33 2005人阅读 评论 ...
- PHP include 和 require 语句 (调用其他php文件进来的方法)
PHP include 和 require 语句通过 include 或 require 语句,可以将 PHP 文件的内容插入另一个 PHP 文件(在服务器执行它之前). require 会生成致命错 ...
- 用linux的iconv函数 转换编码
inux shell 配置文件中默认的字符集编码为UTF-8 .UTF-8是unicode的一种表达方式,gb2312是和unicode都是字符的编码方式,所以说gb2312跟utf-8的概念应该不是 ...
- 6-3-2绕过appium的iOS测试
WDA自带的inspector 1.启动WDA Xcode启动:product-test,适合个人调试 命令行启动:适合持续集成 UDID=$(idevice_id -l) xcodebuild -p ...