Ticket #13751: openredirect-with-docs.diff

File openredirect-with-docs.diff, 4.5 KB (added by dpn, 5 years ago)
  • django/conf/global_settings.py

    diff -r e545a92e9079 django/conf/global_settings.py
    a b  
    521521
    522522# The list of directories to search for fixtures
    523523FIXTURE_DIRS = ()
     524
     525#Default url to redirect to to avoid Open Redirect issues. See: #13751
     526REDIRECT_FAILURE_URL = "/"
  • django/http/__init__.py

    diff -r e545a92e9079 django/http/__init__.py
    a b  
    33from Cookie import BaseCookie, SimpleCookie, CookieError
    44from pprint import pformat
    55from urllib import urlencode
    6 from urlparse import urljoin
     6from urlparse import urljoin, urlparse
     7import logging
    78try:
    89    # The mod_python version is more efficient, so try importing it first.
    910    from mod_python.util import parse_qsl
     
    432433class HttpResponseRedirect(HttpResponse):
    433434    status_code = 302
    434435
    435     def __init__(self, redirect_to):
     436    def __init__(self, redirect_to, whitelist=[], fallback_to=None):
    436437        HttpResponse.__init__(self)
    437438        self['Location'] = iri_to_uri(redirect_to)
     439       
     440        if urlparse(self['Location']).scheme:
     441            effective_whitelist = whitelist + getattr(settings, 'REDIRECT_WHITELIST', [])
     442
     443            matched = False
     444
     445            for pattern in effective_whitelist:
     446                matched = re.compile(pattern).match(self['Location'])
     447
     448                if matched:
     449                    break
     450
     451            if not matched:
     452                logging.warn("Found open redirect attack to %s", self['Location'])
     453
     454                self['Location'] = fallback_to or settings.REDIRECT_FAILURE_URL
    438455
    439456class HttpResponsePermanentRedirect(HttpResponse):
    440457    status_code = 301
  • docs/ref/request-response.txt

    diff -r e545a92e9079 docs/ref/request-response.txt
    a b  
    561561
    562562.. class:: HttpResponseRedirect
    563563
    564     The constructor takes a single argument -- the path to redirect to. This
     564    The constructor takes a single required argument -- the path to redirect to. This
    565565    can be a fully qualified URL (e.g. ``'http://www.yahoo.com/search/'``) or an
    566     absolute URL with no domain (e.g. ``'/search/'``). Note that this returns
    567     an HTTP status code 302.
     566    absolute URL with no domain (e.g. ``'/search/'``).
     567   
     568    Two optional parameters are ``whitelist`` and ``fallback_to``
     569    that are used to avoid the Open Redirect security issue. (see: http://www.google.com/support/webmasters/bin/answer.py?answer=171297 )
     570    The ``whitelist`` param is a list of regular expressions for whitelisted urls.
     571    A whitelist can also be defined in the :setting:`REDIRECT_WHITELIST` setting.
     572    Additionally, the ``fallback_to`` param is an optional URL to fallback to if
     573    none of the ``whitelist`` patterns match. You can also set the :setting:REDIRECT_FAILURE_URL
     574    setting to specify your own default fallback. By default this is set to "/".
     575   
     576    Note that this returns an HTTP status code 302.
    568577
    569578.. class:: HttpResponsePermanentRedirect
    570579
  • tests/regressiontests/httpwrappers/tests.py

    diff -r e545a92e9079 tests/regressiontests/httpwrappers/tests.py
    a b  
    11import copy
    22import pickle
    33import unittest
    4 from django.http import QueryDict, HttpResponse, CompatCookie, BadHeaderError
     4from django.http import QueryDict, HttpResponse, CompatCookie, BadHeaderError,\
     5    HttpResponseRedirect
     6from django.conf import settings
     7
    58
    69class QueryDictTests(unittest.TestCase):
    710    def test_missing_key(self):
     
    254257        c2 = CompatCookie()
    255258        c2.load(c.output())
    256259        self.assertEqual(c['test'].value, c2['test'].value)
     260
     261
     262class HttpResponseRedirectTests(unittest.TestCase):
     263    def test_open_redirect(self):
     264        self.assertEqual('/test', HttpResponseRedirect('/test')['Location'])
     265        self.assertEqual(settings.REDIRECT_FAILURE_URL, HttpResponseRedirect('http://djangoproject.com')['Location'])
     266
     267        r = HttpResponseRedirect('http://djangoproject.com', whitelist=[r'.*'])
     268        self.assertEqual('http://djangoproject.com', r['Location'])
     269
     270        setattr(settings, 'REDIRECT_WHITELIST', [r'.*'])
     271        self.assertEqual('http://djangoproject.com', HttpResponseRedirect('http://djangoproject.com')['Location'])
Back to Top