Django global completely disables the CSRF mechanism

Time:2021-9-16
Write before
  • Only disableCSRFMethod, NoCSRFReason
  • Will recordDjangoAboutCSRFSome common methods and classes
  • To understandDjangoOn the premise of middleware, see the following contents
Disable method
  • The simplest and most recommended method on the Internet, findsettings.py => MIDDLEWAREConfiguration item = > modify as follows
MIDDLEWARE = [
     ...
    'django.middleware.common.CommonMiddleware',
    #'django. Middleware. CSRF. Csrfviewmiddleware ', # comment out this line of code
    'django.contrib.auth.middleware.AuthenticationMiddleware',
     ...
]
  • The writing method I recommend is also the most effective method for global disabling. Customize the middlewaremiddleware.py, as follows
# tools/middleware.py

from django.utils.deprecation import MiddlewareMixin
logger = logging.getLogger(__name__)

class CloseCsrfMiddleware(MiddlewareMixin):

    def process_request(self, request):
        request.csrf_ processing_ Done = true # CSRF processing completed
        Logger. Info ('csrf global disable ')
explain

In the above two methods, if your purpose is to disable CSRF authentication globally, I suggest you use the second disable method, which is completely prohibited. If you use the first method, you will find that when you useadminxadminOr other third-party plug-ins on authentication,CSRFSometimes the mechanism will jump out and do strange things. Why? Why is the ban ineffective?
I’m usingxadminThis is the case when I was young. It’s cleardjango.middleware.csrf.CsrfViewMiddleware, or will you be promptedCSRFVerification failed (I won’t explain the reasons for the failure. Different people encounter different situations. I’m here because the domain name is used as a secondary agent). Take login as an example,xadminPart of the source code is as follows:

# xadmin/view/website.py
...
from django.contrib.auth.views import LoginView as login
...

class LoginView(BaseAdminView):
    ...
    @never_cache
    def get(self, request, *args, **kwargs):
        context = self.get_context()
        helper = FormHelper()
        helper.form_tag = False
        helper.include_media = False
        context.update({
            'title': self.title,
            'helper': helper,
            'app_path': request.get_full_path(),
            REDIRECT_FIELD_NAME: request.get_full_path(),
        })
        defaults = {
            'extra_context': context,
            # 'current_app': self.admin_site.name,
            'authentication_form': self.login_form or AdminAuthenticationForm,
            'template_name': self.login_template or 'xadmin/views/login.html',
        }
        self.update_params(defaults)
        # return login(request, **defaults)
        return login.as_view(**defaults)(request)

    @never_cache
    def post(self, request, *args, **kwargs):
        return self.get(request)
    ...

xadminWhen logging in, the background method is called as follows:
def post() => def get() => login.as_view(); Among them,def post()def get()byxadminlowerclass LoginView()Methods within;login.as_view()bydjangoNative login authentication class

djangoThe source code of the native login authentication class is as follows:

# django/crontrab/auth/view.py

class LoginView(SuccessURLAllowedHostsMixin, FormView):
    ...
    @method_decorator(sensitive_post_parameters())
    @method_ Decorator (csrf_protect) ##### note this line####
    @method_decorator(never_cache)
    def dispatch(self, request, *args, **kwargs):
        if self.redirect_authenticated_user and self.request.user.is_authenticated:
            redirect_to = self.get_success_url()
            if redirect_to == self.request.path:
                raise ValueError(
                    "Redirection loop for authenticated user detected. Check that "
                    "your LOGIN_REDIRECT_URL doesn't point to a login page."
                )
            return HttpResponseRedirect(redirect_to)
        return super().dispatch(request, *args, **kwargs)

Notice this line of code@method_decorator(csrf_protect)
What you need to know here is the decoratorcsrf_protectThe role of is toCSRFverification
So even if you annotatedjango.middleware.csrf.CsrfViewMiddleware, pass the decorator herecsrf_protectOr will it happen againCSRFverification.

The truth finally came out.

Next, the second is disabledCSRFmethod

By viewing@csrf_protectThe source code (not posted) will find that the internal implementation is, rightclass CsrfViewMiddlewareInstantiate, and then call the middleware in turndef process_request()def process_view()And other methods, in which,CsrfViewMiddleware.process_view(), yesCSRFThe source code of the verification logic is as follows:

class CsrfViewMiddleware(MiddlewareMixin):
    ... 
    def process_view(self, request, callback, callback_args, callback_kwargs):
        
        #Pay attention to CSRF_ processing_ Done variable, this variable is critical
        #This variable is used to record whether CSRF verification has been performed in this request
        #If it has been verified, the following verification logic will not be followed.
        if getattr(request, 'csrf_processing_done', False):
            return None

        #This step is to check whether the called def view () method adds @ CSRF_ Exempt decorator
        #If it is added, the following verification logic will not be followed.
        # 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

        #The following is the verification logic of CSRF
        # 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)
    ...

As shown above, the second is disabledCSRFThe principle of the method is to setrequest.csrf_processing_done=True

To this, end!