diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py
index 280bfeb..6b759d8 100644
a
|
b
|
CSRF_COOKIE_PATH = '/'
|
558 | 558 | CSRF_COOKIE_SECURE = False |
559 | 559 | CSRF_COOKIE_HTTPONLY = False |
560 | 560 | CSRF_HEADER_NAME = 'HTTP_X_CSRFTOKEN' |
| 561 | CSRF_TRUSTED_ORIGINS = [] |
561 | 562 | |
562 | 563 | ############ |
563 | 564 | # MESSAGES # |
diff --git a/django/middleware/csrf.py b/django/middleware/csrf.py
index 6d16a92..dc00a70 100644
a
|
b
|
from django.utils.http import same_origin
|
19 | 19 | logger = logging.getLogger('django.request') |
20 | 20 | |
21 | 21 | REASON_NO_REFERER = "Referer checking failed - no Referer." |
22 | | REASON_BAD_REFERER = "Referer checking failed - %s does not match %s." |
| 22 | REASON_BAD_REFERER = "Referer checking failed - %s does not match any allowed hosts." |
23 | 23 | REASON_NO_CSRF_COOKIE = "CSRF cookie not set." |
24 | 24 | REASON_BAD_TOKEN = "CSRF token missing or incorrect." |
25 | 25 | |
… |
… |
class CsrfViewMiddleware(object):
|
154 | 154 | if referer is None: |
155 | 155 | return self._reject(request, REASON_NO_REFERER) |
156 | 156 | |
| 157 | # Here we generate a list of all acceptable HTTP referers, |
| 158 | # including the current host since that has been validated |
| 159 | # upstream. |
| 160 | # |
157 | 161 | # Note that request.get_host() includes the port. |
158 | | good_referer = 'https://%s/' % request.get_host() |
159 | | if not same_origin(referer, good_referer): |
160 | | reason = REASON_BAD_REFERER % (referer, good_referer) |
| 162 | good_hosts = list(settings.CSRF_TRUSTED_ORIGINS) |
| 163 | good_hosts.append(request.get_host()) |
| 164 | good_referers = ['https://{0}/'.format(host) for host in good_hosts] |
| 165 | if not any([same_origin(referer, host) for host in good_referers]): |
| 166 | reason = REASON_BAD_REFERER % (referer) |
161 | 167 | return self._reject(request, reason) |
162 | 168 | |
163 | 169 | if csrf_token is None: |
diff --git a/docs/ref/csrf.txt b/docs/ref/csrf.txt
index 5909905..7f37f8a 100644
a
|
b
|
The CSRF protection is based on the following things:
|
257 | 257 | due to the fact that HTTP 'Set-Cookie' headers are (unfortunately) accepted |
258 | 258 | by clients that are talking to a site under HTTPS. (Referer checking is not |
259 | 259 | done for HTTP requests because the presence of the Referer header is not |
260 | | reliable enough under HTTP.) |
| 260 | reliable enough under HTTP.) Expanding the accepted referers beyond the current host can be done with the :setting:`CSRF_TRUSTED_ORIGINS` setting. |
261 | 261 | |
262 | 262 | This ensures that only forms that have originated from your Web site can be used |
263 | 263 | to POST data back. |
… |
… |
A number of settings can be used to control Django's CSRF behavior:
|
460 | 460 | * :setting:`CSRF_COOKIE_SECURE` |
461 | 461 | * :setting:`CSRF_FAILURE_VIEW` |
462 | 462 | * :setting:`CSRF_HEADER_NAME` |
| 463 | * :setting:`CSRF_TRUSTED_ORIGINS` |
diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt
index 217f542..776c422 100644
a
|
b
|
any hyphens with underscores, and adding an ``'HTTP_'`` prefix to the name.
|
428 | 428 | For example, if your client sends a ``'X-XSRF-TOKEN'`` header, the setting |
429 | 429 | should be ``'HTTP_X_XSRF_TOKEN'``. |
430 | 430 | |
| 431 | CSRF_TRUSTED_ORIGINS |
| 432 | ---------------- |
| 433 | |
| 434 | .. versionadded:: 1.9 |
| 435 | |
| 436 | Default: ``[]`` |
| 437 | |
| 438 | An iterable containing domains which will be included as part of the referer checks during CSRF processing of secure requests. |
| 439 | |
431 | 440 | .. setting:: DATABASES |
432 | 441 | |
433 | 442 | DATABASES |
diff --git a/tests/csrf_tests/tests.py b/tests/csrf_tests/tests.py
index 2d347cc..41a2aed 100644
a
|
b
|
class CsrfViewMiddlewareTest(SimpleTestCase):
|
352 | 352 | req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {}) |
353 | 353 | self.assertIsNone(req2) |
354 | 354 | |
| 355 | @override_settings(ALLOWED_HOSTS=['www.example.com'], CSRF_TRUSTED_ORIGINS=['dashboard.example.com']) |
| 356 | def test_https_csrf_trusted_origin_allowed(self): |
| 357 | """ |
| 358 | Test that a POST HTTPS request with a referer added to the |
| 359 | CSRF_TRUSTED_ORIGINS setting is accepted |
| 360 | """ |
| 361 | # See ticket #24496 |
| 362 | req = self._get_POST_request_with_token() |
| 363 | req._is_secure_override = True |
| 364 | req.META['HTTP_HOST'] = 'www.example.com' |
| 365 | req.META['HTTP_REFERER'] = 'https://dashboard.example.com' |
| 366 | req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {}) |
| 367 | self.assertIsNone(req2) |
| 368 | |
355 | 369 | def test_ensures_csrf_cookie_no_middleware(self): |
356 | 370 | """ |
357 | 371 | Tests that ensures_csrf_cookie decorator fulfils its promise |