diff --git a/django/views/debug.py b/django/views/debug.py
index 608282c232..ae2b68ab70 100644
--- a/django/views/debug.py
+++ b/django/views/debug.py
@@ -123,6 +123,14 @@ class SafeExceptionReporterFilter(ExceptionReporterFilter):
settings_dict[k] = self.cleanse_setting(k, getattr(settings, k))
return settings_dict
+ def get_safe_request_meta(self, request):
+ """
+ Return a dictionary of request.META with sensitive values redacted.
+ """
+ if not hasattr(request, 'META'):
+ return {}
+ return {k: self.cleanse_setting(k, v) for k, v in request.META.items()}
+
def is_active(self, request):
"""
This filter is to add safety in production environments (i.e. DEBUG
@@ -296,6 +304,7 @@ class ExceptionReporter:
'unicode_hint': unicode_hint,
'frames': frames,
'request': self.request,
+ 'request_meta': self.filter.get_safe_request_meta(self.request),
'user_str': user_str,
'filtered_POST_items': list(self.filter.get_post_parameters(self.request).items()),
'settings': self.filter.get_safe_settings(),
diff --git a/django/views/templates/technical_500.html b/django/views/templates/technical_500.html
index b01b00c8e6..a63c7183e6 100644
--- a/django/views/templates/technical_500.html
+++ b/django/views/templates/technical_500.html
@@ -438,7 +438,7 @@ Exception Value: {{ exception_value|force_escape }}
- {% for var in request.META.items|dictsort:0 %}
+ {% for var in request_meta.items|dictsort:0 %}
{{ var.0 }} |
{{ var.1|pprint }} |
diff --git a/django/views/templates/technical_500.txt b/django/views/templates/technical_500.txt
index c9f70af797..f06a1a499e 100644
--- a/django/views/templates/technical_500.txt
+++ b/django/views/templates/technical_500.txt
@@ -50,7 +50,7 @@ FILES:{% for k, v in request_FILES_items %}
COOKIES:{% for k, v in request_COOKIES_items %}
{{ k }} = {{ v|stringformat:"r" }}{% empty %} No cookie data{% endfor %}
-META:{% for k, v in request.META.items|dictsort:0 %}
+META:{% for k, v in request_meta.items|dictsort:0 %}
{{ k }} = {{ v|stringformat:"r" }}{% endfor %}
{% else %}Request data not supplied
{% endif %}
diff --git a/docs/howto/error-reporting.txt b/docs/howto/error-reporting.txt
index a4cb5d2a1a..e145897b2a 100644
--- a/docs/howto/error-reporting.txt
+++ b/docs/howto/error-reporting.txt
@@ -277,8 +277,9 @@ following attributes and methods:
.. versionadded:: 3.1
- A compiled regular expression object used to match settings considered
- as sensitive. By default equivalent to::
+ A compiled regular expression object used to match settings and
+ ``request.META`` values considered as sensitive. By default equivalent
+ to::
import re
@@ -289,8 +290,9 @@ following attributes and methods:
Returns ``True`` to activate the filtering in
:meth:`get_post_parameters` and :meth:`get_traceback_frame_variables`.
By default the filter is active if :setting:`DEBUG` is ``False``. Note
- that sensitive settings are always filtered, as described in the
- :setting:`DEBUG` documentation.
+ that sensitive ``request.META`` values are always filtered along with
+ sensitive setting values, as described in the :setting:`DEBUG`
+ documentation.
.. method:: get_post_parameters(request)
diff --git a/docs/releases/3.1.txt b/docs/releases/3.1.txt
index 48df0a0d66..29e5e22314 100644
--- a/docs/releases/3.1.txt
+++ b/docs/releases/3.1.txt
@@ -161,9 +161,13 @@ Email
Error Reporting
~~~~~~~~~~~~~~~
+* :class:`django.views.debug.SafeExceptionReporterFilter` now filters sensitive
+ values from ``request.META`` in exception reports.
+
* The new :attr:`.SafeExceptionReporterFilter.cleansed_substitute` and
:attr:`.SafeExceptionReporterFilter.hidden_settings` attributes allow
- customization of sensitive settings filtering in exception reports.
+ customization of sensitive settings and ``request.META`` filtering in
+ exception reports.
* The technical 404 debug view now respects
:setting:`DEFAULT_EXCEPTION_REPORTER_FILTER` when applying settings
diff --git a/tests/view_tests/tests/test_debug.py b/tests/view_tests/tests/test_debug.py
index 9becfc77d0..020af1a19c 100644
--- a/tests/view_tests/tests/test_debug.py
+++ b/tests/view_tests/tests/test_debug.py
@@ -1224,6 +1224,24 @@ class ExceptionReporterFilterTests(ExceptionReportTestMixin, LoggingCaptureMixin
{'login': 'cooper', 'password': reporter_filter.cleansed_substitute},
)
+ def test_request_meta_filtering(self):
+ request = self.rf.get('/', HTTP_SECRET_HEADER='super_secret')
+ reporter_filter = SafeExceptionReporterFilter()
+ self.assertEqual(
+ reporter_filter.get_safe_request_meta(request)['HTTP_SECRET_HEADER'],
+ reporter_filter.cleansed_substitute,
+ )
+
+ def test_exception_report_uses_meta_filtering(self):
+ response = self.client.get('/raises500/', HTTP_SECRET_HEADER='super_secret')
+ self.assertNotIn(b'super_secret', response.content)
+ response = self.client.get(
+ '/raises500/',
+ HTTP_SECRET_HEADER='super_secret',
+ HTTP_X_REQUESTED_WITH='XMLHttpRequest',
+ )
+ self.assertNotIn(b'super_secret', response.content)
+
class CustomExceptionReporterFilter(SafeExceptionReporterFilter):
cleansed_substitute = 'XXXXXXXXXXXXXXXXXXXX'