CSRF相关的装饰器 json数据 xml ajax

 

一丶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);
    }
  }
});

 

posted on 2020-03-02 12:19  向往1  阅读(246)  评论(0编辑  收藏  举报

导航

……