Skip to content

Commit 0d8c546

Browse files
committed
fix: stop logging submitted form values
Files changed: - record/log/logger.py: Stop serializing submitted POST values at the shared request logger. - record/tests.py: Cover request-format redaction. - app/test/test_log.py: Cover local and WeChat exception-path redaction.
1 parent 19d415a commit 0d8c546

3 files changed

Lines changed: 59 additions & 6 deletions

File tree

app/test/test_log.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import logging
2+
from unittest.mock import patch
3+
4+
from django.contrib.auth.models import AnonymousUser
5+
from django.test import RequestFactory, SimpleTestCase
6+
7+
from app.log import ProfileLogger
8+
9+
10+
class ProfileLoggerRedactionTestCase(SimpleTestCase):
11+
def test_secure_view_omits_post_values_from_log_and_wechat(self):
12+
secrets = ["password-v13", "token-v13", "identity-v13"]
13+
request = RequestFactory().post(
14+
"/failing-view/",
15+
{"password": secrets[0], "token": secrets[1], "identity": secrets[2]},
16+
)
17+
request.user = AnonymousUser()
18+
logger = ProfileLogger("v13-test")
19+
logger.setLevel(logging.DEBUG)
20+
logger.set_debug_mode(False)
21+
22+
@logger.secure_view()
23+
def failing_view(request):
24+
raise RuntimeError("diagnostic-v13")
25+
26+
with patch.object(logger, "_send_wechat") as send_wechat:
27+
with self.assertLogs(logger, level="ERROR") as captured:
28+
response = failing_view(request)
29+
30+
local_message = "\n".join(captured.output)
31+
wechat_message = send_wechat.call_args.args[0]
32+
self.assertEqual(response.status_code, 302)
33+
for message in (local_message, wechat_message):
34+
self.assertIn("URL: /failing-view/", message)
35+
self.assertIn("Method: POST", message)
36+
for value in secrets:
37+
self.assertNotIn(value, message)

record/log/logger.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
"""
1919

2020
import os
21-
import json
2221
import logging
2322
from typing import Callable, Any, cast, ParamSpec, Concatenate, TypeVar
2423

@@ -111,11 +110,6 @@ def _request_msgs(cls, request: HttpRequest) -> list[str]:
111110
msgs.append('User: ' + request.user.__str__()) # Traceable Call
112111
if request.method is not None:
113112
msgs.append('Method: ' + request.method)
114-
if request.method.lower() == 'POST':
115-
try:
116-
msgs.append('Data: ' + json.dumps(request.POST.dict()))
117-
except:
118-
msgs.append('Failed to jsonify post data.')
119113
return msgs
120114

121115
def on_exception(self, message: str = '', *,

record/tests.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from django.contrib.auth.models import AnonymousUser
2+
from django.test import RequestFactory, SimpleTestCase
3+
4+
from record.log.logger import Logger
5+
6+
7+
class RequestLoggingTestCase(SimpleTestCase):
8+
def test_format_request_omits_post_values(self):
9+
secrets = ["pw-v13-secret", "token-v13-secret", "code-v13-secret"]
10+
request = RequestFactory().post(
11+
"/submit-sensitive/?source=test",
12+
{"password": secrets[0], "token": secrets[1], "code": secrets[2]},
13+
)
14+
request.user = AnonymousUser()
15+
16+
message = Logger.format_request(request)
17+
18+
self.assertIn("URL: /submit-sensitive/?source=test", message)
19+
self.assertIn("Method: POST", message)
20+
self.assertNotIn("Data:", message)
21+
for value in secrets:
22+
self.assertNotIn(value, message)

0 commit comments

Comments
 (0)