django—csrf中间件校验流程
CSRF(跨站请求伪造)是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。
这利用了web中用户身份验证的一个漏洞:简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的。
例如,一个用户刚在某个网站登录过,认证信息记录在浏览器中,此时不小心点进了一个钓鱼网站,钓鱼网站仿照用户真正登录的网页布局,一旦用户执行涉及财产的操作,那么他填写完表单后发生给了真正的网站。其实真正的网站接收到的是钓鱼网站提前设置好的数据。那么这次攻击的目的就实现了。
django为了防止此类事件,便内置了csrf校验的中间件。
CSRF中间件流程
- class CsrfViewMiddleware(MiddlewareMixin):
- def _accept(self, request):
- request.csrf_processing_done = True
return None
- def _reject(self, request, reason):
- response = _get_failure_view()(request, reason=reason)
log_response(
'Forbidden (%s): %s', reason, request.path,
response=response,
request=request,
logger=logger,
)
return response
- def _get_token(self, request)
- def _set_token(self, request, response)
- def process_request(self, request)
- def process_view(self, request, callback, callback_args, callback_kwargs)
- def process_response(self, request, response)
从上述代码段中,不难看出CSRF中间件下共有7个方法。
其中前四个属于私有方法,后三个是中间件的方法。
1、process_request
一个请求到达视图函数前首先要经过中间件的process_request方法,所以从这个方法入手。
- def process_request(self, request):
csrf_token = self._get_token(request)
if csrf_token is not None:
# Use same token next time.
request.META['CSRF_COOKIE'] = csrf_token
该方法主要功能:
首先,需要通过_get_token方法从request对象中获取csrf_token;
然后,判断当获取到的csrf_token不为空时,将其赋值给META字典中的CSRF_COOKIE字段 。
_get_token方法:
- def _get_token(self, request):
if settings.CSRF_USE_SESSIONS:
try:
return request.session.get(CSRF_SESSION_KEY)
except AttributeError:
raise ImproperlyConfigured(
'CSRF_USE_SESSIONS is enabled, but request.session is not '
'set. SessionMiddleware must appear before CsrfViewMiddleware '
'in MIDDLEWARE%s.' % ('_CLASSES' if settings.MIDDLEWARE is None else '')
)
else:
try:
cookie_token = request.COOKIES[settings.CSRF_COOKIE_NAME]
except KeyError:
return None
csrf_token = _sanitize_token(cookie_token)
if csrf_token != cookie_token:
# Cookie token needed to be replaced;
# the cookie needs to be reset.
request.csrf_cookie_needs_reset = True
return csrf_token
a、先判断csrf的值是用什么方式存储,以便获取该值(默认是COOKIE存储,具体可见django的全局设置内的变量)
- from django.conf import global_settings
以下变量出现在global_settings文件中
- # Settings for CSRF cookie.
CSRF_COOKIE_NAME = 'csrftoken'
CSRF_COOKIE_AGE = 60 * 60 * 24 * 7 * 52
CSRF_COOKIE_DOMAIN = None
CSRF_COOKIE_PATH = '/'
CSRF_COOKIE_SECURE = False
CSRF_COOKIE_HTTPONLY = False
CSRF_COOKIE_SAMESITE = 'Lax'
CSRF_HEADER_NAME = 'HTTP_X_CSRFTOKEN'
CSRF_TRUSTED_ORIGINS = []
CSRF_USE_SESSIONS = False
b、从cookie中根据键的名称取出csrf_token的值
c、然后将cookie中取出的csrf_token传入_sanitize_token函数进行验证其是否合格,满足值的长度为64即合格,将该值原样返回
- def _sanitize_token(token):
# Allow only ASCII alphanumerics
if re.search('[^a-zA-Z0-9]', token):
return _get_new_csrf_token()
elif len(token) == CSRF_TOKEN_LENGTH:
return token
elif len(token) == CSRF_SECRET_LENGTH:
return _salt_cipher_secret(token)
return _get_new_csrf_token()
d、如果经过验证后得到的csrftoken和原先的值不一样时,在request对象上新增一个属性,表示需要重置csrftoken的值
e、如果一切正常,则将获取到的csrftoken返回给process_request方法
2、process_view
该方法位于process_request之后,且视图函数之前,所以接下来由它来处理request对象
- def process_view(self, request, callback, callback_args, callback_kwargs):
if getattr(request, 'csrf_processing_done', False):
return None
if getattr(callback, 'csrf_exempt', False):
return None
# Assume that anything not defined as 'safe' by RFC7231 needs protection
if request.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'):
#内部代码块执行校验相关操作
return self._accept(request)
a、根据反射机制判断 request对象中是否有csrf_processing_done属性,有的话就不作csrf验证
同理,判断对应的视图函数是否有csrf_exempt属性,有的话就不作csrf验证
b、如果本次请求的请求方式是
GET、HEAD、OPTIONS、TRACE中的一个,则接收本次请求,不需要csrf验证
c、如果本次请求的请求方式不再上述方式内,则进行csrf验证
- if request.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'):
if getattr(request, '_dont_enforce_csrf_checks', False):
return self._accept(request)
if request.is_secure():
#当请求协议为HTTPS时的一些操作
csrf_token = request.META.get('CSRF_COOKIE')
if csrf_token is None:
return self._reject(request, REASON_NO_CSRF_COOKIE)
# Check non-cookie token for match.
request_csrf_token = ""
if request.method == "POST":
try:
request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
except IOError:
pass
if request_csrf_token == "":
request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME, '')
request_csrf_token = _sanitize_token(request_csrf_token)
if not _compare_salted_tokens(request_csrf_token, csrf_token):
return self._reject(request, REASON_BAD_TOKEN)
- return self._accept(request)
1、排除掉接收本次请求的情况。
2、然后将csrftoken从META字典中取出(process_request方法内将csrftoken存入该字典,这个csrftoken来自于cookie)
3、判断csrftoken是否存在字典中,没有则拒绝本次请求
4、然后从POST提交的数据中获取csrftoken,或者从请求头中获取csrftoken
5、步骤4中获取到的csrftoken经过验证后,与cookie中存的csrftoken对比,如果不相等则拒绝本次请求。
反之,接收该请求
3、总结:
django的csrf校验,主要是:
a、从cookie中获取csrftoken
b、从POST发来的数据中获取csrftoken或者从请求头中获取key为“x-csrftoken”对应的csrftoken
然后比较a和b获取到的值是否一致
关于CSRF校验的装饰器
- from django.views.decorators.csrf import csrf_exempt, csrf_protect, ensure_csrf_cookie
1、csrf_exempt:加上该装饰器的视图函数,对该视图发起的请求不需要进行csrf校验,因为它会给视图函数加上csrd_exempt属性
- wrapped_view.csrf_exempt = True
2、csrf_protect:加上该装饰器的视图函数,必须进行csrf校验
3、ensure_csrf_cookie:加上该装饰器的视图函数,对应的页面中一定有存储csrf的cookie信息
补充:
cookie中必须有csrftoken的键值对时,才能够进行csrftoken校验
a、在页面中使用{% csrf_token%}生成隐藏的csrfmiddlewaretoken的input标签的同时,会设置cookie中的csrftoken键值对
b、给需要的视图函数加上ensure_csrf_cookie装饰器
django—csrf中间件校验流程的更多相关文章
- 30.Django CSRF 中间件
CSRF 1.概述 CSRF(Cross Site Request Forgery)跨站点伪造请求,举例来讲,某个恶意的网站上有一个指向你的网站的链接,如果某个用户已经登录到你的网站上了,那么当这个用 ...
- 7.Django CSRF 中间件
CSRF 1.概述 CSRF(Cross Site Request Forgery)跨站点伪造请求,举例来讲,某个恶意的网站上有一个指向你的网站的链接,如果某个用户已经登录到你的网站上了,那么当这个用 ...
- django csrf 中间件
CSRF和中间件 CSRF使用 说明csrf存在cookie中 全局使用 MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', ...
- Django对中间件的调用思想、csrf中间件详细介绍、Django settings源码剖析、Django的Auth模块
目录 使用Django对中间件的调用思想完成自己的功能 功能要求 importlib模块介绍 功能的实现 csrf中间件详细介绍 跨站请求伪造 Django csrf中间件 form表单 ajax c ...
- django csrf 处理简介
CSRF 是什么 CSRF 即跨站请求伪造,在用户不知情的情况下向有漏洞的网站发送请求.例如有正常网站A,恶意网站B, 用户若对A B 两个网站都有访问,B 可能伪造请求到 A,比如提交表单.至于具体 ...
- Django的csrf中间件
csrf中间件 csrf 跨站请求伪造 补充两个装饰器: from django.views.decorators.csrf import csrf_exempt,csrf_protect ...
- csrf 跨站请求伪造相关以及django的中间件
django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware来完成. 1.django中常用的中间件? - proces ...
- python 全栈开发,Day87(ajax登录示例,CSRF跨站请求伪造,Django的中间件,自定义分页)
一.ajax登录示例 新建项目login_ajax 修改urls.py,增加路径 from app01 import views urlpatterns = [ path('admin/', admi ...
- Django 中CSRF中间件 'django.middleware.csrf.CsrfViewMiddleware',
1.Django中CSRF中间件的工作原理及form表单提交需要添加{% csrf_token %}防止出现403错误 CSRF # 表示django全局发送post请求均需要字符串验证功能:防止跨站 ...
随机推荐
- 预科班D9
2020.09.17星期四 预科班D9 学习内容: 一.列表与字典的嵌套 大前提:将所有同学的信息存起来,取值需求 1.取第二个学生的性别 stus_info = [ {"name" ...
- JVM学习(三)JVM垃圾回收
一.引用的分类 在了解JVM垃圾回收机制之前,了解一下对象的引用类型是非常必要的. 强引用:GC时不会被回收 软引用:描述有用但不是必须的对象,在发生内存溢出异常之前被回收 弱引用:描述有用但不是必须 ...
- 深夜,我偷听到程序员要对session下手……
我是一个web服务器 我是一个web服务器,我的工作是给人类提供上网服务,我每天要为数以万计的人提供网页浏览服务. 已经是深夜了,我还在和手下几个兄弟为了一件事紧张讨论着. "老大,现在咱们 ...
- lua、python对比学习
一.基本数据类型: lua: nil(空).boolean(false和nil为假).number(数值).string(字符串).table(表).function(方法).thread (线程) ...
- 071 01 Android 零基础入门 01 Java基础语法 09 综合案例-数组移位 03 综合案例-数组移位-显示数组当中所有元素的的方法
071 01 Android 零基础入门 01 Java基础语法 09 综合案例-数组移位 03 综合案例-数组移位-显示数组当中所有元素的的方法 本文知识点:综合案例-数组移位-显示数组当中所有元素 ...
- 批处理文件的@echo off
转载:https://blog.csdn.net/zl1zl2zl3/article/details/79218448 @echo off 关闭回显 @echo on 打开回显 ...
- HTML & CSS & JavaScript 从一个表格到一个灰阶颜色表 02
工具1:HBuilder X 1.9.9.20190522 工具2:火狐浏览器 67.0.4 (64 位) 其实,我想使用表格,做一个这样的颜色表,如下图所示: 例 3:我们参照上图,基于上一个例子, ...
- 【题解】SP1811 LCS - Longest Common Substring
\(\color{purple}{Link}\) \(\text{Solution:}\) 题目要求找到两个串的最长公共子串.\(LCP\) 我们将两个串中间和末尾插入终止符,并弄到一棵后缀树上去. ...
- 4-K8S 部署Java应用及应用程序生命周期管理
1.在kubernetes中部署应用程序流程 准备项目源码-->编译构建-->产出war包,打包到镜像中-->推送到镜像仓库 获取源代码是开发人员提交代码的代码托管地址,有Git.S ...
- [KMP]字符串匹配算法
算法介绍: KMP是一种用来处理字符串匹配问题的算法,给你两个字符串A.B,让你回答B是否为A的子串,或者A中有多少子串等于B. 这题最暴力的做法是:枚举A中与B相等的子串的左端点,再判断是否与B相等 ...