From 84290e94e7d84cbfbc84d6e350e43ff0a17356cf Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Thu, 23 Nov 2017 15:16:45 +0000 Subject: [PATCH] Sanitize POST body when it's JSON --- opbeat/processors.py | 3 +++ opbeat/utils/opbeat_json.py | 7 +++++++ tests/processors/tests.py | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/opbeat/processors.py b/opbeat/processors.py index 08f0c19d..08076bed 100644 --- a/opbeat/processors.py +++ b/opbeat/processors.py @@ -13,6 +13,7 @@ from opbeat.utils import six, varmap from opbeat.utils.encoding import force_text +from opbeat.utils.opbeat_json import is_json, loads, dumps class Processor(object): @@ -113,6 +114,8 @@ def filter_http(self, data): data[n] = '&'.join('='.join(k) for k in querybits) continue + if is_json(text_data): + data[n] = dumps(varmap(self.sanitize, loads(text_data))) data[n] = varmap(self.sanitize, data[n]) def process(self, data, **kwargs): diff --git a/opbeat/utils/opbeat_json.py b/opbeat/utils/opbeat_json.py index d23e27ed..eafd5f19 100644 --- a/opbeat/utils/opbeat_json.py +++ b/opbeat/utils/opbeat_json.py @@ -43,3 +43,10 @@ def dumps(value, **kwargs): def loads(value, **kwargs): return json.loads(value, object_hook=better_decoder) + +def is_json(value): + try: + loads(value) + return True + except ValueError: + return False diff --git a/tests/processors/tests.py b/tests/processors/tests.py index d3a42bed..1ddcc00f 100644 --- a/tests/processors/tests.py +++ b/tests/processors/tests.py @@ -8,6 +8,7 @@ SanitizePasswordsProcessor) from opbeat.utils import six from opbeat.utils.encoding import force_text +from opbeat.utils.opbeat_json import dumps from tests.utils.compat import TestCase @@ -106,6 +107,40 @@ def test_post_as_string(self): http = result['http'] assert 'evil' not in force_text(http['data']) + def test_post_as_json_bytes_string(self): + data = { + 'http': { + 'data': six.b(dumps({ + 'password': 'evil', + 'api_key': 'evil', + 'harmless': 'bar' + })), + } + } + proc = SanitizePasswordsProcessor(Mock()) + result = proc.process(data) + self.assertTrue('http' in result) + http = result['http'] + assert 'evil' not in force_text(http['data']) + assert 'bar' in force_text(http['data']) + + def test_post_as_json_string(self): + data = { + 'http': { + 'data': dumps({ + 'password': 'evil', + 'api_key': 'evil', + 'harmless': 'bar' + }), + } + } + proc = SanitizePasswordsProcessor(Mock()) + result = proc.process(data) + self.assertTrue('http' in result) + http = result['http'] + assert 'evil' not in force_text(http['data']) + assert 'bar' in force_text(http['data']) + def test_querystring_as_string(self): data = { 'http': {