Django---CSRF的装饰器,CSRF的流程,JSON数据格式,ajax技术(基于JQ实现)

mac2022-06-30  63

Django---CSRF的装饰器,CSRF的流程,JSON数据格式,ajax技术(基于JQ实现)

一丶CSRF相关的装饰器

from django.utils.decorators import method_decorator # 给cbv加上装饰器 from django.views import View from django.views.decorators.csrf import csrf_exempt, csrf_protect ### 在FBV模式下 # csrf_exempt 豁免csrf校验 # csrf_protect 强制进行csrf校验 ''' csrf_exempt: #豁免,不进行csrf校验 csrf_protect: #强制执行csrf校验 ''' @csrf_exempt #豁免,不进行csrf校验 def csrf_check(request): return render(request,'csrf_check.html') ### 在CBV模式下 # csrf_exempt要加在CBV上,只能加dispatch上 @method_decorator(csrf_exempt,name='dispatch') # 豁免csrf 和 强制csrf ,在CBV上必须添加在dispatch方法上 class CSRF_CHECK(View): def post(self,request): return HttpResponse('post,ok') def get(self,request): return render(request,'csrf_check.html')

二丶CSRF的流程

   1.想要通过csrf校验的前提是. 必须有csrftoken的cookie.

### 生成 input标签 携带csrf的值 # 1. {% csrf_token %} <input type="hidden" name="csrfmiddlewaretoken" value="uVC0dQAf4R9cIfT57OUGFgQTiggYFUD4qwhBYPVLJSwPN2RoiMQSWGNvpFnnkmAX"> # 2. 浏览器中的session中存在csrftoken值 # csrftoken WK1xwuRTVyVLDMTfgsx8cpPDOJZPCAhZSlG8htcpAzioIzRyrqtktPMfV86eh2eS from django.views.decorators.csrf import ensure_csrf_cookie # 确保有session的值 @method_decorator(ensure_csrf_cookie) # ensure_csrf_cookie 确保响应的数据中包含session的csrftoken值 def get(self,request): return render(request,'csrf_check.html')

​   2.从cookie中获取csrftoken的值 与 POST提交的数据中的csrfmiddlwaretoken的值做比对

# 如果从request.POST中获取不到csrfmiddlewaretoken的值,会尝试从请求头中获取x-csrftoken的值,并且拿这个值与csrftoken的值做对比,对比成功也能通过校验。

​ CSRF源码 如下:

#### csrf的源码 from django.middleware.csrf import CsrfViewMiddleware ### 主要了解 三个方法: # def process_request(self, request): 处理请求 # def process_view(self, request, callback, callback_args, callback_kwargs): 视图处理 # def process_response(self, request, response): 响应处理 class CsrfViewMiddleware(MiddlewareMixin): """ Middleware that requires a present and correct csrfmiddlewaretoken for POST requests that have a CSRF cookie, and sets an outgoing CSRF cookie. This middleware should be used in conjunction with the csrf_token template tag. """ # The _accept and _reject methods currently only exist for the sake of the # requires_csrf_token decorator. def _accept(self, request): # Avoid checking the request twice by adding a custom attribute to # request. This will be relevant when both decorator and middleware # are used. 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, ) # Set the Vary header since content varies with the CSRF cookie. patch_vary_headers(response, ('Cookie',)) def process_request(self, request): csrf_token = self._get_token(request) # 从cookie中获取csrftoken的cookie值 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 # Wait until request.META["CSRF_COOKIE"] has been manipulated before # bailing out, so that get_token still works 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'): if getattr(request, '_dont_enforce_csrf_checks', False): # Mechanism to turn off CSRF checks for test suite. # It comes after the creation of CSRF cookies, so that # everything else continues to work exactly the same # (e.g. cookies are sent, etc.), but before any # branches that call reject(). return self._accept(request) if request.is_secure(): # Suppose user visits http://example.com/ # An active network attacker (man-in-the-middle, MITM) sends a # POST form that targets https://example.com/detonate-bomb/ and # submits it via JavaScript. # # The attacker will need to provide a CSRF cookie and token, but # that's no problem for a MITM and the session-independent # secret we're using. So the MITM can circumvent the CSRF # protection. This is true for any HTTP connection, but anyone # using HTTPS expects better! For this reason, for # https://example.com/ we need additional protection that treats # http://example.com/ as completely untrusted. Under HTTPS, # Barth et al. found that the Referer header is missing for # same-domain requests in only about 0.2% of cases or less, so # we can use strict Referer checking. 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) # Make sure we have a valid URL for Referer. if '' in (referer.scheme, referer.netloc): return self._reject(request, REASON_MALFORMED_REFERER) # Ensure that our Referer is also secure. if referer.scheme != 'https': return self._reject(request, REASON_INSECURE_REFERER) # If there isn't a CSRF_COOKIE_DOMAIN, require an exact match # match on host:port. If not, obey the cookie rules (or those # for the session cookie, if CSRF_USE_SESSIONS). 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 ('443', '80'): good_referer = '%s:%s' % (good_referer, server_port) else: # request.get_host() includes the port. good_referer = request.get_host() # Here we generate a list of all acceptable HTTP referers, # including the current host since that has been validated # upstream. 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: # No CSRF cookie. For POST requests, we insist on a CSRF cookie, # and in this way we can avoid all CSRF attacks, including login # CSRF. 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: # Handle a broken connection before we've completed reading # the POST data. process_view shouldn't raise any # exceptions, so we'll ignore and serve the user a 403 # (assuming they're still listening, which they probably # aren't because of the error). pass if request_csrf_token == "": # Fall back to X-CSRFToken, to make things easier for AJAX, # and possible for PUT/DELETE. 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 # Set the CSRF cookie even if it's already set, so we renew # the expiry timer. self._set_token(request, response) response.csrf_cookie_set = True return response

三丶JSON

什么是JSON

      1.JSON指的是JavaScript对象表示

      2.JSON是轻量级的文本数据交换格式

​      3.JSON独立于语言

​      4.JSON具有自我描述性,更容易理解

### JSON的语法, json本质还是一个字符串 # JSON是一个标记符的序列。这套标记符包含六个构造字符、字符串、数字和三个字面名。 # JSON是一个序列化的对象或数组。

JSON数据

# 合格的json数据 必须是 双引号. ["one", "two", "three"] { "one": 1, "two": 2, "three": 3 } {"names": ["张三", "李四"] } [ { "name": "张三"}, {"name": "李四"} ]  # 不合格的json数据 { name: "张三", 'age': 32 }        // 属性名必须使用双引号 [32, 64, 128, 0xFFF]            // 不能使用十六进制值 { "name": "张三", "age": undefined } // 不能使用undefined { "name": "张三", "birthday": new Date('Fri, 26 Aug 2011 07:13:10 GMT'), "getName": function() {return this.name;} // 不能使用函数和日期对象 }

和XML技术相比

​      JSON 格式于2001年由 Douglas Crockford 提出,目的就是取代繁琐笨重的 XML 格式。

      JSON 格式有两个显著的优点:书写简单,一目了然;符合 JavaScript 原生语法,可以由解释引擎直接处理,不用另外添加解析代码。所以,JSON迅速被接受,已经成为各大网站交换数据的标准格式,并被写入ECMAScript 5,成为标准的一部分。

​      XML和JSON都使用结构化方法来标记数据,下面来做一个简单的比较.

# JSON 简单的语法格式和清晰的层次结构明显要比 XML 容易阅读,并且在数据交换方面,由于 JSON 所使用的字符要比 XML 少得多,可以大大得节约传输数据所占用得带宽

四丶ajax技术(JQ实现)

发送请求的方式

# 1. 浏览器输入地址 发送get请求 # 2. a标签 发送get请求 # 3. form表单,默认是get请求, 可以指定发送请求的方式 method # 4. 异步发送 ajax js技术,type指定发送请求的方式

什么是ajax

​      AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步的Javascript和XML”。即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML)。

      AJAX 不是新的编程语言,而是一种使用现有标准的新方法。

      AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。(这一特点给用户的感受是在不知不觉中完成请求和响应过程)

​      AJAX 不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。

# 1.同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求; # 2.异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。

AJAX的优缺点

### 优点: 1.AJAX使用JavaScript技术向服务器发送异步请求; 2.AJAX请求无须刷新整个页面; 3.因为服务器响应内容不再是整个页面,而是页面中的部分内容,所以AJAX性能高 4.前端与后端负载均衡 将一些后端的工作移到前端,减少服务器与带宽的负担 5.异步与服务器通信 使用异步的方式与服务器通信,不打断用户的操作 6. ### 缺点: 1.Ajax干掉了Back与History功能,即对浏览器机制的破坏   在动态更新页面的情况下,用户无法回到前一页的页面状态,因为浏览器仅能记忆历史纪录中的静态页面 2.安全问题   AJAX技术给用户带来很好的用户体验的同时也对IT企业带来了新的安全威胁,Ajax技术就如同对企业数据建立了一个直接通道。这使得开发者在不经意间会暴露比以前更多的数据和服务器逻辑。 3.对搜索引擎支持较弱 4.破坏程序的异常处理机制 5.违背URL与资源定位的初衷 6.不能很好地支持移动设备 7.客户端肥大,太多客户段代码造成开发上的成本 ## 如果网速慢,则会出现ajax请求缓慢,页面空白的情况,对客户的体验不好。ajax请求不利于搜索引擎优化,一般搜不到ajax添加到页面的信息! ## 解决的办法:可以先用服务器渲染。

jQuery实现的AJAX

import json # json模块 from django.http import JsonResponse # 直接转换成JSON对象 def ajax_jq(request): if request.method=='POST': text=request.POST.get('text') if len(text)>0: json1=json.dumps({'name':'xixi'}) # 序列化 return HttpResponse('OK') # 发送一个普通的HTTPResponse对象,普通的字符串 return HttpResponse(json1) # 发送的是一个json序列化的字符串 return JsonResponse({'name':'xixi2'}) # 直接发送的就是json数据 return render(request,'ajax.html') <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> {% load static %} </head> <body> {% csrf_token %} <input type="text" id="te"> <button>提交</button> <script src="{% static 'js/jquery-1.11.1.min.js' %}"></script> <script> $('button').click(function () { $.ajax({ // JQ 已经封装好了ajax的请求. 调用 ajax方法即可. url: '/ajax_jq/', //发送的目标url地址 type: 'post', //发送方式 data: { //发送的数据 'csrfmiddlewaretoken': $('input[name="csrfmiddlewaretoken"]').val(), //由于存在csrf校验,必须携带csrfmiddlewaretoken的值 'text': $('#te').val(), //自定义文本框数据 }, success: function (res) { // 回调函数 ,res是结果, 一般是json数据 res=JSON.parse(res) // 反序列化json数据 console.log(res) } }) }) </script> </body> </html>

JS实现AJAX

var b2 = document.getElementById("b2"); b2.onclick = function () { // 原生JS var xmlHttp = new XMLHttpRequest(); //得到一个XML对象 xmlHttp.open("POST", "/ajax_test/", true); // xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); //设置类型 xmlHttp.send("username=q1mi&password=123456"); //发送请求 xmlHttp.onreadystatechange = function () { //回调函数 if (xmlHttp.readyState === 4 && xmlHttp.status === 200) { alert(xmlHttp.responseText); } }; };

AJAX请求如何设置csrf_token

1.通过获取隐藏的input标签中的csrfmiddlewaretoken值,放置在data中发送。

<script> $('button').click(function () { $.ajax({ url: '/ajax_jq/', type: 'post', data: { 'csrfmiddlewaretoken': $('input[name="csrfmiddlewaretoken"]').val(), //由于存在csrf校验,必须携带csrfmiddlewaretoken的值 'text': $('#te').val(), }, success: function (res) { // 回调函数 ,res是结果, 一般是json数据 res=JSON.parse(res) // 反序列化json数据 console.log(res) } }) }) </script>

2.通过获取返回的cookie中的字符串 放置在请求头中发送 (加请求头 x-csrftoken)

$('#btn2').click(function () { console.log($.cookie('csrftoken')) $.ajax({ url: '/ajax_csrf/', //发送的目标url地址 type: 'post', //发送方式 headers: {'X-CSRFToken': $.cookie('csrftoken')}, // 从cookie中获取csrftoken的值 , 需要插件js.cookies headers: {'X-CSRFToken': $('input[name="csrfmiddlewaretoken"]').val()}, // 从页面中获得csrf的csrfmiddlewaretoken的值 data: { //发送的数据 'text': $('#te').val(), //自定义文本框数据 }, success: function (res) { console.log(res) } }) })

3.导入jquery.cookie.js插件 或者 自定义getCookie方法

// ajaxSetup 设置全局的ajax, 自动获取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); } } });

https://www.cnblogs.com/maple-shaw/articles/9524153.html

转载于:https://www.cnblogs.com/dengl/p/11494920.html

最新回复(0)