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请求均需要字符串验证功能:防止跨站 ...
随机推荐
- C#开发PACS医学影像处理系统(十四):处理Dicom影像窗宽窗位
概念解释(网络资料): 窗宽: 窗宽指CT图像所显示的CT 值范围.在此CT值范围内的组织结构按其密度高低从白到黑分为16 个灰阶以供观察对比.例如,窗宽选定为100 Hu ,则人眼可分辨的CT值为1 ...
- Jenkins+Git+Gitlab+Ansible实现持续集成自动化部署动态网站(7)
项目前言 在上一篇博客<Jenkins+Git+Gitlab+Ansible实现持续化集成一键部署静态网站(一)–技术流ken>中已经详细讲解了如何使用这四个工具来持续集成自动化部署一个静 ...
- Linux里隐藏的计算器,你知道它的奥秘吗?
Linux里隐藏的计算器,你知道它的奥秘吗? 大家都知道,windows下有个计算器工具,我们在工作生活中经常使用到它.但是,你可知Linux下也同样有个计算器吗? 当然,良许说的是命令行下的计算器工 ...
- hystrix源码小贴士之调用异常处理
executeCommandAndObserve方法处理onerror异常. return execution.doOnNext(markEmits) .doOnCompleted(markOnCom ...
- 新手接触springboot
新手使用springboot或者说,刚接触java行业,有些不明白的就是项目的架构是怎么样的,我今天在这儿稍微整理了一下 有些新手可能在想,springboot是怎么解决最原始的增-删-改-查, 快速 ...
- maven打包(jar)类型错误
maven项目打包测试环境时部署发现是开发环境.确认打包命令无误, 此情况下将target内容全部删除,重新打包即可.是全部删除.
- springboot:This application has no explicit mapping for /erro
springboot启动没有报错,但是访问的时候返回如上图的错误.看报错内容感觉是没有这个mapping对应的接口.但是确实写了. 最终发现是因为springboot的启动类放的位置不对.启动类所在的 ...
- 使用SpringBoot的方式配置过滤器
springboot 不存在web.xml 那么如何配置过滤器呢 springboot提供了一种方式 通过spring容器配置 @Bean public FilterRegistrationBean ...
- Linux环境下C++调试的三板斧
调试解决程序的漏洞,是程序员最基本的技能之一.用惯了图形化IDE,在目前使用gtest框架进行单元测试,需要通过xshell远程连接Linux虚拟机进行C++代码的调试时,觉得很不适应.经过几天查资料 ...
- 错误: 在类中找不到 main 方法, 请将 main 方法定义为:    public static void main(String[] args) 否则 JavaFX 应用程序类必须扩展javafx.application.Application 。
昨天在eclipse编写JAVA程序时,遇到一个问题: 错误: 在类中找不到 main 方法, 请将 main 方法定义为: public static void main(String[] a ...