Ticket #16008: 0001-Add-DNS-rebinding-protection.patch
File 0001-Add-DNS-rebinding-protection.patch, 5.5 KB (added by , 14 years ago) |
---|
-
TabularUnified 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' 497 497 CSRF_COOKIE_NAME = 'csrftoken' 498 498 CSRF_COOKIE_DOMAIN = None 499 499 500 ############# 501 # HOSTMATCH # 502 ############# 503 504 HOSTMATCH_FAILURE_VIEW = 'django.views.hostmatch.hostmatch_failure' 505 HOSTMATCH_ALLOWED_HOSTNAMES = None 506 500 507 ############ 501 508 # MESSAGES # 502 509 ############ -
TabularUnified 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 """ 2 Host-matching middleware. 3 4 This module provides a middleware that implements protection 5 against DNS rebinding. 6 """ 7 8 from django.conf import settings 9 from django.core.urlresolvers import get_callable 10 11 REASON_BAD_HOST = "Host checking failed - %s not an allowed hostname." 12 13 def _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 19 class 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, )) -
TabularUnified 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
- + 1 from django.http import HttpResponseForbidden 2 from django.template import Context, Template 3 from 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 9 HOSTMATCH_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 70 def 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')