一、详解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中间件的更多相关文章

  1. django—csrf中间件校验流程

    CSRF(跨站请求伪造)是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法. 这利用了web中用户身份验证的一个漏洞:简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求 ...

  2. 30.Django CSRF 中间件

    CSRF 1.概述 CSRF(Cross Site Request Forgery)跨站点伪造请求,举例来讲,某个恶意的网站上有一个指向你的网站的链接,如果某个用户已经登录到你的网站上了,那么当这个用 ...

  3. 7.Django CSRF 中间件

    CSRF 1.概述 CSRF(Cross Site Request Forgery)跨站点伪造请求,举例来讲,某个恶意的网站上有一个指向你的网站的链接,如果某个用户已经登录到你的网站上了,那么当这个用 ...

  4. django csrf 中间件

    CSRF和中间件 CSRF使用 说明csrf存在cookie中 全局使用 MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', ...

  5. Django对中间件的调用思想、csrf中间件详细介绍、Django settings源码剖析、Django的Auth模块

    目录 使用Django对中间件的调用思想完成自己的功能 功能要求 importlib模块介绍 功能的实现 csrf中间件详细介绍 跨站请求伪造 Django csrf中间件 form表单 ajax c ...

  6. Python之路-(Django(csrf,中间件,缓存,信号,Model操作,Form操作))

    csrf 中间件 缓存 信号 Model操作 Form操作 csrf: 用 django 有多久,我跟 csrf 这个概念打交道就有久了. 每次初始化一个项目时都能看到 django.middlewa ...

  7. Django的csrf中间件

    csrf中间件 ​ csrf 跨站请求伪造 ​ 补充两个装饰器: ​ from django.views.decorators.csrf import csrf_exempt,csrf_protect ...

  8. csrf 跨站请求伪造相关以及django的中间件

    django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware来完成. 1.django中常用的中间件? - proces ...

  9. python 全栈开发,Day87(ajax登录示例,CSRF跨站请求伪造,Django的中间件,自定义分页)

    一.ajax登录示例 新建项目login_ajax 修改urls.py,增加路径 from app01 import views urlpatterns = [ path('admin/', admi ...

  10. Django 中CSRF中间件 'django.middleware.csrf.CsrfViewMiddleware',

    1.Django中CSRF中间件的工作原理及form表单提交需要添加{% csrf_token %}防止出现403错误 CSRF # 表示django全局发送post请求均需要字符串验证功能:防止跨站 ...

随机推荐

  1. jQuery I

    jQuery 两大特点: 链式编程:比如.show()和.html()可以连写成.show().html(). 隐式迭代:隐式对应的是显式.隐式迭代的意思是:在方法的内部进行循环遍历,而不用我们自己再 ...

  2. 实现文件上传功能(FileUpload组件)

    文件上传: 项目中经常用到文件上传. 自己实现文件上传,使用文件上传组件fileupload组件 1.指定表单类型为文件上传, enctype=”multipart/form-data” 2.提交方式 ...

  3. AS将一个项目导入到另一个项目中

    需求:有项目A,B.需要将B集成到A中,作为A的一个模块. 方法: 1.将B工程的app下面的build.gradle文字中  apply plugin: 'com.android.applicati ...

  4. [转帖]U盘安装centos 的方法

    通过U盘或CD/DVD装centos7,出现“dracut-initqueue timeout..."解决办法   1.在用CD/DVD挂载centos7镜像安装系统时,出现“dracut- ...

  5. [转帖]rpm包和deb分别是什么?

    https://www.cnblogs.com/hanfanfan/p/9133789.html 需要不停的学习才可以. 一.RMP 是 LINUX 下的一种软件的可执行程序,你只要安装它就可以了.这 ...

  6. 非旋(fhq)Treap小记

    前置知识:二叉搜索树 以下摘自 ↑: 二叉搜索树每次操作访问O(深度)个节点. 在刻意构造的数据中,树的形态会被卡成一条链,于是复杂度爆炸 它的复杂度与直接暴力删除类似. 但二叉搜索树扩展性强.更复杂 ...

  7. 安装Composer与PsySH

    Windows安装Composer 需要开启 openssl 配置:打开 php 目录下的 php.ini,将 extension=php_openssl.dll 前面的分号去掉就可以了. https ...

  8. JWT了解和实际使用

    一.JWT JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案.虫虫今天给大家介绍JWT的原理和用法. 1.跨域身份验证 Internet服务无法与用户身份验证分开.一般过程如下 ...

  9. thinkphp5.1 关于加载静态资源路径问题

    和thinkphp5.0不一样,thinkphp5.1的 thinkphp5.0的 直接在config.php文件中加入代码: <?phpreturn [ 'view_replace_str' ...

  10. 从入门到自闭之Python序列化

    序列化(背) json :将数据类型转换成字符串(序列化),将字符串装换成原数据类型(反序列),支持dict,list,tuple等,序列后都变成了列表 dumps,loads ------ 用于网络 ...