Browse Source

Fixed #33606 -- Cleansed sessionid cookie in error reports.

Co-authored-by: Simon Charette <charette.s@gmail.com>
Tobias Bengfort 2 years ago
parent
commit
350455b666

+ 17 - 6
django/views/debug.py

@@ -110,7 +110,7 @@ class SafeExceptionReporterFilter:
 
     cleansed_substitute = "********************"
     hidden_settings = _lazy_re_compile(
-        "API|TOKEN|KEY|SECRET|PASS|SIGNATURE", flags=re.I
+        "API|TOKEN|KEY|SECRET|PASS|SIGNATURE|HTTP_COOKIE", flags=re.I
     )
 
     def cleanse_setting(self, key, value):
@@ -118,10 +118,13 @@ class SafeExceptionReporterFilter:
         Cleanse an individual setting key/value of sensitive content. If the
         value is a dictionary, recursively cleanse the keys in that dictionary.
         """
-        try:
-            is_sensitive = self.hidden_settings.search(key)
-        except TypeError:
-            is_sensitive = False
+        if key == settings.SESSION_COOKIE_NAME:
+            is_sensitive = True
+        else:
+            try:
+                is_sensitive = self.hidden_settings.search(key)
+            except TypeError:
+                is_sensitive = False
 
         if is_sensitive:
             cleansed = self.cleansed_substitute
@@ -158,6 +161,14 @@ class SafeExceptionReporterFilter:
             return {}
         return {k: self.cleanse_setting(k, v) for k, v in request.META.items()}
 
+    def get_safe_cookies(self, request):
+        """
+        Return a dictionary of request.COOKIES with sensitive values redacted.
+        """
+        if not hasattr(request, "COOKIES"):
+            return {}
+        return {k: self.cleanse_setting(k, v) for k, v in request.COOKIES.items()}
+
     def is_active(self, request):
         """
         This filter is to add safety in production environments (i.e. DEBUG
@@ -359,6 +370,7 @@ class ExceptionReporter:
             "frames": frames,
             "request": self.request,
             "request_meta": self.filter.get_safe_request_meta(self.request),
+            "request_COOKIES_items": self.filter.get_safe_cookies(self.request).items(),
             "user_str": user_str,
             "filtered_POST_items": list(
                 self.filter.get_post_parameters(self.request).items()
@@ -376,7 +388,6 @@ class ExceptionReporter:
         if self.request is not None:
             c["request_GET_items"] = self.request.GET.items()
             c["request_FILES_items"] = self.request.FILES.items()
-            c["request_COOKIES_items"] = self.request.COOKIES.items()
             c["request_insecure_uri"] = self._get_raw_insecure_uri()
             c["raising_view_name"] = get_caller(self.request)
 

+ 5 - 1
docs/howto/error-reporting.txt

@@ -281,7 +281,11 @@ following attributes and methods:
 
             import re
 
-            re.compile(r'API|TOKEN|KEY|SECRET|PASS|SIGNATURE', flags=re.IGNORECASE)
+            re.compile(r'API|TOKEN|KEY|SECRET|PASS|SIGNATURE|HTTP_COOKIE', flags=re.IGNORECASE)
+
+        .. versionchanged:: 4.2
+
+            ``HTTP_COOKIE`` was added.
 
     .. method:: is_active(request)
 

+ 3 - 0
docs/releases/4.2.txt

@@ -176,6 +176,9 @@ Forms
 * :func:`~django.forms.models.modelform_factory` now respects the
   ``formfield_callback`` attribute of the ``form``’s ``Meta``.
 
+* Session cookies are now treated as credentials and therefore hidden and
+  replaced with stars (``**********``) in error reports.
+
 Generic Views
 ~~~~~~~~~~~~~
 

+ 6 - 0
tests/view_tests/tests/test_debug.py

@@ -1696,6 +1696,12 @@ class ExceptionReporterFilterTests(
         )
         self.assertNotIn(b"super_secret", response.content)
 
+    @override_settings(SESSION_COOKIE_NAME="djangosession")
+    def test_cleanse_session_cookie_value(self):
+        self.client.cookies.load({"djangosession": "should not be displayed"})
+        response = self.client.get("/raises500/")
+        self.assertNotContains(response, "should not be displayed", status_code=500)
+
 
 class CustomExceptionReporterFilter(SafeExceptionReporterFilter):
     cleansed_substitute = "XXXXXXXXXXXXXXXXXXXX"