Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions api/logging/http_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,20 @@ def __get_http_info(r: Union[Request,Response]) -> dict:
return details


SENSITIVE_HEADERS = [
'Cookie',
'Set-Cookie',
'X-CSRF-Token',
'Authorization',
]


def __filter_headers(headers: dict):
""" utility function to remove sensitive information from request headers """
""" utility function to remove sensitive information from request/response headers """
_headers = dict(headers)
_headers.pop('Cookie', None)
_headers.pop('X-CSRF-Token', None)
_lower_to_key = {k.lower(): k for k in _headers}
for header in SENSITIVE_HEADERS:
key = _lower_to_key.get(header.lower())
if key:
_headers.pop(key)
return _headers
61 changes: 61 additions & 0 deletions api/tests/logging/test_logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,64 @@ def test_log_response_body_and_headers():
}

mock_logger.info.assert_called_once_with(expected_details)


class MockRequestWithSensitiveHeaders:
headers = {
'Content-Type': 'application/json',
'Cookie': 'accessToken=eyJsecrettoken',
'Set-Cookie': 'accessToken=eyJsecrettoken; Secure; HttpOnly',
'X-CSRF-Token': 'csrf-secret-value',
'Authorization': 'Bearer eyJsecrettoken',
}
args = {}
json = None
path = '/fake-path'
environ = {}


def test_log_filters_sensitive_headers():
"""
Given headers containing sensitive values (Cookie, Set-Cookie, X-CSRF-Token, Authorization)
When logging request body and headers
Then sensitive headers should be stripped from the log output
"""
mock_logger = MagicMock(wraps=DefaultLogger(True))
log_request_body_and_headers(mock_logger, MockRequestWithSensitiveHeaders())

logged_details = mock_logger.info.call_args[0][0]
logged_headers = logged_details['headers']

assert 'Content-Type' in logged_headers
assert 'Cookie' not in logged_headers
assert 'Set-Cookie' not in logged_headers
assert 'X-CSRF-Token' not in logged_headers
assert 'Authorization' not in logged_headers


class MockRequestWithMixedCaseHeaders:
headers = {
'Content-Type': 'application/json',
'cookie': 'accessToken=eyJsecrettoken',
'SET-COOKIE': 'accessToken=eyJsecrettoken; Secure; HttpOnly',
'x-csrf-token': 'csrf-secret-value',
'AUTHORIZATION': 'Bearer eyJsecrettoken',
}
args = {}
json = None
path = '/fake-path'
environ = {}


def test_log_filters_sensitive_headers_case_insensitive():
mock_logger = MagicMock(wraps=DefaultLogger(True))
log_request_body_and_headers(mock_logger, MockRequestWithMixedCaseHeaders())

logged_details = mock_logger.info.call_args[0][0]
logged_headers = logged_details['headers']

assert 'Content-Type' in logged_headers
assert 'cookie' not in logged_headers
assert 'SET-COOKIE' not in logged_headers
assert 'x-csrf-token' not in logged_headers
assert 'AUTHORIZATION' not in logged_headers
Loading