Ticket #9977: csrf_template_tag_r11477_1.diff

File csrf_template_tag_r11477_1.diff, 77.0 KB (added by Luke Plant, 15 years ago)

Mainly updated tutorials, and update to trunk

  • AUTHORS

    diff -r 1b4df7524b7c AUTHORS
    a b  
    468468    Gasper Zejn <zejn@kiberpipa.org>
    469469    Jarek Zgoda <jarek.zgoda@gmail.com>
    470470    Cheng Zhang
     471    Glenn
     472    bthomas
    471473
    472474A big THANK YOU goes to:
    473475
  • django/conf/global_settings.py

    diff -r 1b4df7524b7c django/conf/global_settings.py
    a b  
    165165    'django.core.context_processors.debug',
    166166    'django.core.context_processors.i18n',
    167167    'django.core.context_processors.media',
     168    'django.contrib.csrf.context_processors.csrf',
    168169#    'django.core.context_processors.request',
    169170)
    170171
     
    300301MIDDLEWARE_CLASSES = (
    301302    'django.middleware.common.CommonMiddleware',
    302303    'django.contrib.sessions.middleware.SessionMiddleware',
     304    'django.contrib.csrf.middleware.CsrfViewMiddleware',
    303305    'django.contrib.auth.middleware.AuthenticationMiddleware',
    304306#     'django.middleware.http.ConditionalGetMiddleware',
    305307#     'django.middleware.gzip.GZipMiddleware',
     
    374376# The number of days a password reset link is valid for
    375377PASSWORD_RESET_TIMEOUT_DAYS = 3
    376378
     379########
     380# CSRF #
     381########
     382
     383# Dotted path to callable to be used as view when a request is
     384# rejected by the CSRF middleware.
     385CSRF_FAILURE_VIEW = 'django.contrib.csrf.views.csrf_failure'
     386
     387# Name and domain for CSRF cookie.
     388CSRF_COOKIE_NAME = 'csrftoken'
     389CSRF_COOKIE_DOMAIN = None
     390
    377391###########
    378392# TESTING #
    379393###########
  • django/conf/project_template/settings.py

    diff -r 1b4df7524b7c django/conf/project_template/settings.py
    a b  
    6060MIDDLEWARE_CLASSES = (
    6161    'django.middleware.common.CommonMiddleware',
    6262    'django.contrib.sessions.middleware.SessionMiddleware',
     63    'django.contrib.csrf.middleware.CsrfViewMiddleware',
    6364    'django.contrib.auth.middleware.AuthenticationMiddleware',
    6465)
    6566
     
    7475INSTALLED_APPS = (
    7576    'django.contrib.auth',
    7677    'django.contrib.contenttypes',
     78    'django.contrib.csrf',
    7779    'django.contrib.sessions',
    7880    'django.contrib.sites',
    7981)
  • django/contrib/admin/sites.py

    diff -r 1b4df7524b7c django/contrib/admin/sites.py
    a b  
    33from django.contrib.admin import ModelAdmin
    44from django.contrib.admin import actions
    55from django.contrib.auth import authenticate, login
     6from django.contrib.csrf.middleware import csrf_response_exempt
    67from django.db.models.base import ModelBase
    78from django.core.exceptions import ImproperlyConfigured
    89from django.core.urlresolvers import reverse
     
    154155            raise ImproperlyConfigured("Put 'django.contrib.admin' in your INSTALLED_APPS setting in order to use the admin application.")
    155156        if not ContentType._meta.installed:
    156157            raise ImproperlyConfigured("Put 'django.contrib.contenttypes' in your INSTALLED_APPS setting in order to use the admin application.")
     158        if 'django.contrib.csrf' not in settings.INSTALLED_APPS:
     159            raise ImproperlyConfigured("Put 'django.contrib.csrf' in your INSTALLED_APPS setting in order to use the admin application.")
    157160        if 'django.core.context_processors.auth' not in settings.TEMPLATE_CONTEXT_PROCESSORS:
    158161            raise ImproperlyConfigured("Put 'django.core.context_processors.auth' in your TEMPLATE_CONTEXT_PROCESSORS setting in order to use the admin application.")
     162        if 'django.contrib.csrf.context_processors.csrf' not in settings.TEMPLATE_CONTEXT_PROCESSORS:
     163            raise ImproperlyConfigured("Put 'django.contrib.csrf.context_processors.csrf' in your TEMPLATE_CONTEXT_PROCESSORS setting in order to use the admin application.")
    159164
    160165    def admin_view(self, view, cacheable=False):
    161166        """
     
    186191            return view(request, *args, **kwargs)
    187192        if not cacheable:
    188193            inner = never_cache(inner)
     194        inner = csrf_response_exempt(inner)
    189195        return update_wrapper(inner, view)
    190196
    191197    def get_urls(self):
  • django/contrib/admin/templates/admin/auth/user/change_password.html

    diff -r 1b4df7524b7c django/contrib/admin/templates/admin/auth/user/change_password.html
    a b  
    11{% extends "admin/base_site.html" %}
    2 {% load i18n admin_modify adminmedia %}
     2{% load i18n admin_modify adminmedia csrf %}
    33{% block extrahead %}{{ block.super }}
    44<script type="text/javascript" src="../../../../jsi18n/"></script>
    55{% endblock %}
     
    1515</div>
    1616{% endif %}{% endblock %}
    1717{% block content %}<div id="content-main">
    18 <form action="{{ form_url }}" method="post" id="{{ opts.module_name }}_form">{% block form_top %}{% endblock %}
     18<form action="{{ form_url }}" method="post" id="{{ opts.module_name }}_form">{% csrf_token %}{% block form_top %}{% endblock %}
    1919<div>
    2020{% if is_popup %}<input type="hidden" name="_popup" value="1" />{% endif %}
    2121{% if form.errors %}
  • django/contrib/admin/templates/admin/change_form.html

    diff -r 1b4df7524b7c django/contrib/admin/templates/admin/change_form.html
    a b  
    11{% extends "admin/base_site.html" %}
    2 {% load i18n admin_modify adminmedia %}
     2{% load i18n admin_modify adminmedia csrf %}
    33
    44{% block extrahead %}{{ block.super }}
    55<script type="text/javascript" src="../../../jsi18n/"></script>
     
    2929  </ul>
    3030{% endif %}{% endif %}
    3131{% endblock %}
    32 <form {% if has_file_field %}enctype="multipart/form-data" {% endif %}action="{{ form_url }}" method="post" id="{{ opts.module_name }}_form">{% block form_top %}{% endblock %}
     32<form {% if has_file_field %}enctype="multipart/form-data" {% endif %}action="{{ form_url }}" method="post" id="{{ opts.module_name }}_form">{% csrf_token %}{% block form_top %}{% endblock %}
    3333<div>
    3434{% if is_popup %}<input type="hidden" name="_popup" value="1" />{% endif %}
    3535{% if save_on_top %}{% submit_row %}{% endif %}
  • django/contrib/admin/templates/admin/change_list.html

    diff -r 1b4df7524b7c django/contrib/admin/templates/admin/change_list.html
    a b  
    11{% extends "admin/base_site.html" %}
    2 {% load adminmedia admin_list i18n %}
     2{% load adminmedia admin_list i18n csrf %}
    33
    44{% block extrastyle %}
    55  {{ block.super }}
     
    6868        {% endif %}
    6969      {% endblock %}
    7070     
    71       <form action="" method="post"{% if cl.formset.is_multipart %} enctype="multipart/form-data"{% endif %}>
     71      <form action="" method="post"{% if cl.formset.is_multipart %} enctype="multipart/form-data"{% endif %}>{% csrf_token %}
    7272      {% if cl.formset %}
    7373        {{ cl.formset.management_form }}
    7474      {% endif %}
  • django/contrib/admin/templates/admin/delete_confirmation.html

    diff -r 1b4df7524b7c django/contrib/admin/templates/admin/delete_confirmation.html
    a b  
    11{% extends "admin/base_site.html" %}
    2 {% load i18n %}
     2{% load i18n csrf %}
    33
    44{% block breadcrumbs %}
    55<div class="breadcrumbs">
     
    2222{% else %}
    2323    <p>{% blocktrans with object as escaped_object %}Are you sure you want to delete the {{ object_name }} "{{ escaped_object }}"? All of the following related items will be deleted:{% endblocktrans %}</p>
    2424    <ul>{{ deleted_objects|unordered_list }}</ul>
    25     <form action="" method="post">
     25    <form action="" method="post">{% csrf_token %}
    2626    <div>
    2727    <input type="hidden" name="post" value="yes" />
    2828    <input type="submit" value="{% trans "Yes, I'm sure" %}" />
  • django/contrib/admin/templates/admin/delete_selected_confirmation.html

    diff -r 1b4df7524b7c django/contrib/admin/templates/admin/delete_selected_confirmation.html
    a b  
    11{% extends "admin/base_site.html" %}
    2 {% load i18n %}
     2{% load i18n csrf %}
    33
    44{% block breadcrumbs %}
    55<div class="breadcrumbs">
     
    2323    {% for deleteable_object in deletable_objects %}
    2424        <ul>{{ deleteable_object|unordered_list }}</ul>
    2525    {% endfor %}
    26     <form action="" method="post">
     26    <form action="" method="post">{% csrf_token %}
    2727    <div>
    2828    {% for obj in queryset %}
    2929    <input type="hidden" name="{{ action_checkbox_name }}" value="{{ obj.pk }}" />
  • django/contrib/admin/templates/admin/login.html

    diff -r 1b4df7524b7c django/contrib/admin/templates/admin/login.html
    a b  
    11{% extends "admin/base_site.html" %}
    2 {% load i18n %}
     2{% load i18n csrf %}
    33
    44{% block extrastyle %}{% load adminmedia %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% admin_media_prefix %}css/login.css" />{% endblock %}
    55
     
    1414<p class="errornote">{{ error_message }}</p>
    1515{% endif %}
    1616<div id="content-main">
    17 <form action="{{ app_path }}" method="post" id="login-form">
     17<form action="{{ app_path }}" method="post" id="login-form">{% csrf_token %}
    1818  <div class="form-row">
    1919    <label for="id_username">{% trans 'Username:' %}</label> <input type="text" name="username" id="id_username" />
    2020  </div>
  • django/contrib/admin/templates/admin/template_validator.html

    diff -r 1b4df7524b7c django/contrib/admin/templates/admin/template_validator.html
    a b  
    11{% extends "admin/base_site.html" %}
    2 
     2{% load csrf %}
    33{% block content %}
    44
    55<div id="content-main">
    66
    7 <form action="" method="post">
     7<form action="" method="post">{% csrf_token %}
    88
    99{% if form.errors %}
    1010<p class="errornote">Your template had {{ form.errors|length }} error{{ form.errors|pluralize }}:</p>
  • django/contrib/admin/templates/registration/password_change_form.html

    diff -r 1b4df7524b7c django/contrib/admin/templates/registration/password_change_form.html
    a b  
    11{% extends "admin/base_site.html" %}
    2 {% load i18n %}
     2{% load i18n csrf %}
    33{% block userlinks %}{% url django-admindocs-docroot as docsroot %}{% if docsroot %}<a href="{{ docsroot }}">{% trans 'Documentation' %}</a> / {% endif %} {% trans 'Change password' %} / <a href="../logout/">{% trans 'Log out' %}</a>{% endblock %}
    44{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">{% trans 'Home' %}</a> &rsaquo; {% trans 'Password change' %}</div>{% endblock %}
    55
     
    1111
    1212<p>{% trans "Please enter your old password, for security's sake, and then enter your new password twice so we can verify you typed it in correctly." %}</p>
    1313
    14 <form action="" method="post">
     14<form action="" method="post">{% csrf_token %}
    1515
    1616{{ form.old_password.errors }}
    1717<p class="aligned wide"><label for="id_old_password">{% trans 'Old password:' %}</label>{{ form.old_password }}</p>
  • django/contrib/admin/templates/registration/password_reset_confirm.html

    diff -r 1b4df7524b7c django/contrib/admin/templates/registration/password_reset_confirm.html
    a b  
    11{% extends "admin/base_site.html" %}
    2 {% load i18n %}
     2{% load i18n csrf %}
    33
    44{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">{% trans 'Home' %}</a> &rsaquo; {% trans 'Password reset confirmation' %}</div>{% endblock %}
    55
     
    1313
    1414<p>{% trans "Please enter your new password twice so we can verify you typed it in correctly." %}</p>
    1515
    16 <form action="" method="post">
     16<form action="" method="post">{% csrf_token %}
    1717{{ form.new_password1.errors }}
    1818<p class="aligned wide"><label for="id_new_password1">{% trans 'New password:' %}</label>{{ form.new_password1 }}</p>
    1919{{ form.new_password2.errors }}
  • django/contrib/admin/templates/registration/password_reset_form.html

    diff -r 1b4df7524b7c django/contrib/admin/templates/registration/password_reset_form.html
    a b  
    11{% extends "admin/base_site.html" %}
    2 {% load i18n %}
     2{% load i18n csrf %}
    33
    44{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">{% trans 'Home' %}</a> &rsaquo; {% trans 'Password reset' %}</div>{% endblock %}
    55
     
    1111
    1212<p>{% trans "Forgotten your password? Enter your e-mail address below, and we'll e-mail instructions for setting a new one." %}</p>
    1313
    14 <form action="" method="post">
     14<form action="" method="post">{% csrf_token %}
    1515{{ form.email.errors }}
    1616<p><label for="id_email">{% trans 'E-mail address:' %}</label> {{ form.email }} <input type="submit" value="{% trans 'Reset my password' %}" /></p>
    1717</form>
  • django/contrib/comments/templates/comments/approve.html

    diff -r 1b4df7524b7c django/contrib/comments/templates/comments/approve.html
    a b  
    11{% extends "comments/base.html" %}
    2 {% load i18n %}
     2{% load i18n csrf %}
    33
    44{% block title %}{% trans "Approve a comment" %}{% endblock %}
    55
    66{% block content %}
    77  <h1>{% trans "Really make this comment public?" %}</h1>
    88  <blockquote>{{ comment|linebreaks }}</blockquote>
    9   <form action="." method="post">
     9  <form action="." method="post">{% csrf_token %}
    1010    {% if next %}<input type="hidden" name="next" value="{{ next }}" id="next" />{% endif %}
    1111    <p class="submit">
    1212      <input type="submit" name="submit" value="{% trans "Approve" %}" /> or <a href="{{ comment.get_absolute_url }}">cancel</a>
  • django/contrib/comments/templates/comments/delete.html

    diff -r 1b4df7524b7c django/contrib/comments/templates/comments/delete.html
    a b  
    11{% extends "comments/base.html" %}
    2 {% load i18n %}
     2{% load i18n csrf %}
    33
    44{% block title %}{% trans "Remove a comment" %}{% endblock %}
    55
    66{% block content %}
    77<h1>{% trans "Really remove this comment?" %}</h1>
    88  <blockquote>{{ comment|linebreaks }}</blockquote>
    9   <form action="." method="post">
     9  <form action="." method="post">{% csrf_token %}
    1010    {% if next %}<input type="hidden" name="next" value="{{ next }}" id="next" />{% endif %}
    1111    <p class="submit">
    1212    <input type="submit" name="submit" value="{% trans "Remove" %}" /> or <a href="{{ comment.get_absolute_url }}">cancel</a>
  • django/contrib/comments/templates/comments/flag.html

    diff -r 1b4df7524b7c django/contrib/comments/templates/comments/flag.html
    a b  
    11{% extends "comments/base.html" %}
    2 {% load i18n %}
     2{% load i18n csrf %}
    33
    44{% block title %}{% trans "Flag this comment" %}{% endblock %}
    55
    66{% block content %}
    77<h1>{% trans "Really flag this comment?" %}</h1>
    88  <blockquote>{{ comment|linebreaks }}</blockquote>
    9   <form action="." method="post">
     9  <form action="." method="post">{% csrf_token %}
    1010    {% if next %}<input type="hidden" name="next" value="{{ next }}" id="next" />{% endif %}
    1111    <p class="submit">
    1212    <input type="submit" name="submit" value="{% trans "Flag" %}" /> or <a href="{{ comment.get_absolute_url }}">cancel</a>
  • django/contrib/comments/templates/comments/form.html

    diff -r 1b4df7524b7c django/contrib/comments/templates/comments/form.html
    a b  
    1 {% load comments i18n %}
    2 <form action="{% comment_form_target %}" method="post">
     1{% load comments i18n csrf %}
     2<form action="{% comment_form_target %}" method="post">{% csrf_token %}
    33  {% if next %}<input type="hidden" name="next" value="{{ next }}" />{% endif %}
    44  {% for field in form %}
    55    {% if field.is_hidden %}
  • django/contrib/comments/templates/comments/moderation_queue.html

    diff -r 1b4df7524b7c django/contrib/comments/templates/comments/moderation_queue.html
    a b  
    11{% extends "admin/change_list.html" %}
    2 {% load adminmedia i18n %}
     2{% load adminmedia i18n csrf %}
    33
    44{% block title %}{% trans "Comment moderation queue" %}{% endblock %}
    55
     
    4444      {% for comment in comments %}
    4545        <tr class="{% cycle 'row1' 'row2' %}">
    4646          <td class="actions">
    47             <form action="{% url comments-approve comment.pk %}" method="post">
     47            <form action="{% url comments-approve comment.pk %}" method="post">{% csrf_token %}
    4848              <input type="hidden" name="next" value="{% url comments-moderation-queue %}" />
    4949              <input class="approve submit" type="submit" name="submit" value="{% trans "Approve" %}" />
    5050            </form>
    51             <form action="{% url comments-delete comment.pk %}" method="post">
     51            <form action="{% url comments-delete comment.pk %}" method="post">{% csrf_token %}
    5252              <input type="hidden" name="next" value="{% url comments-moderation-queue %}" />
    5353              <input class="remove submit" type="submit" name="submit" value="{% trans "Remove" %}" />
    5454            </form>
  • django/contrib/comments/templates/comments/preview.html

    diff -r 1b4df7524b7c django/contrib/comments/templates/comments/preview.html
    a b  
    11{% extends "comments/base.html" %}
    2 {% load i18n %}
     2{% load i18n csrf %}
    33
    44{% block title %}{% trans "Preview your comment" %}{% endblock %}
    55
    66{% block content %}
    77  {% load comments %}
    8   <form action="{% comment_form_target %}" method="post">
     8  <form action="{% comment_form_target %}" method="post">{% csrf_token %}
    99    {% if next %}<input type="hidden" name="next" value="{{ next }}" />{% endif %}
    1010    {% if form.errors %}
    1111    <h1>{% blocktrans count form.errors|length as counter %}Please correct the error below{% plural %}Please correct the errors below{% endblocktrans %}</h1>
  • new file django/contrib/csrf/context_processors.py

    diff -r 1b4df7524b7c django/contrib/csrf/context_processors.py
    - +  
     1from django.contrib.csrf.middleware import get_token
     2from django.utils.functional import lazy
     3
     4def csrf(request):
     5    """
     6    Context processor that provides a CSRF token, or the string
     7    'NOTNEEDED' if it is not needed
     8    """
     9    def _get_val():
     10        token = get_token(request)
     11        if token is None:
     12            # In order to be able to provide debugging info in the
     13            # case of misconfiguration, we use a sentinel value
     14            # instead of returning an empty dict.
     15            return 'NOTNEEDED'
     16        else:
     17            return token
     18    _get_val = lazy(_get_val, str)
     19
     20    return {'csrf_token': _get_val() }
  • django/contrib/csrf/middleware.py

    diff -r 1b4df7524b7c django/contrib/csrf/middleware.py
    a b  
    55against request forgeries from other sites.
    66"""
    77
     8import itertools
    89import re
    9 import itertools
     10import random
    1011try:
    1112    from functools import wraps
    1213except ImportError:
    1314    from django.utils.functional import wraps  # Python 2.3, 2.4 fallback.
    1415
    1516from django.conf import settings
    16 from django.http import HttpResponseForbidden
     17from django.core.urlresolvers import get_callable
    1718from django.utils.hashcompat import md5_constructor
    1819from django.utils.safestring import mark_safe
    1920
    20 _ERROR_MSG = mark_safe('<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><body><h1>403 Forbidden</h1><p>Cross Site Request Forgery detected. Request aborted.</p></body></html>')
    21 
    2221_POST_FORM_RE = \
    2322    re.compile(r'(<form\W[^>]*\bmethod\s*=\s*(\'|"|)POST(\'|"|)\b[^>]*>)', re.IGNORECASE)
    2423
    2524_HTML_TYPES = ('text/html', 'application/xhtml+xml')
    2625
    27 def _make_token(session_id):
     26# Use the system (hardware-based) random number generator if it exists.
     27if hasattr(random, 'SystemRandom'):
     28    randrange = random.SystemRandom().randrange
     29else:
     30    randrange = random.randrange
     31_MAX_CSRF_KEY = 18446744073709551616L     # 2 << 63
     32
     33def _get_failure_view():
     34    """
     35    Returns the view to be used for CSRF rejections
     36    """
     37    return get_callable(settings.CSRF_FAILURE_VIEW)
     38
     39def _get_new_csrf_key():
     40    return md5_constructor("%s%s"
     41                % (randrange(0, _MAX_CSRF_KEY), settings.SECRET_KEY)).hexdigest()
     42
     43def _make_legacy_session_token(session_id):
    2844    return md5_constructor(settings.SECRET_KEY + session_id).hexdigest()
    2945
     46def get_token(request):
     47    """
     48    Returns the the CSRF token required for a POST form.
     49    """
     50    request.META["CSRF_COOKIE_USED"] = True
     51    return request.META.get("CSRF_COOKIE", None)
     52
    3053class CsrfViewMiddleware(object):
    3154    """
    3255    Middleware that requires a present and correct csrfmiddlewaretoken
    33     for POST requests that have an active session.
     56    for POST requests that have a CSRF cookie, and sets an outgoing
     57    CSRF cookie.
     58
     59    This middleware should be used in conjunction with the csrf_token template
     60    tag.
    3461    """
    3562    def process_view(self, request, callback, callback_args, callback_kwargs):
     63        reject = lambda: _get_failure_view()(request)
     64
     65        if getattr(callback, 'csrf_exempt', False):
     66            return None
     67
     68        # If the user doesn't have a CSRF cookie, generate one and store it in the
     69        # request, so it's available to the view.  We'll store it in a cookie when
     70        # we reach the response.
     71        try:
     72            request.META["CSRF_COOKIE"] = request.COOKIES[settings.CSRF_COOKIE_NAME]
     73            cookie_is_new = False
     74        except KeyError:
     75            # No cookie, so create one.
     76            request.META["CSRF_COOKIE"] = _get_new_csrf_key()
     77            cookie_is_new = True
     78
    3679        if request.method == 'POST':
    37             if getattr(callback, 'csrf_exempt', False):
    38                 return None
    39 
    4080            if request.is_ajax():
    4181                return None
    4282
    43             try:
    44                 session_id = request.COOKIES[settings.SESSION_COOKIE_NAME]
    45             except KeyError:
    46                 # No session, no check required
    47                 return None
     83            if request.is_secure():
     84                # Strict referer checking for HTTPS
     85                referer = request.META.get('HTTP_REFERER')
     86                if referer is None:
     87                    return reject()
    4888
    49             csrf_token = _make_token(session_id)
     89                # The following check ensures that the referer is HTTPS,
     90                # the domains match and the ports match.  This might be too strict.
     91                if not referer.startswith('https://%s/' % request.get_host()):
     92                    return reject()
     93
     94            # If the user didn't already have a CSRF key, then accept the
     95            # session key for the middleware token, so CSRF protection isn't lost
     96            # for the period between upgrading to CSRF cookes to the first time
     97            # each user comes back to the site to receive one.
     98            if cookie_is_new:
     99                try:
     100                    session_id = request.COOKIES[settings.SESSION_COOKIE_NAME]
     101                    csrf_token = _make_legacy_session_token(session_id)
     102                except KeyError:
     103                    # No CSRF cookie and no session cookie. For POST requests,
     104                    # we insist on a CSRF cookie, and in this way we can avoid
     105                    # all CSRF attacks, including login CSRF.
     106                    return reject()
     107            else:
     108                csrf_token = request.META["CSRF_COOKIE"]
     109
    50110            # check incoming token
    51             try:
    52                 request_csrf_token = request.POST['csrfmiddlewaretoken']
    53             except KeyError:
    54                 return HttpResponseForbidden(_ERROR_MSG)
    55 
     111            request_csrf_token = request.POST.get('csrfmiddlewaretoken', None)
    56112            if request_csrf_token != csrf_token:
    57                 return HttpResponseForbidden(_ERROR_MSG)
     113                return reject()
    58114
    59115        return None
    60116
     117    def process_response(self, request, response):
     118        # If CSRF_COOKIE is unset, then CsrfViewMiddleware.process_view was
     119        # never called, probaby because a request middleware returned a response
     120        # (for example, contrib.auth redirecting to a login page).
     121        if request.META.get("CSRF_COOKIE") is None:
     122            return response
     123
     124        if not request.META.get("CSRF_COOKIE_USED", False):
     125            return response
     126
     127        # Set the CSRF cookie even if it's already set, so we renew the expiry timer.
     128        response.set_cookie(settings.CSRF_COOKIE_NAME,
     129                request.META["CSRF_COOKIE"], max_age = 60 * 60 * 24 * 7 * 52,
     130                domain=settings.CSRF_COOKIE_DOMAIN)
     131
     132        return response
     133
    61134class CsrfResponseMiddleware(object):
    62135    """
    63     Middleware that post-processes a response to add a
    64     csrfmiddlewaretoken if the response/request have an active
    65     session.
     136    DEPRECATED
     137    Middleware that post-processes a response to add a csrfmiddlewaretoken.
     138
     139    This exists for backwards compatibility and as an interim measure until
     140    applications are converted to using use the csrf_token template tag
     141    instead. It will be removed in Django 1.4.
    66142    """
     143    def __init__(self):
     144        import warnings
     145        warnings.warn(
     146            "CsrfResponseMiddleware and CsrfMiddleware are deprecated; use CsrfViewMiddleware and the template tag instead (see CSRF documentation).",
     147            PendingDeprecationWarning
     148        )
     149
    67150    def process_response(self, request, response):
    68151        if getattr(response, 'csrf_exempt', False):
    69152            return response
    70153
    71         csrf_token = None
    72         try:
    73             # This covers a corner case in which the outgoing response
    74             # both contains a form and sets a session cookie.  This
    75             # really should not be needed, since it is best if views
    76             # that create a new session (login pages) also do a
    77             # redirect, as is done by all such view functions in
    78             # Django.
    79             cookie = response.cookies[settings.SESSION_COOKIE_NAME]
    80             csrf_token = _make_token(cookie.value)
    81         except KeyError:
    82             # Normal case - look for existing session cookie
    83             try:
    84                 session_id = request.COOKIES[settings.SESSION_COOKIE_NAME]
    85                 csrf_token = _make_token(session_id)
    86             except KeyError:
    87                 # no incoming or outgoing cookie
    88                 pass
    89 
    90         if csrf_token is not None and \
    91                 response['Content-Type'].split(';')[0] in _HTML_TYPES:
     154        if response['Content-Type'].split(';')[0] in _HTML_TYPES:
     155            csrf_token = get_token(request)
     156            # If csrf_token is None, we have no token for this request, which probably
     157            # means that this is a response from a request middleware.
     158            if csrf_token is None:
     159                return response
    92160
    93161            # ensure we don't add the 'id' attribute twice (HTML validity)
    94162            idattributes = itertools.chain(("id='csrfmiddlewaretoken'",),
    95                                             itertools.repeat(''))
     163                                           itertools.repeat(''))
    96164            def add_csrf_field(match):
    97165                """Returns the matched <form> tag plus the added <input> element"""
    98166                return mark_safe(match.group() + "<div style='display:none;'>" + \
     
    104172            response.content = _POST_FORM_RE.sub(add_csrf_field, response.content)
    105173        return response
    106174
    107 class CsrfMiddleware(CsrfViewMiddleware, CsrfResponseMiddleware):
    108     """Django middleware that adds protection against Cross Site
     175class CsrfMiddleware(object):
     176    """
     177    Django middleware that adds protection against Cross Site
    109178    Request Forgeries by adding hidden form fields to POST forms and
    110179    checking requests for the correct value.
    111180
    112     In the list of middlewares, SessionMiddleware is required, and
    113     must come after this middleware.  CsrfMiddleWare must come after
    114     compression middleware.
     181    CsrfMiddleware uses two middleware, CsrfViewMiddleware and
     182    CsrfResponseMiddleware, which can be used independently.  It is recommended
     183    to use only CsrfViewMiddleware and use the csrf_token template tag in
     184    templates for inserting the token.
     185    """
     186    # We can't just inherit from CsrfViewMiddleware and CsrfResponseMiddleware
     187    # because both have process_response methods.
     188    def __init__(self):
     189        self.response_middleware = CsrfResponseMiddleware()
     190        self.view_middleware = CsrfViewMiddleware()
    115191
    116     If a session ID cookie is present, it is hashed with the
    117     SECRET_KEY setting to create an authentication token.  This token
    118     is added to all outgoing POST forms and is expected on all
    119     incoming POST requests that have a session ID cookie.
     192    def process_response(self, request, resp):
     193        # We must do the response post-processing first, because that calls
     194        # get_token(), which triggers a flag saying that the CSRF cookie needs
     195        # to be sent (done in CsrfViewMiddleware.process_response)
     196        resp2 = self.response_middleware.process_response(request, resp)
     197        return self.view_middleware.process_response(request, resp2)
    120198
    121     If you are setting cookies directly, instead of using Django's
    122     session framework, this middleware will not work.
    123 
    124     CsrfMiddleWare is composed of two middleware, CsrfViewMiddleware
    125     and CsrfResponseMiddleware which can be used independently.
    126     """
    127     pass
     199    def process_view(self, request, callback, callback_args, callback_kwargs):
     200        return self.view_middleware.process_view(request, callback, callback_args,
     201                                                 callback_kwargs)
    128202
    129203def csrf_response_exempt(view_func):
    130204    """
  • new file django/contrib/csrf/templatetags/__init__.py

    diff -r 1b4df7524b7c django/contrib/csrf/templatetags/__init__.py
    - +  
     1
  • new file django/contrib/csrf/templatetags/csrf.py

    diff -r 1b4df7524b7c django/contrib/csrf/templatetags/csrf.py
    - +  
     1from django import template
     2from django.utils.safestring import mark_safe
     3
     4register = template.Library()
     5
     6class CsrfTokenNode(template.Node):
     7    def render(self, context):
     8        csrf_token = context.get('csrf_token', None)
     9        if csrf_token:
     10            if csrf_token == 'NOTNEEDED':
     11                return mark_safe(u"")
     12            else:
     13                return mark_safe(u"<div style='display:none'><input type='hidden' name='csrfmiddlewaretoken' value='%s' /></div>" % (csrf_token))
     14        else:
     15            # It's very probable that the token is missing because of
     16            # misconfiguration, so we raise a warning
     17            from django.conf import settings
     18            if settings.DEBUG:
     19                import warnings
     20                warnings.warn("A {% csrf_token %} was used in a template, but the context did not provide the value.  This is usually caused by not having 'django.contrib.csrf.context_processors.csrf' in TEMPLATE_CONTEXT_PROCESSORS or not using RequestContext.")
     21            return u''
     22
     23def csrf_token(parser, token):
     24    return CsrfTokenNode()
     25register.tag(csrf_token)
  • django/contrib/csrf/tests.py

    diff -r 1b4df7524b7c django/contrib/csrf/tests.py
    a b  
    11# -*- coding: utf-8 -*-
    22
    33from django.test import TestCase
    4 from django.http import HttpRequest, HttpResponse, HttpResponseForbidden
    5 from django.contrib.csrf.middleware import CsrfMiddleware, _make_token, csrf_exempt
     4from django.http import HttpRequest, HttpResponse
     5from django.contrib.csrf.middleware import CsrfMiddleware, CsrfViewMiddleware, csrf_exempt
     6from django.contrib.csrf.context_processors import csrf
     7from django.contrib.sessions.middleware import SessionMiddleware
     8from django.utils.importlib import import_module
    69from django.conf import settings
     10from django.template import RequestContext, Template
    711
    8 
     12# Response/views used for CsrfResponseMiddleware and CsrfViewMiddleware tests
    913def post_form_response():
    1014    resp = HttpResponse(content="""
    1115<html><body><form method="POST"><input type="text" /></form></body></html>
    1216""", mimetype="text/html")
    1317    return resp
    1418
    15 def test_view(request):
     19def post_form_response_non_html():
     20    resp = post_form_response()
     21    resp["Content-Type"] = "application/xml"
     22    return resp
     23
     24def post_form_view(request):
     25    """A view that returns a POST form (without a token)"""
    1626    return post_form_response()
    1727
     28# Response/views used for template tag tests
     29def _token_template():
     30    return Template("{% load csrf %}{% csrf_token %}")
     31
     32def _render_csrf_token_template(req):
     33    context = RequestContext(req, processors=[csrf])
     34    template = _token_template()
     35    return template.render(context)
     36
     37def token_view(request):
     38    """A view that uses {% csrf_token %}"""
     39    return HttpResponse(_render_csrf_token_template(request))
     40
     41def non_token_view_using_request_processor(request):
     42    """
     43    A view that doesn't use the token, but does use the csrf view processor.
     44    """
     45    context = RequestContext(request, processors=[csrf])
     46    template = Template("{% load csrf %}")
     47    return HttpResponse(template.render(context))
     48
     49class TestingHttpRequest(HttpRequest):
     50    """
     51    A version of HttpRequest that allows us to change some things
     52    more easily
     53    """
     54    def is_secure(self):
     55        return getattr(self, '_is_secure', False)
     56
    1857class CsrfMiddlewareTest(TestCase):
     58    _csrf_id = "1"
    1959
     60    # This is a valid session token for this ID and secret key.  This was generated using
     61    # the old code that we're to be backwards-compatible with.  Don't use the CSRF code
     62    # to generate this hash, or we're merely testing the code against itself and not
     63    # checking backwards-compatibility.  This is also the output of (echo -n test1 | md5sum).
     64    _session_token = "5a105e8b9d40e1329780d62ea2265d8a"
    2065    _session_id = "1"
     66    _secret_key_for_session_test= "test"
    2167
    22     def _get_GET_no_session_request(self):
    23         return HttpRequest()
     68    def _get_GET_no_csrf_cookie_request(self):
     69        return TestingHttpRequest()
    2470
    25     def _get_GET_session_request(self):
    26         req = self._get_GET_no_session_request()
     71    def _get_GET_csrf_cookie_request(self):
     72        req = TestingHttpRequest()
     73        req.COOKIES[settings.CSRF_COOKIE_NAME] = self._csrf_id
     74        return req
     75
     76    def _get_POST_csrf_cookie_request(self):
     77        req = self._get_GET_csrf_cookie_request()
     78        req.method = "POST"
     79        return req
     80
     81    def _get_POST_no_csrf_cookie_request(self):
     82        req = self._get_GET_no_csrf_cookie_request()
     83        req.method = "POST"
     84        return req
     85
     86    def _get_POST_request_with_token(self):
     87        req = self._get_POST_csrf_cookie_request()
     88        req.POST['csrfmiddlewaretoken'] = self._csrf_id
     89        return req
     90
     91    def _get_POST_session_request_with_token(self):
     92        req = self._get_POST_no_csrf_cookie_request()
     93        req.COOKIES[settings.SESSION_COOKIE_NAME] = self._session_id
     94        req.POST['csrfmiddlewaretoken'] = self._session_token
     95        return req
     96
     97    def _get_POST_session_request_no_token(self):
     98        req = self._get_POST_no_csrf_cookie_request()
    2799        req.COOKIES[settings.SESSION_COOKIE_NAME] = self._session_id
    28100        return req
    29101
    30     def _get_POST_session_request(self):
    31         req = self._get_GET_session_request()
    32         req.method = "POST"
    33         return req
     102    def _check_token_present(self, response, csrf_id=None):
     103        self.assertContains(response, "name='csrfmiddlewaretoken' value='%s'" % (csrf_id or self._csrf_id))
    34104
    35     def _get_POST_no_session_request(self):
    36         req = self._get_GET_no_session_request()
    37         req.method = "POST"
    38         return req
     105    # Check the post processing and outgoing cookie
     106    def test_process_response_no_csrf_cookie(self):
     107        """
     108        When no prior CSRF cookie exists, check that the cookie is created and a
     109        token is inserted.
     110        """
     111        req = self._get_GET_no_csrf_cookie_request()
     112        CsrfMiddleware().process_view(req, post_form_view, (), {})
    39113
    40     def _get_POST_session_request_with_token(self):
    41         req = self._get_POST_session_request()
    42         req.POST['csrfmiddlewaretoken'] = _make_token(self._session_id)
    43         return req
    44 
    45     def _get_post_form_response(self):
    46         return post_form_response()
    47 
    48     def _get_new_session_response(self):
    49         resp = self._get_post_form_response()
    50         resp.cookies[settings.SESSION_COOKIE_NAME] = self._session_id
    51         return resp
    52 
    53     def _check_token_present(self, response):
    54         self.assertContains(response, "name='csrfmiddlewaretoken' value='%s'" % _make_token(self._session_id))
    55 
    56     def get_view(self):
    57         return test_view
    58 
    59     # Check the post processing
    60     def test_process_response_no_session(self):
    61         """
    62         Check the post-processor does nothing if no session active
    63         """
    64         req = self._get_GET_no_session_request()
    65         resp = self._get_post_form_response()
     114        resp = post_form_response()
    66115        resp_content = resp.content # needed because process_response modifies resp
    67116        resp2 = CsrfMiddleware().process_response(req, resp)
    68         self.assertEquals(resp_content, resp2.content)
    69117
    70     def test_process_response_existing_session(self):
     118        csrf_cookie = resp2.cookies.get(settings.CSRF_COOKIE_NAME, False)
     119        self.assertNotEqual(csrf_cookie, False)
     120        self.assertNotEqual(resp_content, resp2.content)
     121        self._check_token_present(resp2, csrf_cookie.value)
     122
     123    def test_process_response_no_csrf_cookie_view_only_get_token_used(self):
    71124        """
    72         Check that the token is inserted if there is an existing session
     125        When no prior CSRF cookie exists, check that the cookie is created, even
     126        if only CsrfViewMiddleware is used.
    73127        """
    74         req = self._get_GET_session_request()
    75         resp = self._get_post_form_response()
     128        # This is checking that CsrfViewMiddleware has the cookie setting
     129        # code. Most of the other tests use CsrfMiddleware.
     130        req = self._get_GET_no_csrf_cookie_request()
     131        # token_view calls get_token() indirectly
     132        CsrfViewMiddleware().process_view(req, token_view, (), {})
     133        resp = token_view(req)
     134        resp2 = CsrfViewMiddleware().process_response(req, resp)
     135
     136        csrf_cookie = resp2.cookies.get(settings.CSRF_COOKIE_NAME, False)
     137        self.assertNotEqual(csrf_cookie, False)
     138
     139    def test_process_response_get_token_not_used(self):
     140        """
     141        Check that if get_token() is not called, the view middleware does not
     142        add a cookie.
     143        """
     144        # This is important to make pages cacheable.  Pages which do call
     145        # get_token(), assuming they use the token, are not cacheable because
     146        # the token is specific to the user
     147        req = self._get_GET_no_csrf_cookie_request()
     148        # non_token_view_using_request_processor does not call get_token(), but
     149        # does use the csrf request processor.  By using this, we are testing
     150        # that the view processor is properly lazy and doesn't call get_token()
     151        # until needed.
     152        CsrfViewMiddleware().process_view(req, non_token_view_using_request_processor, (), {})
     153        resp = non_token_view_using_request_processor(req)
     154        resp2 = CsrfViewMiddleware().process_response(req, resp)
     155
     156        csrf_cookie = resp2.cookies.get(settings.CSRF_COOKIE_NAME, False)
     157        self.assertEqual(csrf_cookie, False)
     158
     159    def test_process_response_existing_csrf_cookie(self):
     160        """
     161        Check that the token is inserted when a prior CSRF cookie exists
     162        """
     163        req = self._get_GET_csrf_cookie_request()
     164        CsrfMiddleware().process_view(req, post_form_view, (), {})
     165
     166        resp = post_form_response()
    76167        resp_content = resp.content # needed because process_response modifies resp
    77168        resp2 = CsrfMiddleware().process_response(req, resp)
    78169        self.assertNotEqual(resp_content, resp2.content)
    79170        self._check_token_present(resp2)
    80171
    81     def test_process_response_new_session(self):
     172    def test_process_response_non_html(self):
    82173        """
    83         Check that the token is inserted if there is a new session being started
     174        Check the the post-processor does nothing for content-types not in _HTML_TYPES.
    84175        """
    85         req = self._get_GET_no_session_request() # no session in request
    86         resp = self._get_new_session_response() # but new session started
     176        req = self._get_GET_no_csrf_cookie_request()
     177        CsrfMiddleware().process_view(req, post_form_view, (), {})
     178        resp = post_form_response_non_html()
    87179        resp_content = resp.content # needed because process_response modifies resp
    88180        resp2 = CsrfMiddleware().process_response(req, resp)
    89         self.assertNotEqual(resp_content, resp2.content)
    90         self._check_token_present(resp2)
     181        self.assertEquals(resp_content, resp2.content)
    91182
    92183    def test_process_response_exempt_view(self):
    93184        """
    94185        Check that no post processing is done for an exempt view
    95186        """
    96         req = self._get_POST_session_request()
    97         resp = csrf_exempt(self.get_view())(req)
     187        req = self._get_POST_csrf_cookie_request()
     188        resp = csrf_exempt(post_form_view)(req)
    98189        resp_content = resp.content
    99190        resp2 = CsrfMiddleware().process_response(req, resp)
    100191        self.assertEquals(resp_content, resp2.content)
    101192
    102193    # Check the request processing
    103     def test_process_request_no_session(self):
     194    def test_process_request_no_session_no_csrf_cookie(self):
    104195        """
    105         Check that if no session is present, the middleware does nothing.
    106         to the incoming request.
     196        Check that if neither a CSRF cookie nor a session cookie are present,
     197        the middleware rejects the incoming request.  This will stop login CSRF.
    107198        """
    108         req = self._get_POST_no_session_request()
    109         req2 = CsrfMiddleware().process_view(req, self.get_view(), (), {})
     199        req = self._get_POST_no_csrf_cookie_request()
     200        req2 = CsrfMiddleware().process_view(req, post_form_view, (), {})
     201        self.assertEquals(403, req2.status_code)
     202
     203    def test_process_request_csrf_cookie_no_token(self):
     204        """
     205        Check that if a CSRF cookie is present but no token, the middleware
     206        rejects the incoming request.
     207        """
     208        req = self._get_POST_csrf_cookie_request()
     209        req2 = CsrfMiddleware().process_view(req, post_form_view, (), {})
     210        self.assertEquals(403, req2.status_code)
     211
     212    def test_process_request_csrf_cookie_and_token(self):
     213        """
     214        Check that if both a cookie and a token is present, the middleware lets it through.
     215        """
     216        req = self._get_POST_request_with_token()
     217        req2 = CsrfMiddleware().process_view(req, post_form_view, (), {})
    110218        self.assertEquals(None, req2)
    111219
    112     def test_process_request_session_no_token(self):
     220    def test_process_request_session_cookie_no_csrf_cookie_token(self):
    113221        """
    114         Check that if a session is present but no token, we get a 'forbidden'
     222        When no CSRF cookie exists, but the user has a session, check that a token
     223        using the session cookie as a legacy CSRF cookie is accepted.
    115224        """
    116         req = self._get_POST_session_request()
    117         req2 = CsrfMiddleware().process_view(req, self.get_view(), (), {})
    118         self.assertEquals(HttpResponseForbidden, req2.__class__)
     225        orig_secret_key = settings.SECRET_KEY
     226        settings.SECRET_KEY = self._secret_key_for_session_test
     227        try:
     228            req = self._get_POST_session_request_with_token()
     229            req2 = CsrfMiddleware().process_view(req, post_form_view, (), {})
     230            self.assertEquals(None, req2)
     231        finally:
     232            settings.SECRET_KEY = orig_secret_key
    119233
    120     def test_process_request_session_and_token(self):
     234    def test_process_request_session_cookie_no_csrf_cookie_no_token(self):
    121235        """
    122         Check that if a session is present and a token, the middleware lets it through
     236        Check that if a session cookie is present but no token and no CSRF cookie,
     237        the request is rejected.
    123238        """
    124         req = self._get_POST_session_request_with_token()
    125         req2 = CsrfMiddleware().process_view(req, self.get_view(), (), {})
    126         self.assertEquals(None, req2)
     239        req = self._get_POST_session_request_no_token()
     240        req2 = CsrfMiddleware().process_view(req, post_form_view, (), {})
     241        self.assertEquals(403, req2.status_code)
    127242
    128     def test_process_request_session_no_token_exempt_view(self):
     243    def test_process_request_csrf_cookie_no_token_exempt_view(self):
    129244        """
    130         Check that if a session is present and no token, but the csrf_exempt
     245        Check that if a CSRF cookie is present and no token, but the csrf_exempt
    131246        decorator has been applied to the view, the middleware lets it through
    132247        """
    133         req = self._get_POST_session_request()
    134         req2 = CsrfMiddleware().process_view(req, csrf_exempt(self.get_view()), (), {})
     248        req = self._get_POST_csrf_cookie_request()
     249        req2 = CsrfMiddleware().process_view(req, csrf_exempt(post_form_view), (), {})
    135250        self.assertEquals(None, req2)
    136251
    137252    def test_ajax_exemption(self):
    138253        """
    139254        Check that AJAX requests are automatically exempted.
    140255        """
    141         req = self._get_POST_session_request()
     256        req = self._get_POST_csrf_cookie_request()
    142257        req.META['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
    143         req2 = CsrfMiddleware().process_view(req, self.get_view(), (), {})
     258        req2 = CsrfMiddleware().process_view(req, post_form_view, (), {})
    144259        self.assertEquals(None, req2)
     260
     261    # Tests for the template tag method
     262    def test_token_node_no_csrf_cookie(self):
     263        """
     264        Check that CsrfTokenNode works when no CSRF cookie is set
     265        """
     266        req = self._get_GET_no_csrf_cookie_request()
     267        resp = token_view(req)
     268        self.assertEquals(u"", resp.content)
     269
     270    def test_token_node_with_csrf_cookie(self):
     271        """
     272        Check that CsrfTokenNode works when a CSRF cookie is set
     273        """
     274        req = self._get_GET_csrf_cookie_request()
     275        CsrfViewMiddleware().process_view(req, token_view, (), {})
     276        resp = token_view(req)
     277        self._check_token_present(resp)
     278
     279    def test_token_node_with_new_csrf_cookie(self):
     280        """
     281        Check that CsrfTokenNode works when a CSRF cookie is created by
     282        the middleware (when one was not already present)
     283        """
     284        req = self._get_GET_no_csrf_cookie_request()
     285        CsrfViewMiddleware().process_view(req, token_view, (), {})
     286        resp = token_view(req)
     287        resp2 = CsrfViewMiddleware().process_response(req, resp)
     288        csrf_cookie = resp2.cookies[settings.CSRF_COOKIE_NAME]
     289        self._check_token_present(resp, csrf_id=csrf_cookie.value)
     290
     291    def test_response_middleware_without_view_middleware(self):
     292        """
     293        Check that CsrfResponseMiddleware finishes without error if the view middleware
     294        has not been called, as is the case if a request middleware returns a response.
     295        """
     296        req = self._get_GET_no_csrf_cookie_request()
     297        resp = post_form_view(req)
     298        CsrfMiddleware().process_response(req, resp)
     299
     300    def test_https_bad_referer(self):
     301        """
     302        Test that a POST HTTP request with a bad referer is rejected
     303        """
     304        req = self._get_POST_request_with_token()
     305        req._is_secure = True
     306        req.META['HTTP_HOST'] = 'www.example.com'
     307        req.META['HTTP_REFERER'] = 'https://www.evil.org/somepage'
     308        req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
     309        self.assertNotEqual(None, req2)
     310        self.assertEquals(403, req2.status_code)
     311
     312    def test_https_good_referer(self):
     313        """
     314        Test that a POST HTTP request with a good referer is accepted
     315        """
     316        req = self._get_POST_request_with_token()
     317        req._is_secure = True
     318        req.META['HTTP_HOST'] = 'www.example.com'
     319        req.META['HTTP_REFERER'] = 'https://www.example.com/somepage'
     320        req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
     321        self.assertEquals(None, req2)
  • new file django/contrib/csrf/views.py

    diff -r 1b4df7524b7c django/contrib/csrf/views.py
    - +  
     1from django.http import HttpResponseForbidden
     2from django.utils.safestring import mark_safe
     3
     4_ERROR_MSG = mark_safe('<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><body><h1>403 Forbidden</h1><p>CSRF verification failed. Request aborted.</p></body></html>')
     5
     6def csrf_failure(request):
     7    """
     8    Default view used when request fails CSRF protection
     9    """
     10    return HttpResponseForbidden(_ERROR_MSG)
  • django/contrib/formtools/templates/formtools/form.html

    diff -r 1b4df7524b7c django/contrib/formtools/templates/formtools/form.html
    a b  
    11{% extends "base.html" %}
    2 
     2{% load csrf %}
    33{% block content %}
    44
    55{% if form.errors %}<h1>Please correct the following errors</h1>{% else %}<h1>Submit</h1>{% endif %}
    66
    7 <form action="" method="post">
     7<form action="" method="post">{% csrf_token %}
    88<table>
    99{{ form }}
    1010</table>
  • django/contrib/formtools/templates/formtools/preview.html

    diff -r 1b4df7524b7c django/contrib/formtools/templates/formtools/preview.html
    a b  
    11{% extends "base.html" %}
    2 
     2{% load csrf %}
    33{% block content %}
    44
    55<h1>Preview your submission</h1>
     
    1515
    1616<p>Security hash: {{ hash_value }}</p>
    1717
    18 <form action="" method="post">
     18<form action="" method="post">{% csrf_token %}
    1919{% for field in form %}{{ field.as_hidden }}
    2020{% endfor %}
    2121<input type="hidden" name="{{ stage_field }}" value="2" />
     
    2525
    2626<h1>Or edit it again</h1>
    2727
    28 <form action="" method="post">
     28<form action="" method="post">{% csrf_token %}
    2929<table>
    3030{{ form }}
    3131</table>
  • docs/intro/tutorial01.txt

    diff -r 1b4df7524b7c docs/intro/tutorial01.txt
    a b  
    209209
    210210    * :mod:`django.contrib.contenttypes` -- A framework for content types.
    211211
     212    * :mod:`django.contrib.csrf` -- A security system for dealing with Cross
     213      Site Request Forgeries
     214
     215    * :mod:`django.contrib.csrf` -- An easy-to-use system for protecting
     216      against Cross Site Request Forgeries.
     217
    212218    * :mod:`django.contrib.sessions` -- A session framework.
    213219
    214220    * :mod:`django.contrib.sites` -- A framework for managing multiple sites
     
    216222
    217223These applications are included by default as a convenience for the common case.
    218224
    219 Each of these applications makes use of at least one database table, though,
     225Most of these applications makes use of at least one database table, though,
    220226so we need to create the tables in the database before we can use them. To do
    221227that, run the following command:
    222228
     
    386392    INSTALLED_APPS = (
    387393        'django.contrib.auth',
    388394        'django.contrib.contenttypes',
     395        'django.contrib.csrf',
    389396        'django.contrib.sessions',
    390397        'django.contrib.sites',
    391398        'mysite.polls'
  • docs/intro/tutorial04.txt

    diff -r 1b4df7524b7c docs/intro/tutorial04.txt
    a b  
    1616
    1717.. code-block:: html+django
    1818
     19    {% load csrf %}
    1920    <h1>{{ poll.question }}</h1>
    2021
    2122    {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
    2223
    2324    <form action="/polls/{{ poll.id }}/vote/" method="post">
     25    {% csrf_token %}
    2426    {% for choice in poll.choice_set.all %}
    2527        <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" />
    2628        <label for="choice{{ forloop.counter }}">{{ choice.choice }}</label><br />
     
    4648    * ``forloop.counter`` indicates how many times the :ttag:`for` tag has gone
    4749      through its loop
    4850
     51    * Since we are creating a POST form (which can have the effect of modifying
     52      data), we unfortunately need to worry about Cross Site Request Forgeries.
     53      Thankfully, you don't have to worry too hard, because Django comes with
     54      very easy-to-use system for protecting against it.  In short, all POST
     55      forms that are targetted at internal URLs need the ``{% csrf_token %}``
     56      template tag adding, and this tag in turn requires the ``{% load csrf %}``
     57      line.  A 'middleware' which is installed by default checks for the
     58      presence of the token in the submitted form data.
     59
     60The ``{% csrf_token %}`` tag requires information from the request object, which
     61is not normally accessible from within the template context.  To fix this, a
     62small adjustment needs to be made to the ``detail`` view, so that it looks like
     63the following::
     64
     65    from django.template import RequestContext
     66    # ...
     67    def detail(request, poll_id):
     68        p = get_object_or_404(Poll, pk=poll_id)
     69        return render_to_response('polls/detail.html', {'poll': p},
     70                                   context_instance=RequestContext(request))
     71
     72The details of how this works are explained in the documentation for
     73:ref:`RequestContext <subclassing-context-requestcontext>`.
     74
    4975Now, let's create a Django view that handles the submitted data and does
    5076something with it. Remember, in :ref:`Tutorial 3 <intro-tutorial03>`, we
    5177created a URLconf for the polls application that includes this line::
     
    5783    from django.shortcuts import get_object_or_404, render_to_response
    5884    from django.http import HttpResponseRedirect
    5985    from django.core.urlresolvers import reverse
     86    from django.template import RequestContext
    6087    from mysite.polls.models import Choice, Poll
    6188    # ...
    6289    def vote(request, poll_id):
     
    6895            return render_to_response('polls/detail.html', {
    6996                'poll': p,
    7097                'error_message': "You didn't select a choice.",
    71             })
     98            }, context_instance=RequestContext(request))
    7299        else:
    73100            selected_choice.votes += 1
    74101            selected_choice.save()
  • docs/ref/contrib/csrf.txt

    diff -r 1b4df7524b7c docs/ref/contrib/csrf.txt
    a b  
    77.. module:: django.contrib.csrf
    88   :synopsis: Protects against Cross Site Request Forgeries
    99
    10 The CsrfMiddleware class provides easy-to-use protection against
     10The CSRF middleware and template tag provides easy-to-use protection against
    1111`Cross Site Request Forgeries`_.  This type of attack occurs when a malicious
    1212Web site creates a link or form button that is intended to perform some action
    13 on your Web site, using the credentials of a logged-in user who is tricked
    14 into clicking on the link in their browser.
     13on your Web site, using the credentials of a logged-in user who is tricked into
     14clicking on the link in their browser.  A related type of attack, 'login CSRF',
     15where an attacking site tricks a user's browser into logging into a site with
     16someone else's credentials, is also covered.
    1517
    16 The first defense against CSRF attacks is to ensure that GET requests
    17 are side-effect free.  POST requests can then be protected by adding this
    18 middleware into your list of installed middleware.
     18The first defense against CSRF attacks is to ensure that GET requests are
     19side-effect free.  POST requests can then be protected by following the steps
     20below.
     21
     22.. versionadded:: 1.2
     23    The 'contrib' apps, including the admin, depend on the functionality
     24    described here. Anyone upgrading from earlier versions should read
     25    the `Upgrading notes`_ carefully.
    1926
    2027.. _Cross Site Request Forgeries: http://www.squarefree.com/securitytips/web-developers.html#CSRF
    2128
    2229How to use it
    2330=============
    2431
    25 Add the middleware ``'django.contrib.csrf.middleware.CsrfMiddleware'`` to
    26 your list of middleware classes, :setting:`MIDDLEWARE_CLASSES`. It needs to process
    27 the response after the SessionMiddleware, so must come before it in the
    28 list. It also must process the response before things like compression
    29 happen to the response, so it must come after GZipMiddleware in the
    30 list.
     32.. versionchanged:: 1.2
     33    The template tag functionality (the recommended way to use this) was added
     34    in version 1.2. The previous method (still available) is described under
     35    `Legacy method`_.
    3136
    32 The ``CsrfMiddleware`` class is actually composed of two middleware:
    33 ``CsrfViewMiddleware`` which performs the checks on incoming requests,
    34 and ``CsrfResponseMiddleware`` which performs post-processing of the
    35 result.  This allows the individual components to be used and/or
    36 replaced instead of using ``CsrfMiddleware``.
     37To enable CSRF protection for your views, follow these steps:
    3738
    38 .. versionchanged:: 1.1
    39     (previous versions of Django did not provide these two components
    40     of ``CsrfMiddleware`` as described above)
     39    1. Add the middleware
     40       ``'django.contrib.csrf.middleware.CsrfViewMiddleware'`` to your list of
     41       middleware classes, :setting:`MIDDLEWARE_CLASSES`.  (It should come
     42       before ``CsrfResponseMiddleware`` if that is being used, and before any
     43       view middleware that assume that CSRF attacks have been dealt with.)
     44
     45    2. Add ``'django.contrib.csrf'`` to your :setting:`INSTALLED_APPS`.
     46
     47    3. In any template that uses a POST form, first load the 'csrf' template tag
     48       library::
     49
     50           {% load csrf %}
     51
     52       Then use the ``csrf_token`` tag inside the ``<form>`` element, e.g.::
     53
     54           <form action="" method="POST">{% csrf_token %}
     55
     56       This should not be done for POST forms that target external URLs, since
     57       that would cause the CSRF token to be leaked, leading to a vulnerability.
     58
     59    4. In the corresponding view functions, ensure that the
     60       ``'django.contrib.csrf.context_processors.csrf'`` context processor is
     61       being used. Usually, this can be done in one of two ways:
     62
     63       1. Using RequestContext:
     64
     65          1. Ensure ``'django.contrib.csrf.context_processors.csrf'`` is present
     66             in your :setting:`TEMPLATE_CONTEXT_PROCESSORS` setting. It is
     67             present by default.
     68
     69          2. Use ``RequestContext`` as the context instance in the relevant
     70             views. If you are using generic views or contrib apps, you are
     71             covered already.
     72
     73       2. Manually import and use the processor to generate the CSRF token and
     74          add it to the template context. e.g.::
     75
     76              from django.contrib.csrf.context_processors import csrf
     77              from django.template import Context
     78              from django.shortcuts import render_to_response
     79              def my_view(request):
     80                  c = Context()
     81                  c.update(csrf(request))
     82                  return render_to_response("a_template.html", context_instance=c)
     83
     84Legacy method
     85-------------
     86
     87In Django 1.1, the template tag did not exist.  Instead, a post-processing
     88middleware that re-wrote POST forms to include the CRSF token was used.  If you
     89are upgrading a site from version 1.1 or earlier, please read this section and
     90the `Upgrading notes`_ below.  The post-processing middleware is still available
     91as ``CsrfResponseMiddleware``, and it can be used by following these steps:
     92
     93    1. Follow step 1 above to install ``CsrfViewMiddleware``.
     94
     95    2. Add ``'django.contrib.csrf.middleware.CsrfResponseMiddleware'`` to your
     96       :setting:`MIDDLEWARE_CLASSES` setting.
     97
     98       ``CsrfResponseMiddleware`` needs to process the response before things
     99       like compression happen to the response, so it must come after
     100       ``GZipMiddleware`` in the list.  It also must come after
     101       ``CsrfViewMiddleware``.
     102
     103Use of the ``CsrfResponseMiddleware`` is not recommended because of the
     104performance hit it imposes, and because of a potential security problem (see
     105below).  It can be used as an interim measure until applications have been
     106updated to use the ``{% crsf_token %}`` tag.  It is deprecated and will be
     107removed in Django 1.4.
     108
     109Django 1.1 and earlier provided a single ``CsrfMiddleware`` class.  This is also
     110still available for backwards compatibility.  It combines the functions of the
     111two middleware.
     112
     113Note also that previous versions of these classes depended on the sessions
     114framework, but this dependency has now been removed, with backward compatibility
     115support so that upgrading will not produce any issues.
     116
     117Security of legacy method
     118~~~~~~~~~~~~~~~~~~~~~~~~~
     119
     120The post-processing ``CsrfResponseMiddleware`` adds the CSRF token to all POST
     121forms (unless the view has been decorated with ``csrf_response_exempt``).  If
     122the POST form has an external untrusted site as its target, rather than an
     123internal page, that site will be sent the CSRF token when the form is submitted.
     124Armed with this leaked information, that site will then be able to successfully
     125launch a CSRF attack on your site against that user.  The
     126``@csrf_response_exempt`` decorator can be used to fix this, but only if the
     127page doesn't also contain internal forms that require the token.
     128
     129Upgrading notes
     130---------------
     131
     132When upgrading to version 1.2 or later, you may have applications that rely on
     133the old post-processing functionality for CSRF protection, or you may not have
     134enabled any CSRF protection.  This section outlines the steps necessary for a
     135smooth upgrade, without having to fix all the applications to use the new
     136template tag method immediately.
     137
     138If you are using any of the contrib apps (such as the admin), there are some
     139required steps for these applications to continue working. First, the CSRF
     140application must be added to :setting:`INSTALLED_APPS` (See `How to use it`_
     141above, step 2).  Second, the :setting:`TEMPLATE_CONTEXT_PROCESSORS` setting must
     142be updated (step 4.1.1 above).
     143
     144If you have ``CsrfMiddleware`` in your :setting:`MIDDLEWARE_CLASSES`, you will now
     145have a working installation with CSRF protection.  It is recommended at this
     146point that you replace ``CsrfMiddleware`` with its two components,
     147``CsrfViewMiddleware`` and ``CsrfResponseMiddleware`` (in that order).
     148
     149If you do not have any of the middleware in your :setting:`MIDDLEWARE_CLASSES`,
     150you will have a working installation but without any CSRF protection (just as
     151you had before). It is strongly recommended to install ``CsrfViewMiddleware``
     152and ``CsrfResponseMiddleware``, but if you are not interested in having any CSRF
     153protection, you can simply stop here.
     154
     155Assuming you have followed the above, all views in your Django site will now be
     156protected by the ``CsrfViewMiddleware``.  Contrib apps meet the requirements
     157imposed by the ``CsrfViewMiddleware`` using the template tag, and other
     158applications in your project will meet its requirements by virtue of the
     159``CsrfResponseMiddleware``.
     160
     161The next step is to update all your applications to use the template tag, as
     162described in `How to use it`_, steps 3-4.  This can be done as soon as is
     163practical. Any applications that are updated will now require Django 1.2 or
     164later, since they will use the CSRF template tag library which was not available
     165in earlier versions.
     166
     167Finally, once all applications are upgraded, ``CsrfResponseMiddleware`` can be
     168removed from your settings.
     169
     170While ``CsrfResponseMiddleware`` is still in use, the ``csrf_response_exempt``
     171decorator, described in `Exceptions`_, may be useful.  The post-processing
     172middleware imposes a performance hit and a potential vulnerability, and any
     173views that have been upgraded to use the new template tag method no longer need
     174it.
    41175
    42176Exceptions
    43177----------
    44178
    45179.. versionadded:: 1.1
    46180
    47 To manually exclude a view function from being handled by the
    48 CsrfMiddleware, you can use the ``csrf_exempt`` decorator, found in
    49 the ``django.contrib.csrf.middleware`` module. For example::
     181To manually exclude a view function from being handled by either of the two CSRF
     182middleware, you can use the ``csrf_exempt`` decorator, found in the
     183``django.contrib.csrf.middleware`` module. For example::
    50184
    51185    from django.contrib.csrf.middleware import csrf_exempt
    52186
     
    54188        return HttpResponse('Hello world')
    55189    my_view = csrf_exempt(my_view)
    56190
    57 Like the middleware itself, the ``csrf_exempt`` decorator is composed
    58 of two parts: a ``csrf_view_exempt`` decorator and a
    59 ``csrf_response_exempt`` decorator, found in the same module.  These
    60 disable the view protection mechanism (``CsrfViewMiddleware``) and the
    61 response post-processing (``CsrfResponseMiddleware``) respectively.
    62 They can be used individually if required.
     191Like the middleware, the ``csrf_exempt`` decorator is composed of two parts: a
     192``csrf_view_exempt`` decorator and a ``csrf_response_exempt`` decorator, found
     193in the same module.  These disable the view protection mechanism
     194(``CsrfViewMiddleware``) and the response post-processing
     195(``CsrfResponseMiddleware``) respectively.  They can be used individually if
     196required.
    63197
    64 You don't have to worry about doing this for most AJAX views. Any
    65 request sent with "X-Requested-With: XMLHttpRequest" is automatically
    66 exempt. (See the next section.)
     198You don't have to worry about doing this for most AJAX views. Any request sent
     199with "X-Requested-With: XMLHttpRequest" is automatically exempt. (See the next
     200section.)
     201
     202Subdomains
     203----------
     204
     205By default, CSRF cookies are specific to the subdomain they are set for.  This
     206means that a form served from one subdomain (e.g. server1.example.com) will not
     207be able to have a target on another subdomain (e.g. server2.example.com).  This
     208restriction can be removed by setting :setting:`CSRF_COOKIE_DOMAIN` to be
     209something like ``".example.com"``.
     210
     211Please note that, with or without use of this setting, this CSRF protection
     212mechanism is not safe against cross-subdomain attacks -- see `Limitations`_.
     213
     214Rejected requests
     215=================
     216
     217By default, a '403 Forbidden' response is sent to the user if an incoming
     218request fails the checks performed by ``CsrfViewMiddleware``.  This should
     219usually only be seen when there is a genuine Cross Site Request Forgery, or
     220when, due to a programming error, the CSRF token has not been included with a
     221POST form.
     222
     223No logging is done, and the error message is not very friendly, so you may want
     224to provide your own page for handling this condition.  To do this, simply set
     225the :setting:`CSRF_FAILURE_VIEW` setting to a dotted path to your own view
     226function.
    67227
    68228How it works
    69229============
    70230
    71 CsrfMiddleware does two things:
     231The CSRF protection is based on the following things:
    72232
    73 1. It modifies outgoing requests by adding a hidden form field to all
    74    'POST' forms, with the name 'csrfmiddlewaretoken' and a value which is
    75    a hash of the session ID plus a secret. If there is no session ID set,
    76    this modification of the response isn't done, so there is very little
    77    performance penalty for those requests that don't have a session.
    78    (This is done by ``CsrfResponseMiddleware``).
     2331. A CSRF cookie that is set to a random value (a session independent nonce, as
     234   it is called), which other sites will not have access to.
    79235
    80 2. On all incoming POST requests that have the session cookie set, it
    81    checks that the 'csrfmiddlewaretoken' is present and correct. If it
    82    isn't, the user will get a 403 error. (This is done by
    83    ``CsrfViewMiddleware``)
     236   This cookie is set by ``CsrfViewMiddleware``.  It is meant to be permanent,
     237   but since there is no way to set a cookie that never expires, it is sent with
     238   every response that has called ``django.contrib.csrf.middleware.get_token()``
     239   (the function used internally to retrieve the CSRF token).
    84240
    85 This ensures that only forms that have originated from your Web site
    86 can be used to POST data back.
     2412. A hidden form field with the name 'csrfmiddlewaretoken' present in all
     242   outgoing POST forms.  The value of this field is the value of the CSRF
     243   cookie.
     244
     245   This part is done by the template tag (and with the legacy method, it is done
     246   by ``CsrfResponseMiddleware``).
     247
     2483. For all incoming POST requests, a CSRF cookie must be present, and the
     249   'csrfmiddlewaretoken' field must be present and correct. If it isn't, the
     250   user will get a 403 error.
     251
     252   This check is done by ``CsrfViewMiddleware``.
     253
     2544. In addition, for HTTPS requests, strict referer checking is done by
     255   ``CsrfViewMiddleware``.  This is necessary to address a Man-In-The-Middle
     256   attack that is possible under HTTPS when using a session independent nonce,
     257   due to the fact that HTTP 'Set-Cookie' headers are (unfortunately) accepted
     258   by clients that are talking to a site under HTTPS.  (Referer checking is not
     259   done for HTTP requests, because under HTTP, the presence of the Referer
     260   header is not reliable enough.)
     261
     262This ensures that only forms that have originated from your Web site can be used
     263to POST data back.
    87264
    88265It deliberately only targets HTTP POST requests (and the corresponding POST
    89 forms). GET requests ought never to have any potentially dangerous side
    90 effects (see `9.1.1 Safe Methods, HTTP 1.1, RFC 2616`_), and so a
    91 CSRF attack with a GET request ought to be harmless.
    92 
    93 POST requests that are not accompanied by a session cookie are not protected,
    94 but they do not need to be protected, since the 'attacking' Web site
    95 could make these kind of requests anyway.
    96 
    97 The Content-Type is checked before modifying the response, and only
    98 pages that are served as 'text/html' or 'application/xml+xhtml'
    99 are modified.
     266forms). GET requests ought never to have any potentially dangerous side effects
     267(see `9.1.1 Safe Methods, HTTP 1.1, RFC 2616`_), and so a CSRF attack with a GET
     268request ought to be harmless.
    100269
    101270The middleware tries to be smart about requests that come in via AJAX. Many
    102271JavaScript toolkits send an "X-Requested-With: XMLHttpRequest" HTTP header;
    103272these requests are detected and automatically *not* handled by this middleware.
    104273We can do this safely because, in the context of a browser, the header can only
    105274be added by using ``XMLHttpRequest``, and browsers already implement a
    106 same-domain policy for ``XMLHttpRequest``. (Note that this is not secure if you
    107 don't trust content within the same domain or subdomains.)
     275same-domain policy for ``XMLHttpRequest``.
    108276
     277``CsrfResponseMiddleware`` checks the Content-Type before modifying the
     278response, and only pages that are served as 'text/html' or
     279'application/xml+xhtml' are modified.
    109280
    110281.. _9.1.1 Safe Methods, HTTP 1.1, RFC 2616: http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
    111282
    112283Limitations
    113284===========
    114285
    115 CsrfMiddleware requires Django's session framework to work. If you have
    116 a custom authentication system that manually sets cookies and the like,
    117 it won't help you.
     286Subdomains within a site will be able to set cookies on the client for the whole
     287domain.  By setting the cookie and using a corresponding token, subdomains will
     288be able to circumvent the CSRF protection.  The only way to avoid this is to
     289ensure that subdomains are controlled by trusted users (or, are at least unable
     290to set cookies).  Note that even without CSRF, there are other vulnerabilities,
     291such as session fixation, that make giving subdomains to untrusted parties a bad
     292idea, and these vulnerabilities cannot easily be fixed with current browsers.
    118293
    119 If your app creates HTML pages and forms in some unusual way, (e.g.
    120 it sends fragments of HTML in JavaScript document.write statements)
    121 you might bypass the filter that adds the hidden field to the form,
    122 in which case form submission will always fail.  It may still be possible
    123 to use the middleware, provided you can find some way to get the
    124 CSRF token and ensure that is included when your form is submitted.
     294If you are using ``CsrfResponseMiddleware`` and your app creates HTML pages and
     295forms in some unusual way, (e.g.  it sends fragments of HTML in JavaScript
     296document.write statements) you might bypass the filter that adds the hidden
     297field to the form, in which case form submission will always fail.  You should
     298use the template tag or :meth:`django.contrib.csrf.middleware.get_token` to get
     299the CSRF token and ensure that is included when your form is submitted.
  • docs/ref/settings.txt

    diff -r 1b4df7524b7c docs/ref/settings.txt
    a b  
    144144The default number of seconds to cache a page when the caching middleware or
    145145``cache_page()`` decorator is used.
    146146
     147.. setting:: CSRF_COOKIE_NAME
     148
     149CSRF_COOKIE_NAME
     150----------------
     151Default: ``'csrftoken'``
     152
     153The name of the cookie to use for the CSRF authentication token. This can be whatever you
     154want.  See :ref:`ref-contrib-csrf`.
     155
     156.. setting:: CSRF_COOKIE_DOMAIN
     157
     158CSRF_COOKIE_DOMAIN
     159------------------
     160
     161Default: ``None``
     162
     163The domain to be used when setting the CSRF cookie.  This can be useful for
     164allowing cross-subdomain requests to be exluded from the normal cross site
     165request forgery protection.  It should be set to a string such as
     166``".lawrence.com"`` to allow a POST request from a form on one subdomain to be
     167accepted by accepted by a view served from another subdomain.
     168
     169.. setting:: CSRF_FAILURE_VIEW
     170
     171CSRF_FAILURE_VIEW
     172-----------------
     173
     174Default: ``'django.contrib.csrf.views.csrf_failure'``
     175
     176A dotted path to the view function to be used when an incoming request
     177is rejected by the CSRF protection. See :ref:`ref-contrib-csrf`.
     178
    147179.. setting:: DATABASE_ENGINE
    148180
    149181DATABASE_ENGINE
     
    751783
    752784    ('django.middleware.common.CommonMiddleware',
    753785     'django.contrib.sessions.middleware.SessionMiddleware',
     786     'django.contrib.csrf.middleware.CsrfViewMiddleware',
    754787     'django.contrib.auth.middleware.AuthenticationMiddleware',)
    755788
    756789A tuple of middleware classes to use. See :ref:`topics-http-middleware`.
  • docs/ref/templates/api.txt

    diff -r 1b4df7524b7c docs/ref/templates/api.txt
    a b  
    311311    ("django.core.context_processors.auth",
    312312    "django.core.context_processors.debug",
    313313    "django.core.context_processors.i18n",
    314     "django.core.context_processors.media")
     314    "django.core.context_processors.media",
     315    "django.contrib.csrf.context_processors.csrf")
    315316
    316317Each processor is applied in order. That means, if one processor adds a
    317318variable to the context and a second processor adds a variable with the same
     
    404405``RequestContext`` will contain a variable ``MEDIA_URL``, providing the
    405406value of the :setting:`MEDIA_URL` setting.
    406407
     408django.contrib.csrf.context_processors.csrf
     409~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     410
     411.. versionadded:: 1.2
     412
     413This processor adds a token that is needed by the ``csrf_token`` template tag
     414for protection against :ref:`Cross Site Request Forgeries <ref-contrib-csrf>`.
     415
    407416django.core.context_processors.request
    408417~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    409418
  • docs/topics/http/middleware.txt

    diff -r 1b4df7524b7c docs/topics/http/middleware.txt
    a b  
    2929    MIDDLEWARE_CLASSES = (
    3030        'django.middleware.common.CommonMiddleware',
    3131        'django.contrib.sessions.middleware.SessionMiddleware',
     32        'django.contrib.csrf.middleware.CsrfViewMiddleware',
    3233        'django.contrib.auth.middleware.AuthenticationMiddleware',
    3334    )
    3435
  • tests/regressiontests/admin_views/tests.py

    diff -r 1b4df7524b7c tests/regressiontests/admin_views/tests.py
    a b  
    874874        # 4 action inputs (3 regular checkboxes, 1 checkbox to select all)
    875875        # main form submit button = 1
    876876        # search field and search submit button = 2
    877         # 6 + 2 + 1 + 2 = 11 inputs
     877        # 6 + 2 + 4 + 1 + 2 + 1 = 15 inputs
    878878        self.failUnlessEqual(response.content.count("<input"), 15)
    879879        # 1 select per object = 3 selects
    880880        self.failUnlessEqual(response.content.count("<select"), 4)
  • tests/runtests.py

    diff -r 1b4df7524b7c tests/runtests.py
    a b  
    3030    'django.contrib.sessions',
    3131    'django.contrib.comments',
    3232    'django.contrib.admin',
     33    'django.contrib.csrf',
    3334]
    3435
    3536def get_test_models():
Back to Top