| | 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') |