feat: log an encrypted string of the full cookie header when over threshold (#29735)

* feat: log an encrypted string of the full cookie header when over threshold
This commit is contained in:
Rebecca Graber
2022-01-10 13:02:47 -05:00
committed by GitHub
parent 29ed3d911a
commit 0e9499de7d
2 changed files with 73 additions and 1 deletions

View File

@@ -14,6 +14,7 @@ from edx_toggles.toggles import WaffleFlag
from opaque_keys import InvalidKeyError
from opaque_keys.edx.keys import CourseKey
from rest_framework.views import exception_handler
from common.djangoapps.util.log_sensitive import encrypt_for_log
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
@@ -143,11 +144,37 @@ class CookieMonitoringMiddleware(MiddlewareMixin):
- `request_utils.capture_cookie_sizes`
- TOP_N_COOKIES_CAPTURED
- TOP_N_COOKIE_GROUPS_CAPTURED
- COOKIE_SIZE_LOGGING_THRESHOLD
- COOKIE_HEADER_DEBUG_PUBLIC_KEY
"""
raw_header_cookie = request.META.get('HTTP_COOKIE', '')
set_custom_attribute('cookies.header.size', len(raw_header_cookie.encode('utf-8')))
cookie_header_size = len(raw_header_cookie.encode('utf-8'))
set_custom_attribute('cookies.header.size', cookie_header_size)
# .. setting_name: COOKIE_SIZE_LOGGING_THRESHOLD
# .. setting_default: None
# .. setting_description: The minimum size for logging the entire (encrypted) cookie header. Should be set
# to a relatively high threshold (suggested 9-10K) to avoid flooding the logs.
# .. setting_warning: Requires COOKIE_HEADER_DEBUG_PUBLIC_KEY to be set
logging_threshold = getattr(settings, "COOKIE_SIZE_LOGGING_THRESHOLD", None)
# .. setting_name: COOKIE_HEADER_DEBUG_PUBLIC_KEY
# .. setting_default: None
# .. setting_description: The public key used to encrypt large cookie headers. See See
# https://github.com/edx/edx-platform/blob/master/common/djangoapps/util/log_sensitive.py
# for instructions on decrypting.
debug_key = getattr(settings, "COOKIE_HEADER_DEBUG_PUBLIC_KEY", None)
if logging_threshold and cookie_header_size > logging_threshold:
if not debug_key:
log.warning("COOKIE_SIZE_LOGGING_THRESHOLD set without COOKIE_HEADER_DEBUG_PUBLIC_KEY")
else:
encrypted_cookie_header = encrypt_for_log(str(raw_header_cookie),
debug_key)
log.info(f"Large (> {logging_threshold}) cookie header detected."
f" Encrypted contents: {encrypted_cookie_header}")
if not CAPTURE_COOKIE_SIZES.is_enabled():
return

View File

@@ -267,6 +267,51 @@ class RequestUtilTestCase(unittest.TestCase):
call('cookies_total_size', 25),
], any_order=True)
@override_settings(COOKIE_SIZE_LOGGING_THRESHOLD=1)
@patch("openedx.core.lib.request_utils.CAPTURE_COOKIE_SIZES")
@patch("openedx.core.lib.request_utils.encrypt_for_log")
def test_log_encrypted_cookies_no_key(self, mock_encrypt, mock_capture_cookie_sizes):
middleware = CookieMonitoringMiddleware()
cookies_dict = {
"a": "." * 10,
"b": "." * 15,
}
factory = RequestFactory()
for name, value in cookies_dict.items():
factory.cookies[name] = value
mock_request = factory.request()
middleware.process_request(mock_request)
mock_encrypt.assert_not_called()
@override_settings(COOKIE_SIZE_LOGGING_THRESHOLD=1)
@override_settings(COOKIE_HEADER_DEBUG_PUBLIC_KEY="fake-key")
@patch("openedx.core.lib.request_utils.CAPTURE_COOKIE_SIZES")
@patch("openedx.core.lib.request_utils.encrypt_for_log")
def test_log_encrypted_cookies(self, mock_encrypt, mock_capture_cookie_sizes):
middleware = CookieMonitoringMiddleware()
cookies_dict = {
"a": "." * 10,
"b": "." * 15,
}
factory = RequestFactory()
for name, value in cookies_dict.items():
factory.cookies[name] = value
mock_request = factory.request()
cookie_header = str(mock_request.META.get('HTTP_COOKIE', ''))
middleware.process_request(mock_request)
mock_encrypt.assert_has_calls([
call(cookie_header, "fake-key")
])
class TestGetExpectedErrorSettingsDict(unittest.TestCase):
"""