mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Moved contrib.csrf.* to core code.
There is stub code for backwards compatiblity with Django 1.1 imports. The documentation has been updated, but has been left in docs/contrib/csrf.txt for now, in order to avoid dead links to documentation on the website. git-svn-id: http://code.djangoproject.com/svn/django/trunk@11661 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
		| @@ -300,7 +300,7 @@ DEFAULT_INDEX_TABLESPACE = '' | |||||||
| MIDDLEWARE_CLASSES = ( | MIDDLEWARE_CLASSES = ( | ||||||
|     'django.middleware.common.CommonMiddleware', |     'django.middleware.common.CommonMiddleware', | ||||||
|     'django.contrib.sessions.middleware.SessionMiddleware', |     'django.contrib.sessions.middleware.SessionMiddleware', | ||||||
|     'django.contrib.csrf.middleware.CsrfViewMiddleware', |     'django.middleware.csrf.CsrfViewMiddleware', | ||||||
|     'django.contrib.auth.middleware.AuthenticationMiddleware', |     'django.contrib.auth.middleware.AuthenticationMiddleware', | ||||||
| #     'django.middleware.http.ConditionalGetMiddleware', | #     'django.middleware.http.ConditionalGetMiddleware', | ||||||
| #     'django.middleware.gzip.GZipMiddleware', | #     'django.middleware.gzip.GZipMiddleware', | ||||||
| @@ -381,7 +381,7 @@ PASSWORD_RESET_TIMEOUT_DAYS = 3 | |||||||
|  |  | ||||||
| # Dotted path to callable to be used as view when a request is | # Dotted path to callable to be used as view when a request is | ||||||
| # rejected by the CSRF middleware. | # rejected by the CSRF middleware. | ||||||
| CSRF_FAILURE_VIEW = 'django.contrib.csrf.views.csrf_failure' | CSRF_FAILURE_VIEW = 'django.views.csrf.csrf_failure' | ||||||
|  |  | ||||||
| # Name and domain for CSRF cookie. | # Name and domain for CSRF cookie. | ||||||
| CSRF_COOKIE_NAME = 'csrftoken' | CSRF_COOKIE_NAME = 'csrftoken' | ||||||
|   | |||||||
| @@ -60,7 +60,7 @@ TEMPLATE_LOADERS = ( | |||||||
| MIDDLEWARE_CLASSES = ( | MIDDLEWARE_CLASSES = ( | ||||||
|     'django.middleware.common.CommonMiddleware', |     'django.middleware.common.CommonMiddleware', | ||||||
|     'django.contrib.sessions.middleware.SessionMiddleware', |     'django.contrib.sessions.middleware.SessionMiddleware', | ||||||
|     'django.contrib.csrf.middleware.CsrfViewMiddleware', |     'django.middleware.csrf.CsrfViewMiddleware', | ||||||
|     'django.contrib.auth.middleware.AuthenticationMiddleware', |     'django.contrib.auth.middleware.AuthenticationMiddleware', | ||||||
| ) | ) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ from django.contrib.contenttypes.models import ContentType | |||||||
| from django.contrib.admin import widgets | from django.contrib.admin import widgets | ||||||
| from django.contrib.admin import helpers | from django.contrib.admin import helpers | ||||||
| from django.contrib.admin.util import unquote, flatten_fieldsets, get_deleted_objects, model_ngettext, model_format_dict | from django.contrib.admin.util import unquote, flatten_fieldsets, get_deleted_objects, model_ngettext, model_format_dict | ||||||
| from django.contrib.csrf.decorators import csrf_protect | from django.views.decorators.csrf import csrf_protect | ||||||
| from django.core.exceptions import PermissionDenied | from django.core.exceptions import PermissionDenied | ||||||
| from django.db import models, transaction | from django.db import models, transaction | ||||||
| from django.db.models.fields import BLANK_CHOICE_DASH | from django.db.models.fields import BLANK_CHOICE_DASH | ||||||
|   | |||||||
| @@ -3,8 +3,7 @@ from django import http, template | |||||||
| from django.contrib.admin import ModelAdmin | from django.contrib.admin import ModelAdmin | ||||||
| from django.contrib.admin import actions | from django.contrib.admin import actions | ||||||
| from django.contrib.auth import authenticate, login | from django.contrib.auth import authenticate, login | ||||||
| from django.contrib.csrf.middleware import csrf_response_exempt | from django.views.decorators.csrf import csrf_protect, csrf_response_exempt | ||||||
| from django.contrib.csrf.decorators import csrf_protect |  | ||||||
| from django.db.models.base import ModelBase | from django.db.models.base import ModelBase | ||||||
| from django.core.exceptions import ImproperlyConfigured | from django.core.exceptions import ImproperlyConfigured | ||||||
| from django.core.urlresolvers import reverse | from django.core.urlresolvers import reverse | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ from django.contrib.auth.decorators import login_required | |||||||
| from django.contrib.auth.forms import AuthenticationForm | from django.contrib.auth.forms import AuthenticationForm | ||||||
| from django.contrib.auth.forms import PasswordResetForm, SetPasswordForm, PasswordChangeForm | from django.contrib.auth.forms import PasswordResetForm, SetPasswordForm, PasswordChangeForm | ||||||
| from django.contrib.auth.tokens import default_token_generator | from django.contrib.auth.tokens import default_token_generator | ||||||
| from django.contrib.csrf.decorators import csrf_protect | from django.views.decorators.csrf import csrf_protect | ||||||
| from django.core.urlresolvers import reverse | from django.core.urlresolvers import reverse | ||||||
| from django.shortcuts import render_to_response, get_object_or_404 | from django.shortcuts import render_to_response, get_object_or_404 | ||||||
| from django.contrib.sites.models import Site, RequestSite | from django.contrib.sites.models import Site, RequestSite | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ from django.utils.html import escape | |||||||
| from django.views.decorators.http import require_POST | from django.views.decorators.http import require_POST | ||||||
| from django.contrib import comments | from django.contrib import comments | ||||||
| from django.contrib.comments import signals | from django.contrib.comments import signals | ||||||
| from django.contrib.csrf.decorators import csrf_protect | from django.views.decorators.csrf import csrf_protect | ||||||
|  |  | ||||||
| class CommentPostBadRequest(http.HttpResponseBadRequest): | class CommentPostBadRequest(http.HttpResponseBadRequest): | ||||||
|     """ |     """ | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ from django.contrib.auth.decorators import login_required, permission_required | |||||||
| from utils import next_redirect, confirmation_view | from utils import next_redirect, confirmation_view | ||||||
| from django.contrib import comments | from django.contrib import comments | ||||||
| from django.contrib.comments import signals | from django.contrib.comments import signals | ||||||
| from django.contrib.csrf.decorators import csrf_protect | from django.views.decorators.csrf import csrf_protect | ||||||
|  |  | ||||||
| @csrf_protect | @csrf_protect | ||||||
| @login_required | @login_required | ||||||
|   | |||||||
| @@ -1,20 +0,0 @@ | |||||||
| from django.contrib.csrf.middleware import get_token |  | ||||||
| from django.utils.functional import lazy |  | ||||||
|  |  | ||||||
| def csrf(request): |  | ||||||
|     """ |  | ||||||
|     Context processor that provides a CSRF token, or the string 'NOTPROVIDED' if |  | ||||||
|     it has not been provided by either a view decorator or the middleware |  | ||||||
|     """ |  | ||||||
|     def _get_val(): |  | ||||||
|         token = get_token(request) |  | ||||||
|         if token is None: |  | ||||||
|             # In order to be able to provide debugging info in the |  | ||||||
|             # case of misconfiguration, we use a sentinel value |  | ||||||
|             # instead of returning an empty dict. |  | ||||||
|             return 'NOTPROVIDED' |  | ||||||
|         else: |  | ||||||
|             return token |  | ||||||
|     _get_val = lazy(_get_val, str) |  | ||||||
|  |  | ||||||
|     return {'csrf_token': _get_val() } |  | ||||||
| @@ -1,10 +0,0 @@ | |||||||
| from django.contrib.csrf.middleware import CsrfViewMiddleware |  | ||||||
| from django.utils.decorators import decorator_from_middleware |  | ||||||
|  |  | ||||||
| csrf_protect = decorator_from_middleware(CsrfViewMiddleware) |  | ||||||
| csrf_protect.__name__ = "csrf_protect" |  | ||||||
| csrf_protect.__doc__ = """ |  | ||||||
| This decorator adds CSRF protection in exactly the same way as |  | ||||||
| CsrfViewMiddleware, but it can be used on a per view basis.  Using both, or |  | ||||||
| using the decorator multiple times, is harmless and efficient. |  | ||||||
| """ |  | ||||||
| @@ -1,294 +1,7 @@ | |||||||
| """ | from django.middleware.csrf import CsrfMiddleware, CsrfViewMiddleware, CsrfResponseMiddleware | ||||||
| Cross Site Request Forgery Middleware. | from django.views.decorators.csrf import csrf_exempt, csrf_view_exempt, csrf_response_exempt | ||||||
|  |  | ||||||
| This module provides a middleware that implements protection |  | ||||||
| against request forgeries from other sites. |  | ||||||
| """ |  | ||||||
|  |  | ||||||
| import itertools |  | ||||||
| import re |  | ||||||
| import random |  | ||||||
| try: |  | ||||||
|     from functools import wraps |  | ||||||
| except ImportError: |  | ||||||
|     from django.utils.functional import wraps  # Python 2.3, 2.4 fallback. |  | ||||||
|  |  | ||||||
| from django.conf import settings |  | ||||||
| from django.core.urlresolvers import get_callable |  | ||||||
| from django.utils.cache import patch_vary_headers |  | ||||||
| from django.utils.hashcompat import md5_constructor |  | ||||||
| from django.utils.safestring import mark_safe |  | ||||||
|  |  | ||||||
| _POST_FORM_RE = \ |  | ||||||
|     re.compile(r'(<form\W[^>]*\bmethod\s*=\s*(\'|"|)POST(\'|"|)\b[^>]*>)', re.IGNORECASE) |  | ||||||
|  |  | ||||||
| _HTML_TYPES = ('text/html', 'application/xhtml+xml') |  | ||||||
|  |  | ||||||
| # Use the system (hardware-based) random number generator if it exists. |  | ||||||
| if hasattr(random, 'SystemRandom'): |  | ||||||
|     randrange = random.SystemRandom().randrange |  | ||||||
| else: |  | ||||||
|     randrange = random.randrange |  | ||||||
| _MAX_CSRF_KEY = 18446744073709551616L     # 2 << 63 |  | ||||||
|  |  | ||||||
| def _get_failure_view(): |  | ||||||
|     """ |  | ||||||
|     Returns the view to be used for CSRF rejections |  | ||||||
|     """ |  | ||||||
|     return get_callable(settings.CSRF_FAILURE_VIEW) |  | ||||||
|  |  | ||||||
| def _get_new_csrf_key(): |  | ||||||
|     return md5_constructor("%s%s" |  | ||||||
|                 % (randrange(0, _MAX_CSRF_KEY), settings.SECRET_KEY)).hexdigest() |  | ||||||
|  |  | ||||||
| def _make_legacy_session_token(session_id): |  | ||||||
|     return md5_constructor(settings.SECRET_KEY + session_id).hexdigest() |  | ||||||
|  |  | ||||||
| def get_token(request): |  | ||||||
|     """ |  | ||||||
|     Returns the the CSRF token required for a POST form. |  | ||||||
|  |  | ||||||
|     A side effect of calling this function is to make the the csrf_protect |  | ||||||
|     decorator and the CsrfViewMiddleware add a CSRF cookie and a 'Vary: Cookie' |  | ||||||
|     header to the outgoing response.  For this reason, you may need to use this |  | ||||||
|     function lazily, as is done by the csrf context processor. |  | ||||||
|     """ |  | ||||||
|     request.META["CSRF_COOKIE_USED"] = True |  | ||||||
|     return request.META.get("CSRF_COOKIE", None) |  | ||||||
|  |  | ||||||
| class CsrfViewMiddleware(object): |  | ||||||
|     """ |  | ||||||
|     Middleware that requires a present and correct csrfmiddlewaretoken |  | ||||||
|     for POST requests that have a CSRF cookie, and sets an outgoing |  | ||||||
|     CSRF cookie. |  | ||||||
|  |  | ||||||
|     This middleware should be used in conjunction with the csrf_token template |  | ||||||
|     tag. |  | ||||||
|     """ |  | ||||||
|     def process_view(self, request, callback, callback_args, callback_kwargs): |  | ||||||
|         if getattr(callback, 'csrf_exempt', False): |  | ||||||
|             return None |  | ||||||
|  |  | ||||||
|         if getattr(request, 'csrf_processing_done', False): |  | ||||||
|             return None |  | ||||||
|  |  | ||||||
|         reject = lambda s: _get_failure_view()(request, reason=s) |  | ||||||
|         def accept(): |  | ||||||
|             # Avoid checking the request twice by adding a custom attribute to |  | ||||||
|             # request.  This will be relevant when both decorator and middleware |  | ||||||
|             # are used. |  | ||||||
|             request.csrf_processing_done = True |  | ||||||
|             return None |  | ||||||
|  |  | ||||||
|         # If the user doesn't have a CSRF cookie, generate one and store it in the |  | ||||||
|         # request, so it's available to the view.  We'll store it in a cookie when |  | ||||||
|         # we reach the response. |  | ||||||
|         try: |  | ||||||
|             request.META["CSRF_COOKIE"] = request.COOKIES[settings.CSRF_COOKIE_NAME] |  | ||||||
|             cookie_is_new = False |  | ||||||
|         except KeyError: |  | ||||||
|             # No cookie, so create one. |  | ||||||
|             request.META["CSRF_COOKIE"] = _get_new_csrf_key() |  | ||||||
|             cookie_is_new = True |  | ||||||
|  |  | ||||||
|         if request.method == 'POST': |  | ||||||
|             if getattr(request, '_dont_enforce_csrf_checks', False): |  | ||||||
|                 # Mechanism to turn off CSRF checks for test suite.  It comes after |  | ||||||
|                 # the creation of CSRF cookies, so that everything else continues to |  | ||||||
|                 # work exactly the same (e.g. cookies are sent etc), but before the |  | ||||||
|                 # any branches that call reject() |  | ||||||
|                 return accept() |  | ||||||
|  |  | ||||||
|             if request.is_ajax(): |  | ||||||
|                 # .is_ajax() is based on the presence of X-Requested-With.  In |  | ||||||
|                 # the context of a browser, this can only be sent if using |  | ||||||
|                 # XmlHttpRequest.  Browsers implement careful policies for |  | ||||||
|                 # XmlHttpRequest: |  | ||||||
|                 # |  | ||||||
|                 #  * Normally, only same-domain requests are allowed. |  | ||||||
|                 # |  | ||||||
|                 #  * Some browsers (e.g. Firefox 3.5 and later) relax this |  | ||||||
|                 #    carefully: |  | ||||||
|                 # |  | ||||||
|                 #    * if it is a 'simple' GET or POST request (which can |  | ||||||
|                 #      include no custom headers), it is allowed to be cross |  | ||||||
|                 #      domain.  These requests will not be recognized as AJAX. |  | ||||||
|                 # |  | ||||||
|                 #    * if a 'preflight' check with the server confirms that the |  | ||||||
|                 #      server is expecting and allows the request, cross domain |  | ||||||
|                 #      requests even with custom headers are allowed. These |  | ||||||
|                 #      requests will be recognized as AJAX, but can only get |  | ||||||
|                 #      through when the developer has specifically opted in to |  | ||||||
|                 #      allowing the cross-domain POST request. |  | ||||||
|                 # |  | ||||||
|                 # So in all cases, it is safe to allow these requests through. |  | ||||||
|                 return accept() |  | ||||||
|  |  | ||||||
|             if request.is_secure(): |  | ||||||
|                 # Strict referer checking for HTTPS |  | ||||||
|                 referer = request.META.get('HTTP_REFERER') |  | ||||||
|                 if referer is None: |  | ||||||
|                     return reject("Referer checking failed - no Referer.") |  | ||||||
|  |  | ||||||
|                 # The following check ensures that the referer is HTTPS, |  | ||||||
|                 # the domains match and the ports match.  This might be too strict. |  | ||||||
|                 good_referer = 'https://%s/' % request.get_host() |  | ||||||
|                 if not referer.startswith(good_referer): |  | ||||||
|                     return reject("Referer checking failed - %s does not match %s." % |  | ||||||
|                                   (referer, good_referer)) |  | ||||||
|  |  | ||||||
|             # If the user didn't already have a CSRF key, then accept the |  | ||||||
|             # session key for the middleware token, so CSRF protection isn't lost |  | ||||||
|             # for the period between upgrading to CSRF cookes to the first time |  | ||||||
|             # each user comes back to the site to receive one. |  | ||||||
|             if cookie_is_new: |  | ||||||
|                 try: |  | ||||||
|                     session_id = request.COOKIES[settings.SESSION_COOKIE_NAME] |  | ||||||
|                     csrf_token = _make_legacy_session_token(session_id) |  | ||||||
|                 except KeyError: |  | ||||||
|                     # No CSRF cookie and no session cookie. For POST requests, |  | ||||||
|                     # we insist on a CSRF cookie, and in this way we can avoid |  | ||||||
|                     # all CSRF attacks, including login CSRF. |  | ||||||
|                     return reject("No CSRF cookie.") |  | ||||||
|             else: |  | ||||||
|                 csrf_token = request.META["CSRF_COOKIE"] |  | ||||||
|  |  | ||||||
|             # check incoming token |  | ||||||
|             request_csrf_token = request.POST.get('csrfmiddlewaretoken', None) |  | ||||||
|             if request_csrf_token != csrf_token: |  | ||||||
|                 return reject("CSRF token missing or incorrect.") |  | ||||||
|  |  | ||||||
|         return accept() |  | ||||||
|  |  | ||||||
|     def process_response(self, request, response): |  | ||||||
|         if getattr(response, 'csrf_processing_done', False): |  | ||||||
|             return response |  | ||||||
|  |  | ||||||
|         # If CSRF_COOKIE is unset, then CsrfViewMiddleware.process_view was |  | ||||||
|         # never called, probaby because a request middleware returned a response |  | ||||||
|         # (for example, contrib.auth redirecting to a login page). |  | ||||||
|         if request.META.get("CSRF_COOKIE") is None: |  | ||||||
|             return response |  | ||||||
|  |  | ||||||
|         if not request.META.get("CSRF_COOKIE_USED", False): |  | ||||||
|             return response |  | ||||||
|  |  | ||||||
|         # Set the CSRF cookie even if it's already set, so we renew the expiry timer. |  | ||||||
|         response.set_cookie(settings.CSRF_COOKIE_NAME, |  | ||||||
|                 request.META["CSRF_COOKIE"], max_age = 60 * 60 * 24 * 7 * 52, |  | ||||||
|                 domain=settings.CSRF_COOKIE_DOMAIN) |  | ||||||
|         # Content varies with the CSRF cookie, so set the Vary header. |  | ||||||
|         patch_vary_headers(response, ('Cookie',)) |  | ||||||
|         response.csrf_processing_done = True |  | ||||||
|         return response |  | ||||||
|  |  | ||||||
| class CsrfResponseMiddleware(object): |  | ||||||
|     """ |  | ||||||
|     DEPRECATED |  | ||||||
|     Middleware that post-processes a response to add a csrfmiddlewaretoken. |  | ||||||
|  |  | ||||||
|     This exists for backwards compatibility and as an interim measure until |  | ||||||
|     applications are converted to using use the csrf_token template tag |  | ||||||
|     instead. It will be removed in Django 1.4. |  | ||||||
|     """ |  | ||||||
|     def __init__(self): |  | ||||||
| import warnings | import warnings | ||||||
|         warnings.warn( | warnings.warn("This import for CSRF functionality is deprecated.  Please use django.middleware.csrf for the middleware and django.views.decorators.csrf for decorators.", | ||||||
|             "CsrfResponseMiddleware and CsrfMiddleware are deprecated; use CsrfViewMiddleware and the template tag instead (see CSRF documentation).", |  | ||||||
|               PendingDeprecationWarning |               PendingDeprecationWarning | ||||||
|               ) |               ) | ||||||
|  |  | ||||||
|     def process_response(self, request, response): |  | ||||||
|         if getattr(response, 'csrf_exempt', False): |  | ||||||
|             return response |  | ||||||
|  |  | ||||||
|         if response['Content-Type'].split(';')[0] in _HTML_TYPES: |  | ||||||
|             csrf_token = get_token(request) |  | ||||||
|             # If csrf_token is None, we have no token for this request, which probably |  | ||||||
|             # means that this is a response from a request middleware. |  | ||||||
|             if csrf_token is None: |  | ||||||
|                 return response |  | ||||||
|  |  | ||||||
|             # ensure we don't add the 'id' attribute twice (HTML validity) |  | ||||||
|             idattributes = itertools.chain(("id='csrfmiddlewaretoken'",), |  | ||||||
|                                            itertools.repeat('')) |  | ||||||
|             def add_csrf_field(match): |  | ||||||
|                 """Returns the matched <form> tag plus the added <input> element""" |  | ||||||
|                 return mark_safe(match.group() + "<div style='display:none;'>" + \ |  | ||||||
|                 "<input type='hidden' " + idattributes.next() + \ |  | ||||||
|                 " name='csrfmiddlewaretoken' value='" + csrf_token + \ |  | ||||||
|                 "' /></div>") |  | ||||||
|  |  | ||||||
|             # Modify any POST forms |  | ||||||
|             response.content, n = _POST_FORM_RE.subn(add_csrf_field, response.content) |  | ||||||
|             if n > 0: |  | ||||||
|                 # Content varies with the CSRF cookie, so set the Vary header. |  | ||||||
|                 patch_vary_headers(response, ('Cookie',)) |  | ||||||
|  |  | ||||||
|                 # Since the content has been modified, any Etag will now be |  | ||||||
|                 # incorrect.  We could recalculate, but only if we assume that               |  | ||||||
|                 # the Etag was set by CommonMiddleware. The safest thing is just |  | ||||||
|                 # to delete. See bug #9163 |  | ||||||
|                 del response['ETag'] |  | ||||||
|         return response |  | ||||||
|  |  | ||||||
| class CsrfMiddleware(object): |  | ||||||
|     """ |  | ||||||
|     Django middleware that adds protection against Cross Site |  | ||||||
|     Request Forgeries by adding hidden form fields to POST forms and |  | ||||||
|     checking requests for the correct value. |  | ||||||
|  |  | ||||||
|     CsrfMiddleware uses two middleware, CsrfViewMiddleware and |  | ||||||
|     CsrfResponseMiddleware, which can be used independently.  It is recommended |  | ||||||
|     to use only CsrfViewMiddleware and use the csrf_token template tag in |  | ||||||
|     templates for inserting the token. |  | ||||||
|     """ |  | ||||||
|     # We can't just inherit from CsrfViewMiddleware and CsrfResponseMiddleware |  | ||||||
|     # because both have process_response methods. |  | ||||||
|     def __init__(self): |  | ||||||
|         self.response_middleware = CsrfResponseMiddleware() |  | ||||||
|         self.view_middleware = CsrfViewMiddleware() |  | ||||||
|  |  | ||||||
|     def process_response(self, request, resp): |  | ||||||
|         # We must do the response post-processing first, because that calls |  | ||||||
|         # get_token(), which triggers a flag saying that the CSRF cookie needs |  | ||||||
|         # to be sent (done in CsrfViewMiddleware.process_response) |  | ||||||
|         resp2 = self.response_middleware.process_response(request, resp) |  | ||||||
|         return self.view_middleware.process_response(request, resp2) |  | ||||||
|  |  | ||||||
|     def process_view(self, request, callback, callback_args, callback_kwargs): |  | ||||||
|         return self.view_middleware.process_view(request, callback, callback_args, |  | ||||||
|                                                  callback_kwargs) |  | ||||||
|  |  | ||||||
| def csrf_response_exempt(view_func): |  | ||||||
|     """ |  | ||||||
|     Modifies a view function so that its response is exempt |  | ||||||
|     from the post-processing of the CSRF middleware. |  | ||||||
|     """ |  | ||||||
|     def wrapped_view(*args, **kwargs): |  | ||||||
|         resp = view_func(*args, **kwargs) |  | ||||||
|         resp.csrf_exempt = True |  | ||||||
|         return resp |  | ||||||
|     return wraps(view_func)(wrapped_view) |  | ||||||
|  |  | ||||||
| def csrf_view_exempt(view_func): |  | ||||||
|     """ |  | ||||||
|     Marks a view function as being exempt from CSRF view protection. |  | ||||||
|     """ |  | ||||||
|     # We could just do view_func.csrf_exempt = True, but decorators |  | ||||||
|     # are nicer if they don't have side-effects, so we return a new |  | ||||||
|     # function. |  | ||||||
|     def wrapped_view(*args, **kwargs): |  | ||||||
|         return view_func(*args, **kwargs) |  | ||||||
|     wrapped_view.csrf_exempt = True |  | ||||||
|     return wraps(view_func)(wrapped_view) |  | ||||||
|  |  | ||||||
| def csrf_exempt(view_func): |  | ||||||
|     """ |  | ||||||
|     Marks a view function as being exempt from the CSRF checks |  | ||||||
|     and post processing. |  | ||||||
|  |  | ||||||
|     This is the same as using both the csrf_view_exempt and |  | ||||||
|     csrf_response_exempt decorators. |  | ||||||
|     """ |  | ||||||
|     return csrf_response_exempt(csrf_view_exempt(view_func)) |  | ||||||
|   | |||||||
| @@ -14,7 +14,7 @@ from django.template.context import RequestContext | |||||||
| from django.utils.hashcompat import md5_constructor | from django.utils.hashcompat import md5_constructor | ||||||
| from django.utils.translation import ugettext_lazy as _ | from django.utils.translation import ugettext_lazy as _ | ||||||
| from django.contrib.formtools.utils import security_hash | from django.contrib.formtools.utils import security_hash | ||||||
| from django.contrib.csrf.decorators import csrf_protect | from django.views.decorators.csrf import csrf_protect | ||||||
|  |  | ||||||
| class FormWizard(object): | class FormWizard(object): | ||||||
|     # Dictionary of extra template context variables. |     # Dictionary of extra template context variables. | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ RequestContext. | |||||||
| """ | """ | ||||||
|  |  | ||||||
| from django.conf import settings | from django.conf import settings | ||||||
|  | from django.middleware.csrf import get_token | ||||||
| from django.utils.functional import lazy, memoize, SimpleLazyObject | from django.utils.functional import lazy, memoize, SimpleLazyObject | ||||||
|  |  | ||||||
| def auth(request): | def auth(request): | ||||||
| @@ -40,6 +41,24 @@ def auth(request): | |||||||
|         'perms':  lazy(lambda: PermWrapper(get_user()), PermWrapper)(), |         'perms':  lazy(lambda: PermWrapper(get_user()), PermWrapper)(), | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | def csrf(request): | ||||||
|  |     """ | ||||||
|  |     Context processor that provides a CSRF token, or the string 'NOTPROVIDED' if | ||||||
|  |     it has not been provided by either a view decorator or the middleware | ||||||
|  |     """ | ||||||
|  |     def _get_val(): | ||||||
|  |         token = get_token(request) | ||||||
|  |         if token is None: | ||||||
|  |             # In order to be able to provide debugging info in the | ||||||
|  |             # case of misconfiguration, we use a sentinel value | ||||||
|  |             # instead of returning an empty dict. | ||||||
|  |             return 'NOTPROVIDED' | ||||||
|  |         else: | ||||||
|  |             return token | ||||||
|  |     _get_val = lazy(_get_val, str) | ||||||
|  |  | ||||||
|  |     return {'csrf_token': _get_val() } | ||||||
|  |  | ||||||
| def debug(request): | def debug(request): | ||||||
|     "Returns context variables helpful for debugging." |     "Returns context variables helpful for debugging." | ||||||
|     context_extras = {} |     context_extras = {} | ||||||
|   | |||||||
							
								
								
									
										262
									
								
								django/middleware/csrf.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										262
									
								
								django/middleware/csrf.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,262 @@ | |||||||
|  | """ | ||||||
|  | Cross Site Request Forgery Middleware. | ||||||
|  |  | ||||||
|  | This module provides a middleware that implements protection | ||||||
|  | against request forgeries from other sites. | ||||||
|  | """ | ||||||
|  |  | ||||||
|  | import itertools | ||||||
|  | import re | ||||||
|  | import random | ||||||
|  | try: | ||||||
|  |     from functools import wraps | ||||||
|  | except ImportError: | ||||||
|  |     from django.utils.functional import wraps  # Python 2.3, 2.4 fallback. | ||||||
|  |  | ||||||
|  | from django.conf import settings | ||||||
|  | from django.core.urlresolvers import get_callable | ||||||
|  | from django.utils.cache import patch_vary_headers | ||||||
|  | from django.utils.hashcompat import md5_constructor | ||||||
|  | from django.utils.safestring import mark_safe | ||||||
|  |  | ||||||
|  | _POST_FORM_RE = \ | ||||||
|  |     re.compile(r'(<form\W[^>]*\bmethod\s*=\s*(\'|"|)POST(\'|"|)\b[^>]*>)', re.IGNORECASE) | ||||||
|  |  | ||||||
|  | _HTML_TYPES = ('text/html', 'application/xhtml+xml') | ||||||
|  |  | ||||||
|  | # Use the system (hardware-based) random number generator if it exists. | ||||||
|  | if hasattr(random, 'SystemRandom'): | ||||||
|  |     randrange = random.SystemRandom().randrange | ||||||
|  | else: | ||||||
|  |     randrange = random.randrange | ||||||
|  | _MAX_CSRF_KEY = 18446744073709551616L     # 2 << 63 | ||||||
|  |  | ||||||
|  | def _get_failure_view(): | ||||||
|  |     """ | ||||||
|  |     Returns the view to be used for CSRF rejections | ||||||
|  |     """ | ||||||
|  |     return get_callable(settings.CSRF_FAILURE_VIEW) | ||||||
|  |  | ||||||
|  | def _get_new_csrf_key(): | ||||||
|  |     return md5_constructor("%s%s" | ||||||
|  |                 % (randrange(0, _MAX_CSRF_KEY), settings.SECRET_KEY)).hexdigest() | ||||||
|  |  | ||||||
|  | def _make_legacy_session_token(session_id): | ||||||
|  |     return md5_constructor(settings.SECRET_KEY + session_id).hexdigest() | ||||||
|  |  | ||||||
|  | def get_token(request): | ||||||
|  |     """ | ||||||
|  |     Returns the the CSRF token required for a POST form. | ||||||
|  |  | ||||||
|  |     A side effect of calling this function is to make the the csrf_protect | ||||||
|  |     decorator and the CsrfViewMiddleware add a CSRF cookie and a 'Vary: Cookie' | ||||||
|  |     header to the outgoing response.  For this reason, you may need to use this | ||||||
|  |     function lazily, as is done by the csrf context processor. | ||||||
|  |     """ | ||||||
|  |     request.META["CSRF_COOKIE_USED"] = True | ||||||
|  |     return request.META.get("CSRF_COOKIE", None) | ||||||
|  |  | ||||||
|  | class CsrfViewMiddleware(object): | ||||||
|  |     """ | ||||||
|  |     Middleware that requires a present and correct csrfmiddlewaretoken | ||||||
|  |     for POST requests that have a CSRF cookie, and sets an outgoing | ||||||
|  |     CSRF cookie. | ||||||
|  |  | ||||||
|  |     This middleware should be used in conjunction with the csrf_token template | ||||||
|  |     tag. | ||||||
|  |     """ | ||||||
|  |     def process_view(self, request, callback, callback_args, callback_kwargs): | ||||||
|  |         if getattr(callback, 'csrf_exempt', False): | ||||||
|  |             return None | ||||||
|  |  | ||||||
|  |         if getattr(request, 'csrf_processing_done', False): | ||||||
|  |             return None | ||||||
|  |  | ||||||
|  |         reject = lambda s: _get_failure_view()(request, reason=s) | ||||||
|  |         def accept(): | ||||||
|  |             # Avoid checking the request twice by adding a custom attribute to | ||||||
|  |             # request.  This will be relevant when both decorator and middleware | ||||||
|  |             # are used. | ||||||
|  |             request.csrf_processing_done = True | ||||||
|  |             return None | ||||||
|  |  | ||||||
|  |         # If the user doesn't have a CSRF cookie, generate one and store it in the | ||||||
|  |         # request, so it's available to the view.  We'll store it in a cookie when | ||||||
|  |         # we reach the response. | ||||||
|  |         try: | ||||||
|  |             request.META["CSRF_COOKIE"] = request.COOKIES[settings.CSRF_COOKIE_NAME] | ||||||
|  |             cookie_is_new = False | ||||||
|  |         except KeyError: | ||||||
|  |             # No cookie, so create one. | ||||||
|  |             request.META["CSRF_COOKIE"] = _get_new_csrf_key() | ||||||
|  |             cookie_is_new = True | ||||||
|  |  | ||||||
|  |         if request.method == 'POST': | ||||||
|  |             if getattr(request, '_dont_enforce_csrf_checks', False): | ||||||
|  |                 # Mechanism to turn off CSRF checks for test suite.  It comes after | ||||||
|  |                 # the creation of CSRF cookies, so that everything else continues to | ||||||
|  |                 # work exactly the same (e.g. cookies are sent etc), but before the | ||||||
|  |                 # any branches that call reject() | ||||||
|  |                 return accept() | ||||||
|  |  | ||||||
|  |             if request.is_ajax(): | ||||||
|  |                 # .is_ajax() is based on the presence of X-Requested-With.  In | ||||||
|  |                 # the context of a browser, this can only be sent if using | ||||||
|  |                 # XmlHttpRequest.  Browsers implement careful policies for | ||||||
|  |                 # XmlHttpRequest: | ||||||
|  |                 # | ||||||
|  |                 #  * Normally, only same-domain requests are allowed. | ||||||
|  |                 # | ||||||
|  |                 #  * Some browsers (e.g. Firefox 3.5 and later) relax this | ||||||
|  |                 #    carefully: | ||||||
|  |                 # | ||||||
|  |                 #    * if it is a 'simple' GET or POST request (which can | ||||||
|  |                 #      include no custom headers), it is allowed to be cross | ||||||
|  |                 #      domain.  These requests will not be recognized as AJAX. | ||||||
|  |                 # | ||||||
|  |                 #    * if a 'preflight' check with the server confirms that the | ||||||
|  |                 #      server is expecting and allows the request, cross domain | ||||||
|  |                 #      requests even with custom headers are allowed. These | ||||||
|  |                 #      requests will be recognized as AJAX, but can only get | ||||||
|  |                 #      through when the developer has specifically opted in to | ||||||
|  |                 #      allowing the cross-domain POST request. | ||||||
|  |                 # | ||||||
|  |                 # So in all cases, it is safe to allow these requests through. | ||||||
|  |                 return accept() | ||||||
|  |  | ||||||
|  |             if request.is_secure(): | ||||||
|  |                 # Strict referer checking for HTTPS | ||||||
|  |                 referer = request.META.get('HTTP_REFERER') | ||||||
|  |                 if referer is None: | ||||||
|  |                     return reject("Referer checking failed - no Referer.") | ||||||
|  |  | ||||||
|  |                 # The following check ensures that the referer is HTTPS, | ||||||
|  |                 # the domains match and the ports match.  This might be too strict. | ||||||
|  |                 good_referer = 'https://%s/' % request.get_host() | ||||||
|  |                 if not referer.startswith(good_referer): | ||||||
|  |                     return reject("Referer checking failed - %s does not match %s." % | ||||||
|  |                                   (referer, good_referer)) | ||||||
|  |  | ||||||
|  |             # If the user didn't already have a CSRF key, then accept the | ||||||
|  |             # session key for the middleware token, so CSRF protection isn't lost | ||||||
|  |             # for the period between upgrading to CSRF cookes to the first time | ||||||
|  |             # each user comes back to the site to receive one. | ||||||
|  |             if cookie_is_new: | ||||||
|  |                 try: | ||||||
|  |                     session_id = request.COOKIES[settings.SESSION_COOKIE_NAME] | ||||||
|  |                     csrf_token = _make_legacy_session_token(session_id) | ||||||
|  |                 except KeyError: | ||||||
|  |                     # No CSRF cookie and no session cookie. For POST requests, | ||||||
|  |                     # we insist on a CSRF cookie, and in this way we can avoid | ||||||
|  |                     # all CSRF attacks, including login CSRF. | ||||||
|  |                     return reject("No CSRF cookie.") | ||||||
|  |             else: | ||||||
|  |                 csrf_token = request.META["CSRF_COOKIE"] | ||||||
|  |  | ||||||
|  |             # check incoming token | ||||||
|  |             request_csrf_token = request.POST.get('csrfmiddlewaretoken', None) | ||||||
|  |             if request_csrf_token != csrf_token: | ||||||
|  |                 return reject("CSRF token missing or incorrect.") | ||||||
|  |  | ||||||
|  |         return accept() | ||||||
|  |  | ||||||
|  |     def process_response(self, request, response): | ||||||
|  |         if getattr(response, 'csrf_processing_done', False): | ||||||
|  |             return response | ||||||
|  |  | ||||||
|  |         # If CSRF_COOKIE is unset, then CsrfViewMiddleware.process_view was | ||||||
|  |         # never called, probaby because a request middleware returned a response | ||||||
|  |         # (for example, contrib.auth redirecting to a login page). | ||||||
|  |         if request.META.get("CSRF_COOKIE") is None: | ||||||
|  |             return response | ||||||
|  |  | ||||||
|  |         if not request.META.get("CSRF_COOKIE_USED", False): | ||||||
|  |             return response | ||||||
|  |  | ||||||
|  |         # Set the CSRF cookie even if it's already set, so we renew the expiry timer. | ||||||
|  |         response.set_cookie(settings.CSRF_COOKIE_NAME, | ||||||
|  |                 request.META["CSRF_COOKIE"], max_age = 60 * 60 * 24 * 7 * 52, | ||||||
|  |                 domain=settings.CSRF_COOKIE_DOMAIN) | ||||||
|  |         # Content varies with the CSRF cookie, so set the Vary header. | ||||||
|  |         patch_vary_headers(response, ('Cookie',)) | ||||||
|  |         response.csrf_processing_done = True | ||||||
|  |         return response | ||||||
|  |  | ||||||
|  | class CsrfResponseMiddleware(object): | ||||||
|  |     """ | ||||||
|  |     DEPRECATED | ||||||
|  |     Middleware that post-processes a response to add a csrfmiddlewaretoken. | ||||||
|  |  | ||||||
|  |     This exists for backwards compatibility and as an interim measure until | ||||||
|  |     applications are converted to using use the csrf_token template tag | ||||||
|  |     instead. It will be removed in Django 1.4. | ||||||
|  |     """ | ||||||
|  |     def __init__(self): | ||||||
|  |         import warnings | ||||||
|  |         warnings.warn( | ||||||
|  |             "CsrfResponseMiddleware and CsrfMiddleware are deprecated; use CsrfViewMiddleware and the template tag instead (see CSRF documentation).", | ||||||
|  |             PendingDeprecationWarning | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |     def process_response(self, request, response): | ||||||
|  |         if getattr(response, 'csrf_exempt', False): | ||||||
|  |             return response | ||||||
|  |  | ||||||
|  |         if response['Content-Type'].split(';')[0] in _HTML_TYPES: | ||||||
|  |             csrf_token = get_token(request) | ||||||
|  |             # If csrf_token is None, we have no token for this request, which probably | ||||||
|  |             # means that this is a response from a request middleware. | ||||||
|  |             if csrf_token is None: | ||||||
|  |                 return response | ||||||
|  |  | ||||||
|  |             # ensure we don't add the 'id' attribute twice (HTML validity) | ||||||
|  |             idattributes = itertools.chain(("id='csrfmiddlewaretoken'",), | ||||||
|  |                                            itertools.repeat('')) | ||||||
|  |             def add_csrf_field(match): | ||||||
|  |                 """Returns the matched <form> tag plus the added <input> element""" | ||||||
|  |                 return mark_safe(match.group() + "<div style='display:none;'>" + \ | ||||||
|  |                 "<input type='hidden' " + idattributes.next() + \ | ||||||
|  |                 " name='csrfmiddlewaretoken' value='" + csrf_token + \ | ||||||
|  |                 "' /></div>") | ||||||
|  |  | ||||||
|  |             # Modify any POST forms | ||||||
|  |             response.content, n = _POST_FORM_RE.subn(add_csrf_field, response.content) | ||||||
|  |             if n > 0: | ||||||
|  |                 # Content varies with the CSRF cookie, so set the Vary header. | ||||||
|  |                 patch_vary_headers(response, ('Cookie',)) | ||||||
|  |  | ||||||
|  |                 # Since the content has been modified, any Etag will now be | ||||||
|  |                 # incorrect.  We could recalculate, but only if we assume that               | ||||||
|  |                 # the Etag was set by CommonMiddleware. The safest thing is just | ||||||
|  |                 # to delete. See bug #9163 | ||||||
|  |                 del response['ETag'] | ||||||
|  |         return response | ||||||
|  |  | ||||||
|  | class CsrfMiddleware(object): | ||||||
|  |     """ | ||||||
|  |     Django middleware that adds protection against Cross Site | ||||||
|  |     Request Forgeries by adding hidden form fields to POST forms and | ||||||
|  |     checking requests for the correct value. | ||||||
|  |  | ||||||
|  |     CsrfMiddleware uses two middleware, CsrfViewMiddleware and | ||||||
|  |     CsrfResponseMiddleware, which can be used independently.  It is recommended | ||||||
|  |     to use only CsrfViewMiddleware and use the csrf_token template tag in | ||||||
|  |     templates for inserting the token. | ||||||
|  |     """ | ||||||
|  |     # We can't just inherit from CsrfViewMiddleware and CsrfResponseMiddleware | ||||||
|  |     # because both have process_response methods. | ||||||
|  |     def __init__(self): | ||||||
|  |         self.response_middleware = CsrfResponseMiddleware() | ||||||
|  |         self.view_middleware = CsrfViewMiddleware() | ||||||
|  |  | ||||||
|  |     def process_response(self, request, resp): | ||||||
|  |         # We must do the response post-processing first, because that calls | ||||||
|  |         # get_token(), which triggers a flag saying that the CSRF cookie needs | ||||||
|  |         # to be sent (done in CsrfViewMiddleware.process_response) | ||||||
|  |         resp2 = self.response_middleware.process_response(request, resp) | ||||||
|  |         return self.view_middleware.process_response(request, resp2) | ||||||
|  |  | ||||||
|  |     def process_view(self, request, callback, callback_args, callback_kwargs): | ||||||
|  |         return self.view_middleware.process_view(request, callback, callback_args, | ||||||
|  |                                                  callback_kwargs) | ||||||
|  |  | ||||||
| @@ -6,7 +6,7 @@ _standard_context_processors = None | |||||||
| # We need the CSRF processor no matter what the user has in their settings, | # We need the CSRF processor no matter what the user has in their settings, | ||||||
| # because otherwise it is a security vulnerability, and we can't afford to leave | # because otherwise it is a security vulnerability, and we can't afford to leave | ||||||
| # this to human error or failure to read migration instructions. | # this to human error or failure to read migration instructions. | ||||||
| _builtin_context_processors =  ('django.contrib.csrf.context_processors.csrf',) | _builtin_context_processors =  ('django.core.context_processors.csrf',) | ||||||
|  |  | ||||||
| class ContextPopException(Exception): | class ContextPopException(Exception): | ||||||
|     "pop() has been called more times than push()" |     "pop() has been called more times than push()" | ||||||
|   | |||||||
							
								
								
									
										47
									
								
								django/views/decorators/csrf.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								django/views/decorators/csrf.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | |||||||
|  | from django.middleware.csrf import CsrfViewMiddleware | ||||||
|  | from django.utils.decorators import decorator_from_middleware | ||||||
|  | try: | ||||||
|  |     from functools import wraps | ||||||
|  | except ImportError: | ||||||
|  |     from django.utils.functional import wraps  # Python 2.3, 2.4 fallback. | ||||||
|  |  | ||||||
|  | csrf_protect = decorator_from_middleware(CsrfViewMiddleware) | ||||||
|  | csrf_protect.__name__ = "csrf_protect" | ||||||
|  | csrf_protect.__doc__ = """ | ||||||
|  | This decorator adds CSRF protection in exactly the same way as | ||||||
|  | CsrfViewMiddleware, but it can be used on a per view basis.  Using both, or | ||||||
|  | using the decorator multiple times, is harmless and efficient. | ||||||
|  | """ | ||||||
|  |  | ||||||
|  | def csrf_response_exempt(view_func): | ||||||
|  |     """ | ||||||
|  |     Modifies a view function so that its response is exempt | ||||||
|  |     from the post-processing of the CSRF middleware. | ||||||
|  |     """ | ||||||
|  |     def wrapped_view(*args, **kwargs): | ||||||
|  |         resp = view_func(*args, **kwargs) | ||||||
|  |         resp.csrf_exempt = True | ||||||
|  |         return resp | ||||||
|  |     return wraps(view_func)(wrapped_view) | ||||||
|  |  | ||||||
|  | def csrf_view_exempt(view_func): | ||||||
|  |     """ | ||||||
|  |     Marks a view function as being exempt from CSRF view protection. | ||||||
|  |     """ | ||||||
|  |     # We could just do view_func.csrf_exempt = True, but decorators | ||||||
|  |     # are nicer if they don't have side-effects, so we return a new | ||||||
|  |     # function. | ||||||
|  |     def wrapped_view(*args, **kwargs): | ||||||
|  |         return view_func(*args, **kwargs) | ||||||
|  |     wrapped_view.csrf_exempt = True | ||||||
|  |     return wraps(view_func)(wrapped_view) | ||||||
|  |  | ||||||
|  | def csrf_exempt(view_func): | ||||||
|  |     """ | ||||||
|  |     Marks a view function as being exempt from the CSRF checks | ||||||
|  |     and post processing. | ||||||
|  |  | ||||||
|  |     This is the same as using both the csrf_view_exempt and | ||||||
|  |     csrf_response_exempt decorators. | ||||||
|  |     """ | ||||||
|  |     return csrf_response_exempt(csrf_view_exempt(view_func)) | ||||||
| @@ -19,6 +19,9 @@ their deprecation, as per the :ref:`Django deprecation policy | |||||||
|           token.  ``CsrfMiddleware``, which combines ``CsrfResponseMiddleware`` |           token.  ``CsrfMiddleware``, which combines ``CsrfResponseMiddleware`` | ||||||
|           and ``CsrfViewMiddleware``, is also deprecated. |           and ``CsrfViewMiddleware``, is also deprecated. | ||||||
|  |  | ||||||
|  |         * The old imports for CSRF functionality (``django.contrib.csrf.*``), | ||||||
|  |           which moved to core in 1.2, will be removed. | ||||||
|  |  | ||||||
|     * 2.0 |     * 2.0 | ||||||
|         * ``django.views.defaults.shortcut()``. This function has been moved |         * ``django.views.defaults.shortcut()``. This function has been moved | ||||||
|           to ``django.contrib.contenttypes.views.shortcut()`` as part of the |           to ``django.contrib.contenttypes.views.shortcut()`` as part of the | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ | |||||||
| Cross Site Request Forgery protection | Cross Site Request Forgery protection | ||||||
| ===================================== | ===================================== | ||||||
|  |  | ||||||
| .. module:: django.contrib.csrf | .. module:: django.middleware.csrf | ||||||
|    :synopsis: Protects against Cross Site Request Forgeries |    :synopsis: Protects against Cross Site Request Forgeries | ||||||
|  |  | ||||||
| The CSRF middleware and template tag provides easy-to-use protection against | The CSRF middleware and template tag provides easy-to-use protection against | ||||||
| @@ -37,13 +37,13 @@ How to use it | |||||||
| To enable CSRF protection for your views, follow these steps: | To enable CSRF protection for your views, follow these steps: | ||||||
|  |  | ||||||
|     1. Add the middleware |     1. Add the middleware | ||||||
|        ``'django.contrib.csrf.middleware.CsrfViewMiddleware'`` to your list of |        ``'django.middleware.csrf.CsrfViewMiddleware'`` to your list of | ||||||
|        middleware classes, :setting:`MIDDLEWARE_CLASSES`.  (It should come |        middleware classes, :setting:`MIDDLEWARE_CLASSES`.  (It should come | ||||||
|        before ``CsrfResponseMiddleware`` if that is being used, and before any |        before ``CsrfResponseMiddleware`` if that is being used, and before any | ||||||
|        view middleware that assume that CSRF attacks have been dealt with.) |        view middleware that assume that CSRF attacks have been dealt with.) | ||||||
|  |  | ||||||
|        Alternatively, you can use the decorator |        Alternatively, you can use the decorator | ||||||
|        ``django.contrib.csrf.decorators.csrf_protect`` on particular views you |        ``django.views.decorators.csrf.csrf_protect`` on particular views you | ||||||
|        want to protect.  This is **not recommended** by itself, since if you |        want to protect.  This is **not recommended** by itself, since if you | ||||||
|        forget to use it, you will have a security hole.  The 'belt and braces' |        forget to use it, you will have a security hole.  The 'belt and braces' | ||||||
|        strategy of using both is fine, and will incur minimal overhead. |        strategy of using both is fine, and will incur minimal overhead. | ||||||
| @@ -57,11 +57,11 @@ To enable CSRF protection for your views, follow these steps: | |||||||
|        that would cause the CSRF token to be leaked, leading to a vulnerability. |        that would cause the CSRF token to be leaked, leading to a vulnerability. | ||||||
|  |  | ||||||
|     3. In the corresponding view functions, ensure that the |     3. In the corresponding view functions, ensure that the | ||||||
|        ``'django.contrib.csrf.context_processors.csrf'`` context processor is |        ``'django.core.context_processors.csrf'`` context processor is | ||||||
|        being used. Usually, this can be done in one of two ways: |        being used. Usually, this can be done in one of two ways: | ||||||
|  |  | ||||||
|        1. Use RequestContext, which always uses |        1. Use RequestContext, which always uses | ||||||
|           ``'django.contrib.csrf.context_processors.csrf'`` (no matter what your |           ``'django.core.context_processors.csrf'`` (no matter what your | ||||||
|           TEMPLATE_CONTEXT_PROCESSORS setting).  If you are using |           TEMPLATE_CONTEXT_PROCESSORS setting).  If you are using | ||||||
|           generic views or contrib apps, you are covered already, since these |           generic views or contrib apps, you are covered already, since these | ||||||
|           apps use RequestContext throughout. |           apps use RequestContext throughout. | ||||||
| @@ -69,7 +69,7 @@ To enable CSRF protection for your views, follow these steps: | |||||||
|        2. Manually import and use the processor to generate the CSRF token and |        2. Manually import and use the processor to generate the CSRF token and | ||||||
|           add it to the template context. e.g.:: |           add it to the template context. e.g.:: | ||||||
|  |  | ||||||
|               from django.contrib.csrf.context_processors import csrf |               from django.core.context_processors import csrf | ||||||
|               from django.shortcuts import render_to_response |               from django.shortcuts import render_to_response | ||||||
|  |  | ||||||
|               def my_view(request): |               def my_view(request): | ||||||
| @@ -96,7 +96,7 @@ as ``CsrfResponseMiddleware``, and it can be used by following these steps: | |||||||
|  |  | ||||||
|     1. Follow step 1 above to install ``CsrfViewMiddleware``. |     1. Follow step 1 above to install ``CsrfViewMiddleware``. | ||||||
|  |  | ||||||
|     2. Add ``'django.contrib.csrf.middleware.CsrfResponseMiddleware'`` to your |     2. Add ``'django.middleware.csrf.CsrfResponseMiddleware'`` to your | ||||||
|        :setting:`MIDDLEWARE_CLASSES` setting. |        :setting:`MIDDLEWARE_CLASSES` setting. | ||||||
|  |  | ||||||
|        ``CsrfResponseMiddleware`` needs to process the response before things |        ``CsrfResponseMiddleware`` needs to process the response before things | ||||||
| @@ -140,6 +140,28 @@ enabled any CSRF protection.  This section outlines the steps necessary for a | |||||||
| smooth upgrade, without having to fix all the applications to use the new | smooth upgrade, without having to fix all the applications to use the new | ||||||
| template tag method immediately. | template tag method immediately. | ||||||
|  |  | ||||||
|  | First of all, the location of the middleware and related functions have | ||||||
|  | changed.  There are backwards compatible stub files so that old imports will | ||||||
|  | continue to work for now, but they are deprecated and will be removed in Django | ||||||
|  | 1.4.  The following changes have been made: | ||||||
|  |  | ||||||
|  |  * Middleware have been moved to ``django.middleware.csrf`` | ||||||
|  |  * Decorators have been moved to ``django.views.decorators.csrf`` | ||||||
|  |  | ||||||
|  | ======================================================  ============================================== | ||||||
|  |    Old                                                       New | ||||||
|  | ======================================================  ============================================== | ||||||
|  | django.contrib.csrf.middleware.CsrfMiddleware           django.middleware.csrf.CsrfMiddleware | ||||||
|  | django.contrib.csrf.middleware.CsrfViewMiddleware       django.middleware.csrf.CsrfViewMiddleware | ||||||
|  | django.contrib.csrf.middleware.CsrfResponseMiddleware   django.middleware.csrf.CsrfResponseMiddleware | ||||||
|  | django.contrib.csrf.middleware.csrf_exempt              django.views.decorators.csrf_exempt | ||||||
|  | django.contrib.csrf.middleware.csrf_view_exempt         django.views.decorators.csrf_view_exempt | ||||||
|  | django.contrib.csrf.middleware.csrf_response_exempt     django.views.decorators.csrf_response_exempt | ||||||
|  | ======================================================  ============================================== | ||||||
|  |  | ||||||
|  | You should update any imports, and also the paths in your | ||||||
|  | :setting:`MIDDLEWARE_CLASSES`. | ||||||
|  |  | ||||||
| If you have ``CsrfMiddleware`` in your :setting:`MIDDLEWARE_CLASSES`, you will now | If you have ``CsrfMiddleware`` in your :setting:`MIDDLEWARE_CLASSES`, you will now | ||||||
| have a working installation with CSRF protection.  It is recommended at this | have a working installation with CSRF protection.  It is recommended at this | ||||||
| point that you replace ``CsrfMiddleware`` with its two components, | point that you replace ``CsrfMiddleware`` with its two components, | ||||||
| @@ -186,9 +208,9 @@ Exceptions | |||||||
|  |  | ||||||
| To manually exclude a view function from being handled by either of the two CSRF | To manually exclude a view function from being handled by either of the two CSRF | ||||||
| middleware, you can use the ``csrf_exempt`` decorator, found in the | middleware, you can use the ``csrf_exempt`` decorator, found in the | ||||||
| ``django.contrib.csrf.middleware`` module. For example:: | ``django.views.decorators.csrf`` module. For example:: | ||||||
|  |  | ||||||
|     from django.contrib.csrf.middleware import csrf_exempt |     from django.views.decorators.csrf import csrf_exempt | ||||||
|  |  | ||||||
|     def my_view(request): |     def my_view(request): | ||||||
|         return HttpResponse('Hello world') |         return HttpResponse('Hello world') | ||||||
| @@ -246,7 +268,7 @@ The CSRF protection is based on the following things: | |||||||
|  |  | ||||||
|    This cookie is set by ``CsrfViewMiddleware``.  It is meant to be permanent, |    This cookie is set by ``CsrfViewMiddleware``.  It is meant to be permanent, | ||||||
|    but since there is no way to set a cookie that never expires, it is sent with |    but since there is no way to set a cookie that never expires, it is sent with | ||||||
|    every response that has called ``django.contrib.csrf.middleware.get_token()`` |    every response that has called ``django.middleware.csrf.get_token()`` | ||||||
|    (the function used internally to retrieve the CSRF token). |    (the function used internally to retrieve the CSRF token). | ||||||
|  |  | ||||||
| 2. A hidden form field with the name 'csrfmiddlewaretoken' present in all | 2. A hidden form field with the name 'csrfmiddlewaretoken' present in all | ||||||
| @@ -352,7 +374,7 @@ If you are using ``CsrfResponseMiddleware`` and your app creates HTML pages and | |||||||
| forms in some unusual way, (e.g.  it sends fragments of HTML in JavaScript | forms in some unusual way, (e.g.  it sends fragments of HTML in JavaScript | ||||||
| document.write statements) you might bypass the filter that adds the hidden | document.write statements) you might bypass the filter that adds the hidden | ||||||
| field to the form, in which case form submission will always fail.  You should | field to the form, in which case form submission will always fail.  You should | ||||||
| use the template tag or :meth:`django.contrib.csrf.middleware.get_token` to get | use the template tag or :meth:`django.middleware.csrf.get_token` to get | ||||||
| the CSRF token and ensure it is included when your form is submitted. | the CSRF token and ensure it is included when your form is submitted. | ||||||
|  |  | ||||||
| Contrib and reusable apps | Contrib and reusable apps | ||||||
|   | |||||||
| @@ -165,11 +165,11 @@ every incoming ``HttpRequest`` object. See :ref:`Authentication in Web requests | |||||||
| CSRF protection middleware | CSRF protection middleware | ||||||
| -------------------------- | -------------------------- | ||||||
|  |  | ||||||
| .. module:: django.contrib.csrf.middleware | .. module:: django.middleware.csrf | ||||||
|    :synopsis: Middleware adding protection against Cross Site Request |    :synopsis: Middleware adding protection against Cross Site Request | ||||||
|               Forgeries. |               Forgeries. | ||||||
|  |  | ||||||
| .. class:: django.contrib.csrf.middleware.CsrfMiddleware | .. class:: django.middleware.csrf.CsrfMiddleware | ||||||
|  |  | ||||||
| .. versionadded:: 1.0 | .. versionadded:: 1.0 | ||||||
|  |  | ||||||
|   | |||||||
| @@ -171,7 +171,7 @@ accepted by accepted by a view served from another subdomain. | |||||||
| CSRF_FAILURE_VIEW | CSRF_FAILURE_VIEW | ||||||
| ----------------- | ----------------- | ||||||
|  |  | ||||||
| Default: ``'django.contrib.csrf.views.csrf_failure'`` | Default: ``'django.views.csrf.csrf_failure'`` | ||||||
|  |  | ||||||
| A dotted path to the view function to be used when an incoming request | A dotted path to the view function to be used when an incoming request | ||||||
| is rejected by the CSRF protection.  The function should have this signature:: | is rejected by the CSRF protection.  The function should have this signature:: | ||||||
| @@ -789,7 +789,7 @@ Default:: | |||||||
|  |  | ||||||
|     ('django.middleware.common.CommonMiddleware', |     ('django.middleware.common.CommonMiddleware', | ||||||
|      'django.contrib.sessions.middleware.SessionMiddleware', |      'django.contrib.sessions.middleware.SessionMiddleware', | ||||||
|      'django.contrib.csrf.middleware.CsrfViewMiddleware', |      'django.middleware.csrf.CsrfViewMiddleware', | ||||||
|      'django.contrib.auth.middleware.AuthenticationMiddleware',) |      'django.contrib.auth.middleware.AuthenticationMiddleware',) | ||||||
|  |  | ||||||
| A tuple of middleware classes to use. See :ref:`topics-http-middleware`. | A tuple of middleware classes to use. See :ref:`topics-http-middleware`. | ||||||
|   | |||||||
| @@ -315,7 +315,7 @@ and return a dictionary of items to be merged into the context. By default, | |||||||
|  |  | ||||||
| .. versionadded:: 1.2 | .. versionadded:: 1.2 | ||||||
|    In addition to these, ``RequestContext`` always uses |    In addition to these, ``RequestContext`` always uses | ||||||
|    ``'django.contrib.csrf.context_processors.csrf'``.  This is a security |    ``'django.core.context_processors.csrf'``.  This is a security | ||||||
|    related context processor required by the admin and other contrib apps, and, |    related context processor required by the admin and other contrib apps, and, | ||||||
|    in case of accidental misconfiguration, it is deliberately hardcoded in and |    in case of accidental misconfiguration, it is deliberately hardcoded in and | ||||||
|    cannot be turned off by the :setting:`TEMPLATE_CONTEXT_PROCESSORS` setting. |    cannot be turned off by the :setting:`TEMPLATE_CONTEXT_PROCESSORS` setting. | ||||||
| @@ -411,8 +411,8 @@ If :setting:`TEMPLATE_CONTEXT_PROCESSORS` contains this processor, every | |||||||
| ``RequestContext`` will contain a variable ``MEDIA_URL``, providing the | ``RequestContext`` will contain a variable ``MEDIA_URL``, providing the | ||||||
| value of the :setting:`MEDIA_URL` setting. | value of the :setting:`MEDIA_URL` setting. | ||||||
|  |  | ||||||
| django.contrib.csrf.context_processors.csrf | django.core.context_processors.csrf | ||||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |  | ||||||
| .. versionadded:: 1.2 | .. versionadded:: 1.2 | ||||||
|  |  | ||||||
|   | |||||||
| @@ -18,6 +18,9 @@ changes that developers must be aware of: | |||||||
|    POST requests need to be written to work with the middleware.  Instructions |    POST requests need to be written to work with the middleware.  Instructions | ||||||
|    on how to do this are found in the CSRF docs. |    on how to do this are found in the CSRF docs. | ||||||
|  |  | ||||||
|  |  * All of the CSRF has moved from contrib to core (with backwards compatible | ||||||
|  |    imports in the old locations, which are deprecated). | ||||||
|  |  | ||||||
| LazyObject | LazyObject | ||||||
| ---------- | ---------- | ||||||
|  |  | ||||||
|   | |||||||
| @@ -29,7 +29,7 @@ created by :djadmin:`django-admin.py startproject <startproject>`:: | |||||||
|     MIDDLEWARE_CLASSES = ( |     MIDDLEWARE_CLASSES = ( | ||||||
|         'django.middleware.common.CommonMiddleware', |         'django.middleware.common.CommonMiddleware', | ||||||
|         'django.contrib.sessions.middleware.SessionMiddleware', |         'django.contrib.sessions.middleware.SessionMiddleware', | ||||||
|         'django.contrib.csrf.middleware.CsrfViewMiddleware', |         'django.middleware.csrf.CsrfViewMiddleware', | ||||||
|         'django.contrib.auth.middleware.AuthenticationMiddleware', |         'django.contrib.auth.middleware.AuthenticationMiddleware', | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										0
									
								
								tests/regressiontests/csrf_tests/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								tests/regressiontests/csrf_tests/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -2,8 +2,9 @@ | |||||||
| 
 | 
 | ||||||
| from django.test import TestCase | from django.test import TestCase | ||||||
| from django.http import HttpRequest, HttpResponse | from django.http import HttpRequest, HttpResponse | ||||||
| from django.contrib.csrf.middleware import CsrfMiddleware, CsrfViewMiddleware, csrf_exempt | from django.middleware.csrf import CsrfMiddleware, CsrfViewMiddleware | ||||||
| from django.contrib.csrf.context_processors import csrf | from django.views.decorators.csrf import csrf_exempt | ||||||
|  | from django.core.context_processors import csrf | ||||||
| from django.contrib.sessions.middleware import SessionMiddleware | from django.contrib.sessions.middleware import SessionMiddleware | ||||||
| from django.utils.importlib import import_module | from django.utils.importlib import import_module | ||||||
| from django.conf import settings | from django.conf import settings | ||||||
		Reference in New Issue
	
	Block a user