Django --- CSRF decorator, CSRF process, JSON format data, ajax technique (implemented based JQ)

Django --- CSRF decorator, CSRF process, JSON format data, ajax technique (implemented based JQ)

Dian a CSRF related decorator

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')
    

Two Dian CSRF process

   1. To check on the premise that by csrf must have csrftoken the 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. Get the value of csrfmiddlwaretoken data csrftoken the value POST submission from the cookie than to do

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

CSRF source code as follows:

#### 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

Wed and JSON

What is JSON

      1.JSON refers to the JavaScript Object Notation

      2.JSON is a lightweight data interchange format text

3.JSON language independent

4.JSON self descriptive, easier to understand

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

img

JSON data

# 合格的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;}  // 不能使用函数和日期对象
    }

And XML technology compared

JSON format in 2001, proposed by Douglas Crockford, the purpose is to replace the cumbersome bulky XML format.

      JSON format has two significant advantages: write simple, clear; JavaScript meet native syntax, the engine can be directly processed by an interpreter, without further addition parsing code. So, JSON quickly accepted, the major sites have become the standard format for exchanging data, and is written ECMAScript 5, become part of the standard.

XML and JSON use structured method to mark data, the following do a simple comparison.

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

Four Dian ajax technology (JQ achieve)

Send a request

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

What is ajax

AJAX (Asynchronous Javascript And XML) translated into Chinese is "asynchronous Javascript and XML". That the use of Javascript language to interact with the server asynchronous data transmission for XML (Of course, data transmission is not just XML).

      AJAX is not a new programming language, but a new method to use existing standards.

      The biggest advantage is AJAX without reloading the entire page, you can exchange data with the server and update parts of the page content. (This feature is the feeling to the user request and response process is completed unknowingly)

AJAX does not require any browser plug-ins, but requires the user to allow the execution of JavaScript in the browser.

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

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

AJAX advantages and disadvantages

### 优点:
    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 implementation

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 achieve 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 request How to set csrf_token

1. csrfmiddlewaretoken value by obtaining a hidden input tag placed in data transmission.

<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. Get returned cookie string is placed in the transmission request header (plus request header 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. introducing jquery.cookie.js widget or custom methods 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);
    }
  }
});

Guess you like

Origin www.cnblogs.com/dengl/p/11494920.html