一、详解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. 通道的分离与合并,ROI,

    通道的分离与合并 class Program { static void Main(String[] args) { Mat img = CvInvoke.Imread(@"C:\Users ...

  2. [转帖]jdk8 Metaspace 调优

    jdk8 Metaspace 调优 https://blog.csdn.net/bolg_hero/article/details/78189621 转帖 简介 从JDK8开始,永久代(PermGen ...

  3. 【转贴】Windows常用命令实例

    Windows常用命令实例 https://www.cnblogs.com/linyfeng/p/6261629.html 熟练使用DOS常用命令有助于提高工作效率. 1.windows+R:打开运行 ...

  4. 索引及explain 详解

    索引的分类: 普通索引:仅加速查询 唯一索引:加速查询 + 列值唯一(可以有null) 主键索引:加速查询 + 列值唯一(不可以有null)+ 表中只有一个 组合索引:多列值组成一个索引,专门用于组合 ...

  5. HDU-5238 Calculator

    题目描述 给定一个关于 \(x\) 的表达式,形如下例:\(×4+2^3+8×6\) 按如下方法计算:\((((x×4)+2)^3+8)×6\) 运算符只有 加号,乘号,幂运算三种,给定的式子中有 \ ...

  6. 蚂蚁分类信息商家发布文章、商品外链及远程图片自动添加nofollow属性

    蚂蚁商户发布文章.商品是可以添加外链或者直接用外部图片,但是这对分类网站运营不利. 所以要对外链进行过滤,演示网站保洁,蚂蚁分类的源码. 下面就说下怎么处理自动给外链自动加上nofollow属性. 1 ...

  7. vue-router和webpack懒加载,页面性能优化篇

    在vue单页应用中,当项目不断完善丰富时,即使使用webpack打包,文件依然是非常大的,影响页面的加载.如果我们能把不同路由对应的组件分割成不同的代码块,当路由被访问时才加载对应的组件(也就是按需加 ...

  8. jQuery导出word文档

    DDoc.js function DDoc() { this.data = []; this.relationData = []; this.listCount = 0; this.counter = ...

  9. Fluent API

    fluent api用于onmodelcreating里,可以实现比attribute更强更灵活的配置 public partial class StoreDBContext : DbContext ...

  10. 第一章 T-SQL查询和编程基础 T-SQL语言基础(2)

    T-SQL查询和编程基础 (2) 1.3 创建表和定义数据完整性 注意:表是属于架构,而架构又是属于数据库的 -- Create a database called testdb IF DB_ID(' ...