diff --git a/emark/views.py b/emark/views.py index 26ebaa3..f4bf2e8 100644 --- a/emark/views.py +++ b/emark/views.py @@ -1,5 +1,8 @@ +from urllib.parse import urlparse + from django import http -from django.utils.http import url_has_allowed_host_and_scheme +from django.conf import settings +from django.http.request import validate_host from django.views import View from django.views.generic.detail import SingleObjectMixin @@ -45,11 +48,8 @@ def get(self, request, *args, **kwargs): # The redirect_to URL is user-provided, so it might be malicious # or malformed. We use Django's URL validation to ensure that it # is safe to redirect to. - if not url_has_allowed_host_and_scheme( - url=redirect_to, - allowed_hosts=request.get_host(), - require_https=request.is_secure(), - ): + host = urlparse(redirect_to).netloc + if not host or not validate_host(host, settings.ALLOWED_HOSTS): return http.HttpResponseBadRequest("Missing url or malformed parameter") models.Click.objects.create_for_request( diff --git a/tests/test_views.py b/tests/test_views.py index 80bc896..ab42329 100644 --- a/tests/test_views.py +++ b/tests/test_views.py @@ -51,6 +51,17 @@ def test_get__unsafe_redirect_url(self, client, live_server): response = client.get(url) assert response.status_code == 400 + @pytest.mark.django_db + def test_get__subdomain_redirect_url(self, client, live_server): + msg = baker.make("emark.Send") + redirect_url = "http://sub.testserver/?utm_source=foo" + + url = reverse("emark:email-click", kwargs={"pk": msg.pk}) + + url = f"{url}?{urlencode({'url': redirect_url})}" + response = client.get(url) + assert response.status_code == 302 + @pytest.mark.django_db def test_get__no_email(self, client): response = client.get(reverse("emark:email-click", kwargs={"pk": uuid.uuid4()})) diff --git a/tests/testapp/settings.py b/tests/testapp/settings.py index 99b2082..07d7c55 100644 --- a/tests/testapp/settings.py +++ b/tests/testapp/settings.py @@ -25,7 +25,10 @@ # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -ALLOWED_HOSTS = [] +ALLOWED_HOSTS = [ + "testserver", + ".testserver", +] # Application definition