Code

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

File 0001-Add-DNS-rebinding-protection.patch, 5.5 KB (added by adehnert, 3 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')