Skip to content

Commit 196cb62

Browse files
committed
Sanitize POST body when it's JSON (pull request opbeat#189)
1 parent a593fbc commit 196cb62

3 files changed

Lines changed: 45 additions & 0 deletions

File tree

opbeat/processors.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
from opbeat.utils import six, varmap
1515
from opbeat.utils.encoding import force_text
16+
from opbeat.utils.opbeat_json import is_json, loads, dumps
1617

1718

1819
class Processor(object):
@@ -113,6 +114,8 @@ def filter_http(self, data):
113114

114115
data[n] = '&'.join('='.join(k) for k in querybits)
115116
continue
117+
if is_json(text_data):
118+
data[n] = dumps(varmap(self.sanitize, loads(text_data)))
116119
data[n] = varmap(self.sanitize, data[n])
117120

118121
def process(self, data, **kwargs):

opbeat/utils/opbeat_json.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,10 @@ def dumps(value, **kwargs):
4343

4444
def loads(value, **kwargs):
4545
return json.loads(value, object_hook=better_decoder)
46+
47+
def is_json(value):
48+
try:
49+
loads(value)
50+
return True
51+
except ValueError:
52+
return False

tests/processors/tests.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
SanitizePasswordsProcessor)
99
from opbeat.utils import six
1010
from opbeat.utils.encoding import force_text
11+
from opbeat.utils.opbeat_json import dumps
1112
from tests.utils.compat import TestCase
1213

1314

@@ -106,6 +107,40 @@ def test_post_as_string(self):
106107
http = result['http']
107108
assert 'evil' not in force_text(http['data'])
108109

110+
def test_post_as_json_bytes_string(self):
111+
data = {
112+
'http': {
113+
'data': six.b(dumps({
114+
'password': 'evil',
115+
'api_key': 'evil',
116+
'harmless': 'bar'
117+
})),
118+
}
119+
}
120+
proc = SanitizePasswordsProcessor(Mock())
121+
result = proc.process(data)
122+
self.assertTrue('http' in result)
123+
http = result['http']
124+
assert 'evil' not in force_text(http['data'])
125+
assert 'bar' in force_text(http['data'])
126+
127+
def test_post_as_json_string(self):
128+
data = {
129+
'http': {
130+
'data': dumps({
131+
'password': 'evil',
132+
'api_key': 'evil',
133+
'harmless': 'bar'
134+
}),
135+
}
136+
}
137+
proc = SanitizePasswordsProcessor(Mock())
138+
result = proc.process(data)
139+
self.assertTrue('http' in result)
140+
http = result['http']
141+
assert 'evil' not in force_text(http['data'])
142+
assert 'bar' in force_text(http['data'])
143+
109144
def test_querystring_as_string(self):
110145
data = {
111146
'http': {

0 commit comments

Comments
 (0)