Fix open redirect

Make sure the "next" URL is in the same origin as Horizon before
redirecting to it.

Conflicts:
	horizon/test/unit/workflows/test_workflows.py

Adapted to work with Django before 1.11 which only has a host argument,
instead of allowed_hosts for django.utils.http.is_safe_url().

Change-Id: I06b2bfc8e3638591615547780c3fa34b0abe19f6
Closes-bug: #1865026
(cherry picked from commit 252467100f)
(cherry picked from commit baa370f843)
(cherry picked from commit 6c208edf32)
(cherry picked from commit 8825407c1b)
This commit is contained in:
Radomir Dopieralski 2020-09-07 21:03:36 +02:00 committed by Jan Zerebecki
parent 7fbe9ab5ce
commit cd4e6db77a
No known key found for this signature in database
GPG Key ID: 94D2D0D2432ED7CC
3 changed files with 42 additions and 3 deletions

View File

@ -14,8 +14,8 @@
from django import forms from django import forms
from django import http from django import http
from django.test.utils import override_settings
import mock import mock
import six import six
from horizon import exceptions from horizon import exceptions
@ -359,3 +359,27 @@ class WorkflowsTests(test.TestCase):
flow = TestWorkflow(req, entry_point="test_action_two") flow = TestWorkflow(req, entry_point="test_action_two")
self.assertEqual("test_action_two", flow.get_entry_point()) self.assertEqual("test_action_two", flow.get_entry_point())
@override_settings(ALLOWED_HOSTS=['localhost'])
def test_redirect_url_safe(self):
url = 'http://localhost/test'
view = TestWorkflowView()
request = self.factory.get("/", data={
'next': url,
})
request.META['SERVER_NAME'] = "localhost"
view.request = request
context = view.get_context_data()
self.assertEqual(url, context['REDIRECT_URL'])
@override_settings(ALLOWED_HOSTS=['localhost'])
def test_redirect_url_unsafe(self):
url = 'http://evilcorp/test'
view = TestWorkflowView()
request = self.factory.get("/", data={
'next': url,
})
request.META['SERVER_NAME'] = "localhost"
view.request = request
context = view.get_context_data()
self.assertIsNone(context['REDIRECT_URL'])

View File

@ -18,6 +18,7 @@ import json
from django import forms from django import forms
from django import http from django import http
from django import shortcuts from django import shortcuts
from django.utils import http as utils_http
from django.views import generic from django.views import generic
import six import six
@ -92,8 +93,15 @@ class WorkflowView(hz_views.ModalBackdropMixin, generic.TemplateView):
workflow = self.get_workflow() workflow = self.get_workflow()
workflow.verify_integrity() workflow.verify_integrity()
context[self.context_object_name] = workflow context[self.context_object_name] = workflow
next = self.request.GET.get(workflow.redirect_param_name)
context['REDIRECT_URL'] = next redirect_to = self.request.GET.get(workflow.redirect_param_name)
# Make sure the requested redirect is safe
if redirect_to and not utils_http.is_safe_url(
url=redirect_to,
host=self.request.get_host()):
redirect_to = None
context['REDIRECT_URL'] = redirect_to
context['layout'] = self.get_layout() context['layout'] = self.get_layout()
# For consistency with Workflow class # For consistency with Workflow class
context['modal'] = 'modal' in context['layout'] context['modal'] = 'modal' in context['layout']

View File

@ -0,0 +1,7 @@
---
security:
- |
An open redirect has been fixed, that could redirect users to arbitrary
addresses from certain views by specifying a "next" parameter in the URL.
Now the redirect will only work if the target URL is in the same domain,
and uses the same protocol.