Python 24 Django之csrf中间件

CSRF:跨站请求伪造

一、两种方式通过csrf校验

1、在模板中写上{% csrf_token %}

2、csrf_exempt,csrf_protect装饰器

from django.views.decorators.csrf import csrf_exempt, csrf_protect

@csrf_exempt  # 如果使用csrf中间件,加上这个装饰器可以直接通过检验
def login(request):
    return render(xxx)

@csrf_protect  # 如果不使用csrf中间件,加上这个装饰器可以单独进行检验
def login(request):
    return render(xx)

二、csrf中间件源码解析

1、文字版流程

process_request:

    从请求的cookie中获取csrftoken的值,赋给csrf_token变量,再request.META["CSRF_COOKIE"] = csrf_token

process_view:

    ① 如果视图加上了csrf_exempt装饰器,不做校验

    ② 如果请求方式是GET / HEAD / OPTION / TRACE中的一种,不做校验

    ③ 其他情况做校验:

        csrf_token = request.META["CSRF_COOKIE"],

        request_csrf_token = ""

        # 首先从form表单中获取csrfmiddlewaretoken的值

  request_csrf_token = request.POST.get("csrfmiddlewaretoken", "")

  # 如果表单中没获取到,则取请求头中获取X-csrftoken的值

  request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME, "")

  

  将request_csrf_token和csrf_token做比对校验,如果校验成功则继续,不成功则拒绝。

2、源码流程

class CsrfViewMiddleware(MiddlewareMixin):

    def _get_token(self, request):
        if settings.CSRF_USE_SESSIONS:  #默认是False,忽略
            # 省略
            pass    
        else:
            try:
                cookie_token = request.COOKIES[settings.CSRF_COOKIE_NAME]  #从浏览器中获取cookie中csrf_token的值
            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  # 如果清洗前后的值不一致,则需要重置cookie
            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   

    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):  # 如果视图函数设置了csrf_exempt装饰器,则不进行校验
            return None

        if request.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'):  # 如果是这些方法,则不进行校验
            csrf_token = request.META.get('CSRF_COOKIE')  # 否则获取到cookie中csrf_token的值
            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)  # 如果表单中的值和cookie中的值不一致则拒绝
        return self._accept(request)
原文地址:https://www.cnblogs.com/yinwenjie/p/10941931.html