current position:Home>The source code and implementation of Django CSRF Middleware

The source code and implementation of Django CSRF Middleware

2022-01-31 01:02:12 Waiting for

This is my participation 11 The fourth of the yuegengwen challenge 2 God , Check out the activity details :2021 One last more challenge

1.Django CSRF Source code analysis of Middleware

Django CSRF Source code of Middleware

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 ('443', '80'):
                        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
 Copy code 

You can see from the source code above ,CsrfViewMiddleware Middleware is defined process_request,process_view and process_response Three methods

First look process_request Method

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
 Copy code 

from Django Read from the project configuration folder CSRF_USE_SESSIONS Value , If successful , From session Read from CSRF_SESSION_KEY Value , The default is '_csrftoken', If not CSRF_USE_SESSIONS Value , Get... From the sent request CSRF_COOKIE_NAME Value , If not defined, return None.

Look again. process_view Method in process_view In the method , First check whether the view function is csrf_exempt Ornaments , If the view function is not csrf_exempt Ornaments , Then the program continues , Otherwise return to None. Then from request In the request header or cookie Get the carried token And verify that , Only after passing the verification can the execution and continue URL Matching view functions , Otherwise it returns 403 Forbidden error .

In actual projects , It will be sent POST,PUT,DELETE,PATCH When asked , In the submission of form Add... To the form {% csrf_token %} that will do , Otherwise 403 Error of

2.csrf_exempt Decorators and csrf_protect Decorator

2.1 be based on Django FBV

In a project , If registration is enabled CsrfViewMiddleware middleware , Then all the view functions and view classes in the project must be executed CSRF verification . At this time, you want to make a view function or view class not CSRF verification , You can use csrf_exempt Decorator decoration doesn't want to CSRF Validate the view function

from django.views.decorators.csrf import csrf_exempt

@csrf_exempt 
def index(request):  
    pass
 Copy code 

Also can put the csrf_exempt The decorator is added directly to URL Routing mapping , Make a view function not pass through CSRF verification

from django.views.decorators.csrf import csrf_exempt  
  
from users import views  
 
urlpatterns = [  
    url(r'^admin/', admin.site.urls),  
    url(r'^index/',csrf_exempt(views.index)),  
]
 Copy code 

alike , If in a Django In the project , Not registered to use CsrfViewMiddleware middleware , But I want a view function to CSRF verification , You can use csrf_protect Decorator

csrf_protect The use of decorators is similar to csrf_exempt The decorator is used in the same way , You can decorate the view function above the view function or in URL Directly decorate the view function in routing mapping

from django.views.decorators.csrf import csrf_exempt  

@csrf_protect 
def index(request):  
    pass
 Copy code 

perhaps

from django.views.decorators.csrf import csrf_protect  
  
from users import views  
 
urlpatterns = [  
    url(r'^admin/', admin.site.urls),  
    url(r'^index/',csrf_protect(views.index)),  
]
 Copy code 

2.2 be based on Django CBV

The above situation is based on Django FBV Of , If it is based on Django CBV, You can't directly add it to the view function of the view class

There are three ways to Django CBV Conduct CSRF Verify or not CSRF verification

Method 1 , Define... In the view class dispatch Method , by dispatch Method plus csrf_exempt Decorator

from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator

class UserAuthView(View):

 @method_decorator(csrf_exempt)
    def dispatch(self, request, *args, **kwargs):
        return super(UserAuthView,self).dispatch(request,*args,**kwargs)

    def get(self,request,*args,**kwargs):
        pass

    def post(self,request,*args,**kwargs):
        pass

    def put(self,request,*args,**kwargs):
        pass

    def delete(self,request,*args,**kwargs):
        pass
 Copy code 

Method 2 : Add a decorator above the view class

@method_decorator(csrf_exempt,name='dispatch')
class UserAuthView(View):
    def get(self,request,*args,**kwargs):
        pass

    def post(self,request,*args,**kwargs):
        pass

    def put(self,request,*args,**kwargs):
        pass

    def delete(self,request,*args,**kwargs):
        pass
 Copy code 

Mode three : stay url.py Add decorators to classes in

from django.views.decorators.csrf import csrf_exempt

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^auth/', csrf_exempt(views.UserAuthView.as_view())),
]
 Copy code 

csrf_protect The use of the decorator is the same as above

restframework Authentication process

copyright notice
author[Waiting for],Please bring the original link to reprint, thank you.
https://en.pythonmana.com/2022/01/202201310102094964.html

Random recommended