Ticket #16008: 0001-Add-DNS-rebinding-protection.patch

File 0001-Add-DNS-rebinding-protection.patch, 5.5 KB (added by adehnert, 13 years ago)

Patch to provide protection against DNS rebinding attacks

  • django/conf/global_settings.py

    From ea94f01cc16ee123ab4621ba2e1f942645aaef7a Mon Sep 17 00:00:00 2001
    From: Alex Dehnert <adehnert@mit.edu>
    Date: Wed, 11 May 2011 20:20:50 -0400
    Subject: [PATCH] Add DNS rebinding protection.
    
    ---
     django/conf/global_settings.py |    7 ++++
     django/middleware/hostmatch.py |   42 +++++++++++++++++++++
     django/views/hostmatch.py      |   79 ++++++++++++++++++++++++++++++++++++++++
     3 files changed, 128 insertions(+), 0 deletions(-)
     create mode 100644 django/middleware/hostmatch.py
     create mode 100644 django/views/hostmatch.py
    
    diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py
    index 8638aee..c8b552b 100644
    a b CSRF_FAILURE_VIEW = 'django.views.csrf.csrf_failure'  
    497497CSRF_COOKIE_NAME = 'csrftoken'
    498498CSRF_COOKIE_DOMAIN = None
    499499
     500#############
     501# HOSTMATCH #
     502#############
     503
     504HOSTMATCH_FAILURE_VIEW = 'django.views.hostmatch.hostmatch_failure'
     505HOSTMATCH_ALLOWED_HOSTNAMES = None
     506
    500507############
    501508# MESSAGES #
    502509############
  • new file django/middleware/hostmatch.py

    diff --git a/django/middleware/hostmatch.py b/django/middleware/hostmatch.py
    new file mode 100644
    index 0000000..9eab6e1
    - +  
     1"""
     2Host-matching middleware.
     3
     4This module provides a middleware that implements protection
     5against DNS rebinding.
     6"""
     7
     8from django.conf import settings
     9from django.core.urlresolvers import get_callable
     10
     11REASON_BAD_HOST = "Host checking failed - %s not an allowed hostname."
     12
     13def _get_failure_view():
     14    """
     15    Returns the view to be used for host-matching rejections
     16    """
     17    return get_callable(settings.HOSTMATCH_FAILURE_VIEW)
     18
     19class HostMatchMiddleware(object):
     20    """
     21    Middleware that requires that, if sent, the Host header
     22    be a valid Host header for this site.
     23    """
     24
     25    def _accept(self, request):
     26        return None
     27
     28    def _reject(self, request, reason):
     29        return _get_failure_view()(request, reason=reason)
     30
     31    def host_match(self, name):
     32        if settings.HOSTMATCH_ALLOWED_HOSTNAMES is None:
     33            return True
     34        else:
     35            return name in settings.HOSTMATCH_ALLOWED_HOSTNAMES
     36
     37    def process_view(self, request, callback, callback_args, callback_kwargs):
     38        used_host = request.get_host().split(':')[0]
     39        if self.host_match(used_host):
     40            return self._accept(request)
     41        else:
     42            return self._reject(request, REASON_BAD_HOST % (used_host, ))
  • new file django/views/hostmatch.py

    diff --git a/django/views/hostmatch.py b/django/views/hostmatch.py
    new file mode 100644
    index 0000000..1ff281c
    - +  
     1from django.http import HttpResponseForbidden
     2from django.template import Context, Template
     3from django.conf import settings
     4
     5# We include the template inline since we need to be able to reliably display
     6# this error message, especially for the sake of developers, and there isn't any
     7# other way of making it available independent of what is in the settings file.
     8
     9HOSTMATCH_FAILURE_TEMPLATE = """
     10<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
     11<html lang="en">
     12<head>
     13  <meta http-equiv="content-type" content="text/html; charset=utf-8">
     14  <meta name="robots" content="NONE,NOARCHIVE">
     15  <title>403 Forbidden</title>
     16  <style type="text/css">
     17    html * { padding:0; margin:0; }
     18    body * { padding:10px 20px; }
     19    body * * { padding:0; }
     20    body { font:small sans-serif; background:#eee; }
     21    body>div { border-bottom:1px solid #ddd; }
     22    h1 { font-weight:normal; margin-bottom:.4em; }
     23    h1 span { font-size:60%; color:#666; font-weight:normal; }
     24    #info { background:#f6f6f6; }
     25    #info ul { margin: 0.5em 4em; }
     26    #info p, #summary p { padding-top:10px; }
     27    #summary { background: #ffc; }
     28    #explanation { background:#eee; border-bottom: 0px none; }
     29  </style>
     30</head>
     31<body>
     32<div id="summary">
     33  <h1>Forbidden <span>(403)</span></h1>
     34  <p>Hostname matching failed. Request aborted.</p>
     35
     36  <p>The <kbd>Host</kbd> header your browser supplied did not match the hostnames that this site is configured to serve.</p>
     37
     38</div>
     39{% if DEBUG %}
     40<div id="info">
     41  <h2>Help</h2>
     42    {% if reason %}
     43    <p>Reason given for failure:</p>
     44    <pre>
     45    {{ reason }}
     46    </pre>
     47    {% endif %}
     48
     49  <p>In general, this can occur when there is a genuine DNS rebinding attack, or when
     50  <a
     51  href='http://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ref-contrib-csrf'>Django's
     52  host matching</a> has not been used correctly. Make sure you have
     53  appropriately configured <code>settings.HOSTMATCH_ALLOWED_HOSTNAMES</code>.</p>
     54
     55  <p>You're seeing the help section of this page because you have <code>DEBUG =
     56  True</code> in your Django settings file. Change that to <code>False</code>,
     57  and only the initial error message will be displayed.  </p>
     58
     59  <p>You can customize this page using the HOSTMATCH_FAILURE_VIEW setting.</p>
     60</div>
     61{% else %}
     62<div id="explanation">
     63  <p><small>More information is available with DEBUG=True.</small></p>
     64</div>
     65{% endif %}
     66</body>
     67</html>
     68"""
     69
     70def hostmatch_failure(request, reason=""):
     71    """
     72    Default view used when request fails hostmatch protection
     73    """
     74    from django.middleware.csrf import REASON_NO_REFERER
     75    t = Template(HOSTMATCH_FAILURE_TEMPLATE)
     76    c = Context({'DEBUG': settings.DEBUG,
     77                 'reason': reason,
     78                 })
     79    return HttpResponseForbidden(t.render(c), mimetype='text/html')
Back to Top