mirror of
https://github.com/jazzband/django-axes.git
synced 2026-05-12 17:43:11 +00:00
Add option to cleanse sensitive GET and POST params in database handler
This commit is contained in:
parent
f338057a96
commit
f54c4f095b
5 changed files with 66 additions and 2 deletions
|
|
@ -118,3 +118,12 @@ settings.AXES_META_PRECEDENCE_ORDER = getattr(
|
|||
|
||||
# set CORS allowed origins when calling authentication over ajax
|
||||
settings.AXES_ALLOWED_CORS_ORIGINS = getattr(settings, "AXES_ALLOWED_CORS_ORIGINS", "*")
|
||||
|
||||
# set the list of sensitive parameters to cleanse from get/post data before logging
|
||||
settings.AXES_SENSITIVE_PARAMETERS = getattr(
|
||||
settings,
|
||||
"AXES_SENSITIVE_PARAMETERS",
|
||||
[
|
||||
"password",
|
||||
],
|
||||
)
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ from axes.helpers import (
|
|||
get_credentials,
|
||||
get_failure_limit,
|
||||
get_query_str,
|
||||
cleanse_params,
|
||||
)
|
||||
from axes.models import AccessLog, AccessAttempt
|
||||
from axes.signals import user_locked_out
|
||||
|
|
@ -109,8 +110,8 @@ class AxesDatabaseHandler(AbstractAxesHandler, AxesBaseHandler):
|
|||
)
|
||||
|
||||
# This replaces null byte chars that crash saving failures, meaning an attacker doesn't get locked out.
|
||||
get_data = get_query_str(request.GET).replace("\0", "0x00")
|
||||
post_data = get_query_str(request.POST).replace("\0", "0x00")
|
||||
get_data = get_query_str(cleanse_params(request.GET)).replace("\0", "0x00")
|
||||
post_data = get_query_str(cleanse_params(request.POST)).replace("\0", "0x00")
|
||||
|
||||
if self.is_whitelisted(request, credentials):
|
||||
log.info("AXES: Login failed from whitelisted client %s.", client_str)
|
||||
|
|
|
|||
|
|
@ -476,3 +476,24 @@ def toggleable(func) -> Callable:
|
|||
return func(*args, **kwargs)
|
||||
|
||||
return inner
|
||||
|
||||
|
||||
def cleanse_params(params: dict) -> dict:
|
||||
"""
|
||||
Replace sensitive parameter values in a parameter dict with
|
||||
a safe placeholder value.
|
||||
|
||||
Parameters to be cleansed are named in
|
||||
``settings.AXES_SENSITIVE_PARAMETERS``. If this setting is
|
||||
empty, no parameters will be replaced.
|
||||
|
||||
This is used to prevent passwords and similar values from
|
||||
being logged in cleartext.
|
||||
"""
|
||||
if settings.AXES_SENSITIVE_PARAMETERS:
|
||||
cleansed = params.copy()
|
||||
for param in settings.AXES_SENSITIVE_PARAMETERS:
|
||||
if param in cleansed:
|
||||
cleansed[param] = "********************"
|
||||
return cleansed
|
||||
return params
|
||||
|
|
|
|||
|
|
@ -111,6 +111,8 @@ The following ``settings.py`` options are available for customizing Axes behavio
|
|||
Default: ``False``
|
||||
* ``AXES_ALLOWED_CORS_ORIGINS``: Configures lockout response CORS headers for XHR requests.
|
||||
Default: ``*``
|
||||
* ``AXES_SENSITIVE_PARAMS``: Configures POST and GET parameter values to mask in login attempt logging.
|
||||
Default: ``['password',]``
|
||||
|
||||
The configuration option precedences for the access attempt monitoring are:
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ from axes.helpers import (
|
|||
is_ip_address_in_whitelist,
|
||||
is_user_attempt_whitelisted,
|
||||
toggleable,
|
||||
cleanse_params,
|
||||
)
|
||||
from axes.models import AccessAttempt
|
||||
from tests.base import AxesTestCase
|
||||
|
|
@ -602,6 +603,7 @@ class LockoutResponseTestCase(AxesTestCase):
|
|||
response = get_lockout_response(request=self.request)
|
||||
self.assertEqual(type(response), HttpResponse)
|
||||
|
||||
|
||||
def mock_get_cool_off_str():
|
||||
return timedelta(seconds=30)
|
||||
|
||||
|
|
@ -681,3 +683,32 @@ class AxesLockoutTestCase(AxesTestCase):
|
|||
def test_get_lockout_response_override_invalid(self):
|
||||
with self.assertRaises(TypeError):
|
||||
get_lockout_response(self.request, self.credentials)
|
||||
|
||||
|
||||
class AxesCleanseParamsTestCase(AxesTestCase):
|
||||
def setUp(self):
|
||||
self.params = {
|
||||
"username": "test_user",
|
||||
"password": "test_password",
|
||||
"other_sensitive_data": "sensitive",
|
||||
}
|
||||
|
||||
def test_cleanse_params(self):
|
||||
cleansed = cleanse_params(self.params)
|
||||
self.assertEqual("test_user", cleansed["username"])
|
||||
self.assertEqual("********************", cleansed["password"])
|
||||
self.assertEqual("sensitive", cleansed["other_sensitive_data"])
|
||||
|
||||
@override_settings(AXES_SENSITIVE_PARAMETERS=["other_sensitive_data"])
|
||||
def test_cleanse_params_override(self):
|
||||
cleansed = cleanse_params(self.params)
|
||||
self.assertEqual("test_user", cleansed["username"])
|
||||
self.assertEqual("test_password", cleansed["password"])
|
||||
self.assertEqual("********************", cleansed["other_sensitive_data"])
|
||||
|
||||
@override_settings(AXES_SENSITIVE_PARAMETERS=[])
|
||||
def test_cleanse_params_override_empty(self):
|
||||
cleansed = cleanse_params(self.params)
|
||||
self.assertEqual("test_user", cleansed["username"])
|
||||
self.assertEqual("test_password", cleansed["password"])
|
||||
self.assertEqual("sensitive", cleansed["other_sensitive_data"])
|
||||
|
|
|
|||
Loading…
Reference in a new issue