Django-csrf中间件
一、详解csrf原理
csrf要求发送post,put,或者delete请求的时候,是先以get方式发送请求,服务端响应时会分配一个随机字符串给客户端,客户端第二次发送post,put或delete请求的时携带上次分配的字符串到服务端进行校验。(大白话:用户开始的时候请求网站是发GET请求,之后服务端CSRF会携带一个随机字符型给客户端,当用户提前POST或put、delete请求的时候CSRF会校验随机字符串是不是合法的。)
二、Django中间件的CSRF
首先,我们知道Django中间件作用于整个项目。
在一个项目中,如果想对全局所有视图函数或视图类起作用时,就可以在中间件中实现,比如想实现用户登录判断,用户访问频率,基于用户的权限管理(RBAC)等都可以在Django中间件中来进行操作。
三、Django中间件的CSRF的源码解析:
class CsrfViewMiddleware(MiddlewareMixin): def _accept(self, request):
request.csrf_processing_done = True
return None def _reject(self, request, reason):
logger.warning(
'Forbidden (%s): %s', reason, request.path,
extra={
'status_code': 403,
'request': request,
}
)
return _get_failure_view()(request, reason=reason) 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 def _set_token(self, request, response):
if settings.CSRF_USE_SESSIONS:
request.session[CSRF_SESSION_KEY] = request.META['CSRF_COOKIE']
else:
response.set_cookie(
settings.CSRF_COOKIE_NAME,
request.META['CSRF_COOKIE'],
max_age=settings.CSRF_COOKIE_AGE,
domain=settings.CSRF_COOKIE_DOMAIN,
path=settings.CSRF_COOKIE_PATH,
secure=settings.CSRF_COOKIE_SECURE,
httponly=settings.CSRF_COOKIE_HTTPONLY,
)
patch_vary_headers(response, ('Cookie',)) 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 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 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():
referer = force_text(
request.META.get('HTTP_REFERER'),
strings_only=True,
errors='replace'
)
if referer is None:
return self._reject(request, REASON_NO_REFERER) referer = urlparse(referer) if '' in (referer.scheme, referer.netloc):
return self._reject(request, REASON_MALFORMED_REFERER) if referer.scheme != 'https':
return self._reject(request, REASON_INSECURE_REFERER) good_referer = (
settings.SESSION_COOKIE_DOMAIN
if settings.CSRF_USE_SESSIONS
else settings.CSRF_COOKIE_DOMAIN
)
if good_referer is not None:
server_port = request.get_port()
if server_port not in ('', ''):
good_referer = '%s:%s' % (good_referer, server_port)
else:
good_referer = request.get_host() good_hosts = list(settings.CSRF_TRUSTED_ORIGINS)
good_hosts.append(good_referer) if not any(is_same_domain(referer.netloc, host) for host in good_hosts):
reason = REASON_BAD_REFERER % referer.geturl()
return self._reject(request, reason) csrf_token = request.META.get('CSRF_COOKIE')
if csrf_token is None:
return self._reject(request, REASON_NO_CSRF_COOKIE) 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) def process_response(self, request, response):
if not getattr(request, 'csrf_cookie_needs_reset', False):
if getattr(response, 'csrf_cookie_set', False):
return response if not request.META.get("CSRF_COOKIE_USED", False):
return response self._set_token(request, response)
response.csrf_cookie_set = True
return response
Django中间件CSRF源码
从上面的源码找那个可以看到,CsrfViewMiddleware中间件中定义process_request,prcess_view和process_response三个方法
首先我们来看下process_request方法:
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 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
从Django项目配置文件夹中读取CSRF_USE_SESSIONS
的值,如果获取成功,则从session中读取CSRF_SESSION_KEY的值
,默认为'_csrftoken'
,如果没有获取到CSRF_USE_SESSIONS
的值,则从发送过来的请求中获取CSRF_COOKIE_NAME
的值,如果没有定义则返回None。
再来看process_view方法
在process_view方法中,先检查视图函数是否被csrf_exempt
装饰器装饰,如果视图函数没有被csrf_exempt装饰器装饰,则程序继续执行,否则返回None。接着从request请求头中或者cookie中获取携带的token并进行验证,验证通过才会继续执行与URL匹配的视图函数,否则就返回403 Forbidden
错误。
四、在实际项目中,会在发送POST,PUT,DELETE,PATCH请求时,在提交的form表单中添加{% csrf_token%}
<form action="" method="post">
{% csrf_token %}
<p>username:<input type="text" name="username"></p>
<p>target_account:<input type="text" name="target_user"></p>
<p>money:<input type="text" name="money"></p>
<input type="submit">
</form> #通过浏览器查看我们课一看到它给我们加了name="csrfmiddlewaretoken" value="rJ47FeK9T55wavvVJGY6UxdM1kTMHhTqotGfaXjXIK8Ahz2Uvs02yR9T8bBn5q2D"。
#如下面标签
<input type="hidden" name="csrfmiddlewaretoken" value="rJ47FeK9T55wavvVJGY6UxdM1kTMHhTqotGfaXjXIK8Ahz2Uvs02yR9T8bBn5q2D">
五、在遇到ajax的时候我们如何解决呢:
1.方式一:
#先在页面任意的位置上书写{% csrf_token %}
#然后在发送ajax请求的时候 通过标签查找获取随机字符串添加到data自定义对象即可
data:{'username':'jason','csrfmiddlewaretoken':$('input[name="csrfmiddlewaretoken"]').val()},
2.方式二:
data:{'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'},
3.方式三:
直接建一个js文件,拷贝代码,导入即可,你不需要做任何的CSRF相关的代码书写
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken'); function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
} $.ajaxSetup({
beforeSend: function (xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
六、CSRF相关的装饰器:
1.第一种情况:
from django.views.decorators.csrf import csrf_exempt,csrf_protect
# @csrf_exempt # 给谁装饰就不校验谁 csrf
def index(request):
return HttpResponse('index') @csrf_protect # 给谁装饰就给谁校验csrf
def login(request):
return HttpResponse('login')
2.第二种情况:
#当这两个装饰器在CBV上有何异同
# @method_decorator(csrf_exempt,name='post') # csrf_exempt不支持该方法加装饰器
@method_decorator(csrf_exempt,name='dispatch') # csrf_exempt这种方法支持
class MyIndex(views.View):
# @method_decorator(csrf_exempt) # 这种方法也是支持
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request,*args,**kwargs)
def get(self,request):
return render(request,'transfer.html')
# @method_decorator(csrf_exempt,name='post') # csrf_exempt不支持该方法
def post(self,request):
return HttpResponse('OK')
# csrf_exempt这个装饰器只能给dispatch装才能生效!!!!
3.第三种情况:
csrf_protect方式全都可以 跟你普通的装饰器装饰CBV一致!
class MyIndex(views.View):
@method_decorator(csrf_protect)
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request,*args,**kwargs)
def get(self,request):
return render(request,'transfer.html')
# @method_decorator(csrf_protect) # 可以
def post(self,request):
return HttpResponse('OK')
Django-csrf中间件的更多相关文章
- django—csrf中间件校验流程
CSRF(跨站请求伪造)是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法. 这利用了web中用户身份验证的一个漏洞:简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求 ...
- 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 ...
- Python之路-(Django(csrf,中间件,缓存,信号,Model操作,Form操作))
csrf 中间件 缓存 信号 Model操作 Form操作 csrf: 用 django 有多久,我跟 csrf 这个概念打交道就有久了. 每次初始化一个项目时都能看到 django.middlewa ...
- 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请求均需要字符串验证功能:防止跨站 ...
随机推荐
- LCTF (easyeasy-200)
首先安装,看看app是什么样的. 有点奇怪,没有点击确定的按钮.然后拖到JEB反编译. 要求输入的字符串的长度要在35-39之间(包括边界值),然后会调用Format().form函数.如下图. 可以 ...
- Nginx实现负载均衡的方式有哪几种呢?
什么是负载均衡 当一台服务器的单位时间内的访问量越大时,服务器压力就越大,大到超过自身承受能力时,服务器就会崩溃.为了避免服务器崩溃,让用户有更好的体验,我们通过负载均衡的方式来分担服务器压力. 我们 ...
- MariaDB(第三章)select
基本查询 ``` --查询基本使用(条件,排序,聚合函数,分组,分页) --创建学生表 create table students ( id int unsigned not null auto_in ...
- MSSQL 索引
INCLUDE索引作用:减少 key lookup所带来的性能开销. 效率主要体现在覆盖查询(建的索引为覆盖索引),在查询时把SELECT显示列放在INCLUDE里作为非索引健列,不用于查询只显示在结 ...
- ABC050D/ARC066D Xor Sum
题目链接 题目大意 可表为 $(a \xor b, a + b)$ 的二元组有多少个? $a, b$ 满足下列约束条件: ① $a, b$ 是非负整数: ② $a + b \le N$,$N$ 是给定 ...
- [转]C#集合类型大揭秘
作者:撸码那些事 来源:https://www.cnblogs.com/songwenjie/p/9185790.html 集合是.NET FCL(Framework Class Library)的重 ...
- 区间最值的优秀数据结构---ST表
ST表,听起来高大上,实际上限制非常多,仅仅可以求最值问题: 为什么?先从原理看起: st表运用了倍增的思想:st[i][j] = min(st[i][j - 1],st[i + 2^(j - 1)) ...
- spark教程(六)-Python 编程与 spark-submit 命令
hadoop 是 java 开发的,原生支持 java:spark 是 scala 开发的,原生支持 scala: spark 还支持 java.python.R,本文只介绍 python spark ...
- QuickSort(快排)的JAVA实现
QuickSort的JAVA实现 这是一篇算法课程的复习笔记 用JAVA对快排又实现了一遍. 先实现的是那个easy版的,每次选的排序轴都是数组的最后一个: package com.algorithm ...
- Vue初始化一个项目
@1 npm install -g @vue/cli-init vue init webpack projectName @2 cnpm install -g @vue/cli vue create ...