From 26bfc68c979dc1096e68b175fd3c130af2a269c1 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Tue, 6 Oct 2020 12:40:08 +0200 Subject: [PATCH 1/2] misc: check null characters in query-string and form data (#46625) --- src/authentic2/middleware.py | 21 +++++++++++++++++++++ src/authentic2/settings.py | 1 + tests/test_idp_saml2.py | 5 +++++ tests/test_login.py | 8 ++++++++ 4 files changed, 35 insertions(+) diff --git a/src/authentic2/middleware.py b/src/authentic2/middleware.py index f3b32aa0..c9b8b3b2 100644 --- a/src/authentic2/middleware.py +++ b/src/authentic2/middleware.py @@ -30,6 +30,7 @@ from django.utils.encoding import force_text from django.utils.translation import ugettext as _ from django.utils.six.moves.urllib import parse as urlparse from django.shortcuts import render +from django import http from . import app_settings, utils, plugins from .utils.service import get_service_from_request @@ -215,3 +216,23 @@ class SaveServiceInSessionMiddleware: request.session['service_pk'] = service.pk return self.get_response(request) + + +def null_character_middleware(get_response): + def middleware(request): + def check_query_dict(qd): + for key in qd: + for value in qd.getlist(key): + if '\0' in value: + return False + return True + + if not check_query_dict(request.GET): + return http.HttpResponseBadRequest('null character in query string') + + if request.content_type == 'application/x-www-form-urlencoded': + if not check_query_dict(request.POST): + return http.HttpResponseBadRequest('null character in form data') + + return get_response(request) + return middleware diff --git a/src/authentic2/settings.py b/src/authentic2/settings.py index c0ea6d9e..12bcf0e8 100644 --- a/src/authentic2/settings.py +++ b/src/authentic2/settings.py @@ -88,6 +88,7 @@ TEMPLATES = [ MIDDLEWARE = ( + 'authentic2.middleware.null_character_middleware', 'authentic2.middleware.StoreRequestMiddleware', 'authentic2.middleware.RequestIdMiddleware', 'authentic2.middleware.ServiceAccessControlMiddleware', diff --git a/tests/test_idp_saml2.py b/tests/test_idp_saml2.py index 182bc38d..209a434a 100644 --- a/tests/test_idp_saml2.py +++ b/tests/test_idp_saml2.py @@ -968,3 +968,8 @@ uGnhj8v6XwvbjKZrL9kA+xf8ziazZfvvw/VGTm+IVFYB7d1x457jY5zjjXJvNyso owIDAQAB -----END PUBLIC KEY-----''' response = app.get('/idp/saml2/metadata') + + +def test_null_character_nonce(app, db): + response = app.get('/idp/saml2/continue/', params={'nonce': '\0'}, status=400) + assert response.text == 'null character in query string' diff --git a/tests/test_login.py b/tests/test_login.py index 7302df19..ec2f6c2e 100644 --- a/tests/test_login.py +++ b/tests/test_login.py @@ -304,3 +304,11 @@ def test_login_opened_session_cookie(db, app, settings, simple_user): for cookie in app.cookiejar: if cookie.name == 'A2_OPENED_SESSION': assert cookie.secure is True + + +def test_null_characters(app, db): + response = app.get('/login/') + response.form.set('username', 'xx\0xx') + response.form.set('password', 'whatever') + response = response.form.submit(name='login-password-submit', status=400) + assert response.text == 'null character in form data' -- 2.28.0