diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2b189a3..4ddcd6a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -7,6 +7,9 @@ Next version - Added two missing methods to the ``PermissionsBackend`` so that the admin app list works correctly. +- Added verification of the ``next`` cookie value also when setting the cookie, + not just when reading it. + 0.17 (2024-08-19) ================= diff --git a/authlib/views.py b/authlib/views.py index 21f9883..d80c711 100644 --- a/authlib/views.py +++ b/authlib/views.py @@ -23,8 +23,12 @@ def set_next_cookie(view): @wraps(view) def fn(request, *args, **kwargs): response = view(request, *args, **kwargs) - if request.GET.get("next"): - response.set_cookie(REDIRECT_COOKIE_NAME, request.GET["next"], max_age=600) + if (next := request.GET.get("next")) and url_has_allowed_host_and_scheme( + url=next, + allowed_hosts={request.get_host()}, + require_https=request.is_secure(), + ): + response.set_cookie(REDIRECT_COOKIE_NAME, next, max_age=600) return response return fn diff --git a/tests/testapp/test_authlib.py b/tests/testapp/test_authlib.py index 80f9c39..dbaeecc 100644 --- a/tests/testapp/test_authlib.py +++ b/tests/testapp/test_authlib.py @@ -223,6 +223,13 @@ def test_authlib(self): {"admin@example.com", "test@example.com"}, ) + def test_invalid_next_cookie(self): + client = Client() + response = client.get("/login/?next=http://example.com") + FacebookOAuth2Client.get_user_data = lambda self: {"email": "test@example.com"} + response = client.get("/oauth/facebook/?code=bla") + self.assertRedirects(response, "/?login=1", fetch_redirect_response=False) + def test_str_and_email_obfuscate(self): user = User(email="just-testing@example.com") self.assertEqual(user.get_full_name(), "jus***@***.com")