When accessing from Andorid Chrome, Django CSRF validation fails or you can't log in

environment

Django 1.9 Android Chrome (probably Dolphin)

phenomenon

When I access the Django login form with Chrome on Android, I get a CSRF error (403) and cannot log in.

The message CSRF cookie not set. remains in the Django log.

Overview

Probably the request cookie contains multibyte and is sent to the server.

In my case, the cookie __utmz that Google Analytics put in contained Japanese, which caused a problem.

Django takes it and parses it with the Python http library cookie parser http.cookies regular expression http.cookies._CookiePattern, but the regular expression pattern is flags with re.ASCII. Since it is done, it seems that parsing ends at the place where multi-byte appears.

Correspondence

I have patched the WSGIRequest COOKIES. I tried URL encoding multibyte.

def patch_wsgi_request():
    """
If the cookie contains Japanese, the cookie parsing will fail.
URL encode before parsing
    Android +Frequently used in Google Analytics
    __Japanese is entered in utmz
    """
    import re
    from urllib.parse import quote
    from django.core.handlers.wsgi import WSGIRequest
    from django import http
    from django.core.handlers.wsgi import get_str_from_wsgi
    from django.utils.functional import cached_property

    def _quote(s):
        return quote(s.group(0))

    def COOKIES(self):
        raw_cookie = get_str_from_wsgi(self.environ, 'HTTP_COOKIE', '')
        re_multibyte = re.compile(r'[^\x00-\x7F]+')
        raw_cookie_fixed = re_multibyte.sub(_quote, raw_cookie)
        return http.parse_cookie(raw_cookie_fixed)

    setattr(WSGIRequest, 'COOKIES', cached_property(COOKIES))

patch_wsgi_request()

Run this code somewhere (such as the urls.py evaluation timing)

Recommended Posts

When accessing from Andorid Chrome, Django CSRF validation fails or you can't log in
CSRF validation error when accessing django 3.0 admin page in Chrome
When you can't call base.html in Django
Display error message when login fails in Django