diff --git a/sentry_sdk/integrations/django/__init__.py b/sentry_sdk/integrations/django/__init__.py index bff2982d35..b6b678e9ee 100644 --- a/sentry_sdk/integrations/django/__init__.py +++ b/sentry_sdk/integrations/django/__init__.py @@ -807,9 +807,24 @@ def size_of_file(self, file: "Any") -> int: def parsed_body(self) -> "Optional[Dict[str, Any]]": try: - return self.request.data + data = self.request.data except Exception: - return RequestExtractor.parsed_body(self) + data = RequestExtractor.parsed_body(self) + + # Set by Django's `sensitive_post_parameters` decorator + sensitive_post_parameters = getattr( + self.request, "sensitive_post_parameters", None + ) + if sensitive_post_parameters and isinstance(data, dict): + if sensitive_post_parameters == "__ALL__": + sensitive_post_parameters = data.keys() + + data = { + k: SENSITIVE_DATA_SUBSTITUTE if k in sensitive_post_parameters else v + for k, v in data.items() + } + + return data def _set_user_info(request: "WSGIRequest", event: "Event") -> None: diff --git a/tests/integrations/django/myapp/urls.py b/tests/integrations/django/myapp/urls.py index 7dda30d7ee..2bfb226e60 100644 --- a/tests/integrations/django/myapp/urls.py +++ b/tests/integrations/django/myapp/urls.py @@ -23,6 +23,7 @@ def path(path, *args, **kwargs): return url("^{}$".format(path), *args, **kwargs) +from django.views.decorators.debug import sensitive_post_parameters from django_helpers import views as helper_views from . import views @@ -60,6 +61,16 @@ def path(path, *args, **kwargs): name="sentryclass_csrf", ), path("post-echo", views.post_echo, name="post_echo"), + path( + "sensitive-post-parameters", + sensitive_post_parameters("credit_card_number")(views.message), + name="sensitive_post_parameters", + ), + path( + "sensitive-post-parameters-all", + sensitive_post_parameters()(views.message), + name="sensitive_post_parameters_all", + ), path("template-exc", views.template_exc, name="template_exc"), path("template-test", views.template_test, name="template_test"), path("template-test2", views.template_test2, name="template_test2"), @@ -154,6 +165,13 @@ def path(path, *args, **kwargs): name="rest_framework_read_body_and_exc", ) ) + urlpatterns.append( + path( + "rest-framework-sensitive-post-parameters", + sensitive_post_parameters("credit_card_number")(views.rest_framework_exc), + name="rest_framework_sensitive_post_parameters", + ) + ) urlpatterns.append( path( "rest-authenticated-hello", diff --git a/tests/integrations/django/test_basic.py b/tests/integrations/django/test_basic.py index 59afe9be6b..1026816baa 100644 --- a/tests/integrations/django/test_basic.py +++ b/tests/integrations/django/test_basic.py @@ -1389,6 +1389,41 @@ def raw_data(self): assert "data" not in event["request"] +@pytest.mark.parametrize( + "route, expected_data", + [ + ( + "sensitive_post_parameters", + {"name": "Jane", "credit_card_number": "[Filtered]"}, + ), + ( + "sensitive_post_parameters_all", + {"name": "[Filtered]", "credit_card_number": "[Filtered]"}, + ), + ( + "rest_framework_sensitive_post_parameters", + {"name": "Jane", "credit_card_number": "[Filtered]"}, + ), + ], +) +def test_sensitive_post_parameters( + sentry_init, client, capture_events, route, expected_data +): + if route == "rest_framework_sensitive_post_parameters": + pytest.importorskip("rest_framework") + + sentry_init(integrations=[DjangoIntegration()]) + events = capture_events() + + client.post( + reverse(route), + data={"name": "Jane", "credit_card_number": "4111111111111111"}, + ) + + (event,) = events + assert event["request"]["data"] == expected_data + + @pytest.mark.parametrize("span_streaming", [True, False]) def test_template_tracing_meta( sentry_init,