Ticket #9977: csrf_template_tag_and_no_session_dep.2.diff

File csrf_template_tag_and_no_session_dep.2.diff, 65.2 KB (added by Luke Plant, 15 years ago)

Updated for r10617 and doc update

  • django/conf/project_template/settings.py

     
    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/conf/global_settings.py

     
    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
     
    303304MIDDLEWARE_CLASSES = (
    304305    'django.middleware.common.CommonMiddleware',
    305306    'django.contrib.sessions.middleware.SessionMiddleware',
     307    'django.contrib.csrf.middleware.CsrfViewMiddleware',
    306308    'django.contrib.auth.middleware.AuthenticationMiddleware',
    307309#     'django.middleware.http.ConditionalGetMiddleware',
    308310#     'django.middleware.gzip.GZipMiddleware',
     
    377379# The number of days a password reset link is valid for
    378380PASSWORD_RESET_TIMEOUT_DAYS = 3
    379381
     382########
     383# CSRF #
     384########
     385
     386# Dotted path to callable to be used as view when a request is
     387# rejected by the CSRF middleware.
     388CSRF_FAILURE_VIEW = 'django.contrib.csrf.views.csrf_failure'
     389
    380390###########
    381391# TESTING #
    382392###########
  • django/contrib/formtools/templates/formtools/preview.html

     
    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>
  • django/contrib/formtools/templates/formtools/form.html

     
    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/comments/templates/comments/approve.html

     
    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/preview.html

     
    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>
  • django/contrib/comments/templates/comments/delete.html

     
    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/form.html

     
    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

     
    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/flag.html

     
    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/admin/templates/admin/template_validator.html

     
    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/admin/change_list.html

     
    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_selected_confirmation.html

     
    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 }}" />
     
    3434    </div>
    3535    </form>
    3636{% endif %}
    37 {% endblock %}
    38  No newline at end of file
     37{% endblock %}
  • django/contrib/admin/templates/admin/auth/user/change_password.html

     
    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/login.html

     
    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/change_form.html

     
    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/delete_confirmation.html

     
    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/registration/password_reset_confirm.html

     
    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

     
    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/admin/templates/registration/password_change_form.html

     
    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/sites.py

     
    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.shortcuts import render_to_response
     
    156157            raise ImproperlyConfigured("Put 'django.contrib.admin' in your INSTALLED_APPS setting in order to use the admin application.")
    157158        if not ContentType._meta.installed:
    158159            raise ImproperlyConfigured("Put 'django.contrib.contenttypes' in your INSTALLED_APPS setting in order to use the admin application.")
     160        if 'django.contrib.csrf' not in settings.INSTALLED_APPS:
     161            raise ImproperlyConfigured("Put 'django.contrib.csrf' in your INSTALLED_APPS setting in order to use the admin application.")
    159162        if 'django.core.context_processors.auth' not in settings.TEMPLATE_CONTEXT_PROCESSORS:
    160163            raise ImproperlyConfigured("Put 'django.core.context_processors.auth' in your TEMPLATE_CONTEXT_PROCESSORS setting in order to use the admin application.")
     164        if 'django.contrib.csrf.context_processors.csrf' not in settings.TEMPLATE_CONTEXT_PROCESSORS:
     165            raise ImproperlyConfigured("Put 'django.contrib.csrf.context_processors.csrf' in your TEMPLATE_CONTEXT_PROCESSORS setting in order to use the admin application.")
    161166
    162167    def admin_view(self, view):
    163168        """
     
    182187            if not self.has_permission(request):
    183188                return self.login(request)
    184189            return view(request, *args, **kwargs)
    185         return update_wrapper(inner, view)
     190        inner = update_wrapper(inner, view)
     191        return csrf_response_exempt(inner)
    186192
    187193    def get_urls(self):
    188194        from django.conf.urls.defaults import patterns, url, include
  • django/contrib/csrf/middleware.py

     
    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):
     26def _get_failure_view():
     27    """
     28    Returns the view to be used for CSRF rejections
     29    """
     30    return get_callable(settings.CSRF_FAILURE_VIEW)
     31
     32# Use the system (hardware-based) random number generator if it exists.
     33if hasattr(random, 'SystemRandom'):
     34    randrange = random.SystemRandom().randrange
     35else:
     36    randrange = random.randrange
     37_MAX_CSRF_KEY = 18446744073709551616L     # 2 << 63
     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 _make_token(csrf_cookie):
     47    return md5_constructor("csrf-" + settings.SECRET_KEY + csrf_cookie).hexdigest()
     48
     49def _cookie_name():
     50    # Backwards-compatibility: derive the cookie name from SESSION_COOKIE_NAME, so if the
     51    # user has specified a unique session cookie, we use a unique CSRF cookie, too.
     52    return "csrf_%s" % settings.SESSION_COOKIE_NAME
     53
     54def get_token(request):
     55    """
     56    Returns the the CSRF token required for a POST form.
     57    """
     58    csrf_cookie = request.META.get("CSRF_COOKIE", None)
     59    # This function is called by the csrf_token template tag. So, we don't make
     60    # the CSRF middleware a requirement, otherwise people would have to change
     61    # their templates if they disabled the middleware or used @csrf_view_exempt
     62    if csrf_cookie is None:
     63        return None
     64
     65    return _make_token(csrf_cookie)
     66
    3067class CsrfViewMiddleware(object):
    3168    """
    3269    Middleware that requires a present and correct csrfmiddlewaretoken
    33     for POST requests that have an active session.
     70    for POST requests that have a CSRF cookie, and sets an outgoing
     71    CSRF cookie.
     72
     73    This middleware should be used in conjunction with the csrf_token template
     74    tag.
    3475    """
    3576    def process_view(self, request, callback, callback_args, callback_kwargs):
     77        if getattr(callback, 'csrf_exempt', False):
     78            return None
     79
     80        # If the user doesn't have a CSRF cookie, generate one and store it in the
     81        # request, so it's available to the view.  We'll store it in a cookie when
     82        # we reach the response.
     83        try:
     84            request.META["CSRF_COOKIE"] = request.COOKIES[_cookie_name()]
     85            cookie_is_new = False
     86        except KeyError:
     87            # No cookie, so create one.
     88            request.META["CSRF_COOKIE"] = _get_new_csrf_key()
     89            cookie_is_new = True
     90
    3691        if request.method == 'POST':
    37             if getattr(callback, 'csrf_exempt', False):
    38                 return None
    39 
    4092            if request.is_ajax():
    4193                return None
    4294
    43             try:
    44                 session_id = request.COOKIES[settings.SESSION_COOKIE_NAME]
    45             except KeyError:
    46                 # No session, no check required
    47                 return None
     95            # If the user didn't already have a CSRF key, then accept the
     96            # session key for the middleware token, so CSRF protection isn't lost
     97            # for the period between upgrading to CSRF cookes to the first time
     98            # each user comes back to the site to receive one.
     99            if cookie_is_new:
     100                try:
     101                    session_id = request.COOKIES[settings.SESSION_COOKIE_NAME]
     102                    csrf_token = _make_legacy_session_token(session_id)
     103                except KeyError:
     104                    # No CSRF cookie and no session cookie; no check is performed.
     105                    return None
     106            else:
     107                csrf_cookie = request.META["CSRF_COOKIE"]
     108                csrf_token = _make_token(csrf_cookie)
    48109
    49             csrf_token = _make_token(session_id)
    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 _get_failure_view()(request)
    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        # Set the CSRF cookie even if it's already set, so we renew the expiry timer.
     125        response.set_cookie(_cookie_name(),
     126                request.META["CSRF_COOKIE"], max_age = 60 * 60 * 24 * 7 * 52,
     127                domain=settings.SESSION_COOKIE_DOMAIN,
     128                path=settings.SESSION_COOKIE_PATH)
     129
     130        return response
     131
    61132class CsrfResponseMiddleware(object):
    62133    """
    63     Middleware that post-processes a response to add a
    64     csrfmiddlewaretoken if the response/request have an active
    65     session.
     134    Middleware that post-processes a response to add a csrfmiddlewaretoken.
     135
     136    It is recommended to use the csrf_token template tag instead of
     137    this middleware.
    66138    """
    67139    def process_response(self, request, response):
    68140        if getattr(response, 'csrf_exempt', False):
    69141            return response
    70142
    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
     143        if response['Content-Type'].split(';')[0] in _HTML_TYPES:
     144            csrf_token = get_token(request)
     145            assert csrf_token is not None, 'META["CSRF_COOKIE"] is not set.'
    89146
    90         if csrf_token is not None and \
    91                 response['Content-Type'].split(';')[0] in _HTML_TYPES:
    92 
    93147            # ensure we don't add the 'id' attribute twice (HTML validity)
    94148            idattributes = itertools.chain(("id='csrfmiddlewaretoken'",),
    95                                             itertools.repeat(''))
     149                                           itertools.repeat(''))
    96150            def add_csrf_field(match):
    97151                """Returns the matched <form> tag plus the added <input> element"""
    98152                return mark_safe(match.group() + "<div style='display:none;'>" + \
     
    104158            response.content = _POST_FORM_RE.sub(add_csrf_field, response.content)
    105159        return response
    106160
    107 class CsrfMiddleware(CsrfViewMiddleware, CsrfResponseMiddleware):
     161class CsrfMiddleware(object):
    108162    """Django middleware that adds protection against Cross Site
    109163    Request Forgeries by adding hidden form fields to POST forms and
    110164    checking requests for the correct value.
    111165
    112     In the list of middlewares, SessionMiddleware is required, and
    113     must come after this middleware.  CsrfMiddleWare must come after
    114     compression middleware.
     166    CsrfMiddleware uses two middleware, CsrfViewMiddleware and
     167    CsrfResponseMiddleware, which can be used independently.  It is recommended
     168    to use only CsrfViewMiddleware and use the csrf_token template tag in
     169    templates for inserting the token.
     170    """
     171    # We can't just inherit from CsrfViewMiddleware and CsrfResponseMiddleware
     172    # because both have process_response methods.
     173    def __init__(self):
     174        self.response_middleware = CsrfResponseMiddleware()
     175        self.view_middleware = CsrfViewMiddleware()
    115176
    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.
     177    def process_response(self, request, resp):
     178        # We must do the cookie setting before the post-processing
     179        resp2 = self.view_middleware.process_response(request, resp)
     180        return self.response_middleware.process_response(request, resp2)
    120181
    121     If you are setting cookies directly, instead of using Django's
    122     session framework, this middleware will not work.
     182    def process_view(self, request, callback, callback_args, callback_kwargs):
     183        return self.view_middleware.process_view(request, callback, callback_args,
     184                                                 callback_kwargs)
    123185
    124     CsrfMiddleWare is composed of two middleware, CsrfViewMiddleware
    125     and CsrfResponseMiddleware which can be used independently.
    126     """
    127     pass
    128 
    129186def csrf_response_exempt(view_func):
    130187    """
    131188    Modifies a view function so that its response is exempt
  • 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>Cross Site Request Forgery detected. 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/csrf/tests.py

    Property changes on: django/contrib/csrf/views.py
    ___________________________________________________________________
    Added: svn:eol-style
       + native
    
     
    22
    33from django.test import TestCase
    44from django.http import HttpRequest, HttpResponse, HttpResponseForbidden
    5 from django.contrib.csrf.middleware import CsrfMiddleware, _make_token, csrf_exempt
     5from django.contrib.csrf.middleware import CsrfMiddleware, CsrfViewMiddleware, _make_token, _cookie_name, 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):
    1625    return post_form_response()
    1726
     27# Response/views used for template tag tests
     28def _token_template():
     29    return Template("{% load csrf %}{% csrf_token %}")
     30
     31def _render_csrf_token_template(req):
     32    context = RequestContext(req, processors=[csrf])
     33    template = _token_template()
     34    return template.render(context)
     35
     36def token_view(request):
     37    return HttpResponse(_render_csrf_token_template(request))
     38
    1839class CsrfMiddlewareTest(TestCase):
     40    _csrf_id = "1"
    1941
     42    # This is a valid session token for this ID and secret key.  This was generated using
     43    # the old code that we're to be backwards-compatible with.  Don't use the CSRF code
     44    # to generate this hash, or we're merely testing the code against itself and not
     45    # checking backwards-compatibility.  This is also the output of (echo -n test1 | md5sum).
     46    _session_token = "5a105e8b9d40e1329780d62ea2265d8a"
    2047    _session_id = "1"
     48    _secret_key_for_session_test= "test"
    2149
    22     def _get_GET_no_session_request(self):
     50    def _get_GET_no_csrf_cookie_request(self):
    2351        return HttpRequest()
    2452
    25     def _get_GET_session_request(self):
    26         req = self._get_GET_no_session_request()
    27         req.COOKIES[settings.SESSION_COOKIE_NAME] = self._session_id
     53    def _get_GET_csrf_cookie_request(self):
     54        req = HttpRequest()
     55        req.COOKIES[_cookie_name()] = self._csrf_id
    2856        return req
    2957
    30     def _get_POST_session_request(self):
    31         req = self._get_GET_session_request()
     58    def _get_POST_csrf_cookie_request(self):
     59        req = self._get_GET_csrf_cookie_request()
    3260        req.method = "POST"
    3361        return req
    3462
    35     def _get_POST_no_session_request(self):
    36         req = self._get_GET_no_session_request()
     63    def _get_POST_no_csrf_cookie_request(self):
     64        req = self._get_GET_no_csrf_cookie_request()
    3765        req.method = "POST"
    3866        return req
    3967
     68    def _get_POST_request_with_token(self):
     69        req = self._get_POST_csrf_cookie_request()
     70        req.POST['csrfmiddlewaretoken'] = _make_token(self._csrf_id)
     71        return req
     72
    4073    def _get_POST_session_request_with_token(self):
    41         req = self._get_POST_session_request()
    42         req.POST['csrfmiddlewaretoken'] = _make_token(self._session_id)
     74        req = self._get_POST_no_csrf_cookie_request()
     75        req.COOKIES[settings.SESSION_COOKIE_NAME] = self._session_id
     76        req.POST['csrfmiddlewaretoken'] = self._session_token
    4377        return req
    4478
    45     def _get_post_form_response(self):
    46         return post_form_response()
     79    def _get_POST_session_request_no_token(self):
     80        req = self._get_POST_no_csrf_cookie_request()
     81        req.COOKIES[settings.SESSION_COOKIE_NAME] = self._session_id
     82        return req
    4783
    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
     84    def _check_token_present(self, response, csrf_id=None):
     85        self.assertContains(response, "name='csrfmiddlewaretoken' value='%s'" % _make_token(csrf_id or self._csrf_id))
    5286
    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):
     87    # Check the post processing and outgoing cookie
     88    def test_process_response_no_csrf_cookie(self):
    6189        """
    62         Check the the post-processor does nothing if no session active
     90        When no prior CSRF cookie exists, check that the cookie is created and a
     91        token is inserted.
    6392        """
    64         req = self._get_GET_no_session_request()
    65         resp = self._get_post_form_response()
     93        req = self._get_GET_no_csrf_cookie_request()
     94        CsrfMiddleware().process_view(req, post_form_view, (), {})
     95
     96        resp = post_form_response()
    6697        resp_content = resp.content # needed because process_response modifies resp
    6798        resp2 = CsrfMiddleware().process_response(req, resp)
    68         self.assertEquals(resp_content, resp2.content)
    6999
    70     def test_process_response_existing_session(self):
     100        csrf_cookie = resp2.cookies.get(_cookie_name(), False)
     101        self.assertNotEqual(csrf_cookie, False)
     102        self.assertNotEqual(resp_content, resp2.content)
     103        self._check_token_present(resp2, csrf_cookie.value)
     104
     105    def test_process_response_no_csrf_cookie_view_only(self):
    71106        """
    72         Check that the token is inserted if there is an existing session
     107        When no prior CSRF cookie exists, check that the cookie is created, even
     108        if only CsrfViewMiddleware is used.
    73109        """
    74         req = self._get_GET_session_request()
    75         resp = self._get_post_form_response()
     110        # The CsrfViewMiddleware must have the cookie setting code.
     111        req = self._get_GET_no_csrf_cookie_request()
     112        CsrfViewMiddleware().process_view(req, post_form_view, (), {})
     113        resp = post_form_view(req)
     114        resp2 = CsrfViewMiddleware().process_response(req, resp)
     115
     116        csrf_cookie = resp2.cookies.get(_cookie_name(), False)
     117        self.assertNotEqual(csrf_cookie, False)
     118
     119    def test_process_response_existing_csrf_cookie(self):
     120        """
     121        Check that the token is inserted when a prior CSRF cookie exists
     122        """
     123        req = self._get_GET_csrf_cookie_request()
     124        CsrfMiddleware().process_view(req, post_form_view, (), {})
     125
     126        resp = post_form_response()
    76127        resp_content = resp.content # needed because process_response modifies resp
    77128        resp2 = CsrfMiddleware().process_response(req, resp)
    78129        self.assertNotEqual(resp_content, resp2.content)
    79130        self._check_token_present(resp2)
    80131
    81     def test_process_response_new_session(self):
     132    def test_process_response_non_html(self):
    82133        """
    83134        Check that the token is inserted if there is a new session being started
     135        Check the the post-processor does nothing for content-types not in _HTML_TYPES.
    84136        """
    85         req = self._get_GET_no_session_request() # no session in request
    86         resp = self._get_new_session_response() # but new session started
     137        req = self._get_GET_no_csrf_cookie_request()
     138        CsrfMiddleware().process_view(req, post_form_view, (), {})
     139        resp = post_form_response_non_html()
    87140        resp_content = resp.content # needed because process_response modifies resp
    88141        resp2 = CsrfMiddleware().process_response(req, resp)
    89         self.assertNotEqual(resp_content, resp2.content)
    90         self._check_token_present(resp2)
     142        self.assertEquals(resp_content, resp2.content)
    91143
    92144    def test_process_response_exempt_view(self):
    93145        """
    94146        Check that no post processing is done for an exempt view
    95147        """
    96         req = self._get_POST_session_request()
    97         resp = csrf_exempt(self.get_view())(req)
     148        req = self._get_POST_csrf_cookie_request()
     149        resp = csrf_exempt(post_form_view)(req)
    98150        resp_content = resp.content
    99151        resp2 = CsrfMiddleware().process_response(req, resp)
    100152        self.assertEquals(resp_content, resp2.content)
    101153
    102154    # Check the request processing
    103     def test_process_request_no_session(self):
     155    def test_process_request_no_session_no_csrf_cookie(self):
    104156        """
    105         Check that if no session is present, the middleware does nothing.
    106         to the incoming request.
     157        Check that if neither a CSRF cookie nor a session cookie are present, the
     158        middleware does nothing to the incoming request.
    107159        """
    108         req = self._get_POST_no_session_request()
    109         req2 = CsrfMiddleware().process_view(req, self.get_view(), (), {})
     160        req = self._get_POST_no_csrf_cookie_request()
     161        req2 = CsrfMiddleware().process_view(req, post_form_view, (), {})
    110162        self.assertEquals(None, req2)
    111163
    112     def test_process_request_session_no_token(self):
     164    def test_process_request_csrf_cookie_no_token(self):
    113165        """
    114         Check that if a session is present but no token, we get a 'forbidden'
     166        Check that if a CSRF cookie is present but no token, we get a 'forbidden'.
    115167        """
    116         req = self._get_POST_session_request()
    117         req2 = CsrfMiddleware().process_view(req, self.get_view(), (), {})
     168        req = self._get_POST_csrf_cookie_request()
     169        req2 = CsrfMiddleware().process_view(req, post_form_view, (), {})
    118170        self.assertEquals(HttpResponseForbidden, req2.__class__)
    119171
    120     def test_process_request_session_and_token(self):
     172    def test_process_request_csrf_cookie_and_token(self):
    121173        """
    122         Check that if a session is present and a token, the middleware lets it through
     174        Check that if both a cookie and a token is present, the middleware lets it through.
    123175        """
    124         req = self._get_POST_session_request_with_token()
    125         req2 = CsrfMiddleware().process_view(req, self.get_view(), (), {})
     176        req = self._get_POST_request_with_token()
     177        req2 = CsrfMiddleware().process_view(req, post_form_view, (), {})
    126178        self.assertEquals(None, req2)
    127179
    128     def test_process_request_session_no_token_exempt_view(self):
     180    def test_process_request_session_cookie_no_csrf_cookie_token(self):
    129181        """
    130         Check that if a session is present and no token, but the csrf_exempt
     182        When no CSRF cookie exists, but the user has a session, check that a token
     183        using the session cookie as a legacy CSRF cookie is accepted.
     184        """
     185        orig_secret_key = settings.SECRET_KEY
     186        settings.SECRET_KEY = self._secret_key_for_session_test
     187        try:
     188            req = self._get_POST_session_request_with_token()
     189            req2 = CsrfMiddleware().process_view(req, post_form_view, (), {})
     190            self.assertEquals(None, req2)
     191        finally:
     192            settings.SECRET_KEY = orig_secret_key
     193
     194    def test_process_request_session_cookie_no_csrf_cookie_no_token(self):
     195        """
     196        Check that if a session cookie is present but no token and no CSRF cookie,
     197        we get a 'forbidden'.
     198        """
     199        req = self._get_POST_session_request_no_token()
     200        req2 = CsrfMiddleware().process_view(req, post_form_view, (), {})
     201        self.assertEquals(HttpResponseForbidden, req2.__class__)
     202
     203    def test_process_request_csrf_cookie_no_token_exempt_view(self):
     204        """
     205        Check that if a CSRF cookie is present and no token, but the csrf_exempt
    131206        decorator has been applied to the view, the middleware lets it through
    132207        """
    133         req = self._get_POST_session_request()
    134         req2 = CsrfMiddleware().process_view(req, csrf_exempt(self.get_view()), (), {})
     208        req = self._get_POST_csrf_cookie_request()
     209        req2 = CsrfMiddleware().process_view(req, csrf_exempt(post_form_view), (), {})
    135210        self.assertEquals(None, req2)
    136211
    137212    def test_ajax_exemption(self):
    138213        """
    139214        Check that AJAX requests are automatically exempted.
    140215        """
    141         req = self._get_POST_session_request()
     216        req = self._get_POST_csrf_cookie_request()
    142217        req.META['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
    143         req2 = CsrfMiddleware().process_view(req, self.get_view(), (), {})
     218        req2 = CsrfMiddleware().process_view(req, post_form_view, (), {})
    144219        self.assertEquals(None, req2)
     220
     221    # Tests for the template tag method
     222    def test_token_node_no_csrf_cookie(self):
     223        """
     224        Check that CsrfTokenNode works when no CSRF cookie is set
     225        """
     226        req = self._get_GET_no_csrf_cookie_request()
     227        resp = token_view(req)
     228        self.assertEquals(u"", resp.content)
     229
     230    def test_token_node_with_csrf_cookie(self):
     231        """
     232        Check that CsrfTokenNode works when a CSRF cookie is set
     233        """
     234        req = self._get_GET_csrf_cookie_request()
     235        CsrfViewMiddleware().process_view(req, token_view, (), {})
     236        resp = token_view(req)
     237        self._check_token_present(resp)
     238
     239    def test_token_node_with_new_csrf_cookie(self):
     240        """
     241        Check that CsrfTokenNode works when a CSRF cookie is created by
     242        the middleware (when one was not already present)
     243        """
     244        req = self._get_GET_no_csrf_cookie_request()
     245        CsrfViewMiddleware().process_view(req, token_view, (), {})
     246        resp = token_view(req)
     247        resp2 = CsrfViewMiddleware().process_response(req, resp)
     248        csrf_cookie = resp2.cookies[_cookie_name()]
     249        self._check_token_present(resp, csrf_id=csrf_cookie.value)
  • 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.")
     21            return u''
     22
     23def csrf_token(parser, token):
     24    return CsrfTokenNode()
     25register.tag(csrf_token)
  • django/contrib/csrf/templatetags/__init__.py

    Property changes on: django/contrib/csrf/templatetags/csrf.py
    ___________________________________________________________________
    Added: svn:eol-style
       + native
    
     
     1
  • django/contrib/csrf/context_processors.py

    Property changes on: django/contrib/csrf/templatetags/__init__.py
    ___________________________________________________________________
    Added: svn:eol-style
       + native
    
     
     1from django.contrib.csrf.middleware import get_token
     2from django.utils.functional import memoize
     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 = memoize(_get_val, {}, 0)
     19
     20    return {'csrf_token': _get_val() }
  • tests/regressiontests/admin_views/tests.py

    Property changes on: django/contrib/csrf/context_processors.py
    ___________________________________________________________________
    Added: svn:eol-style
       + native
    
     
    811811        # 4 action inputs (3 regular checkboxes, 1 checkbox to select all)
    812812        # main form submit button = 1
    813813        # search field and search submit button = 2
    814         # 6 + 2 + 1 + 2 = 11 inputs
    815         self.failUnlessEqual(response.content.count("<input"), 15)
     814        # csrf hidden field = 1
     815        # 6 + 2 + 4 + 1 + 2 + 1 = 16 inputs
     816        self.failUnlessEqual(response.content.count("<input"), 16)
    816817        # 1 select per object = 3 selects
    817818        self.failUnlessEqual(response.content.count("<select"), 4)
    818819
  • tests/runtests.py

     
    3030    'django.contrib.sessions',
    3131    'django.contrib.comments',
    3232    'django.contrib.admin',
     33    'django.contrib.csrf',
    3334]
    3435
    3536def get_test_models():
  • AUTHORS

     
    463463    Gasper Zejn <zejn@kiberpipa.org>
    464464    Jarek Zgoda <jarek.zgoda@gmail.com>
    465465    Cheng Zhang
     466    Glenn
     467    bthomas
    466468
    467469A big THANK YOU goes to:
    468470
  • docs/topics/http/middleware.txt

     
    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
  • docs/ref/contrib/csrf.txt

     
    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.
    1515
    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.
     16The first defense against CSRF attacks is to ensure that GET requests are
     17side-effect free.  POST requests can then be protected by adding these
     18middleware into your list of installed middleware following the steps below.
    1919
     20.. versionadded:: 1.1
     21    The 'contrib' apps, including the admin, depend on the functionality
     22    described here. Anyone upgrading from earlier versions should read
     23    the `Upgrading notes`_ carefully.
     24
    2025.. _Cross Site Request Forgeries: http://www.squarefree.com/securitytips/web-developers.html#CSRF
    2126
    2227How to use it
    2328=============
    2429
    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.
     30.. versionchanged:: 1.1
     31    The template tag functionality (the recommended way to use this) was added
     32    in version 1.1. The previous method (still available) is described under
     33    `Legacy method`_.
    3134
    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``.
     35To enable CSRF protection for your views, follow these steps:
    3736
    38 .. versionchanged:: 1.1
    39     (previous versions of Django did not provide these two components
    40     of ``CsrfMiddleware`` as described above)
     37    1. Add the middleware
     38       ``'django.contrib.csrf.middleware.CsrfViewMiddleware'`` to your list of
     39       middleware classes, :setting:`MIDDLEWARE_CLASSES`.  (Currently it can
     40       come anywhere in the list with respect to other middleware included in
     41       Django.  It should come before any view middleware that assume that CSRF
     42       attacks have been dealt with.)
    4143
     44    2. Add ``'django.contrib.csrf'`` to your :setting:`INSTALLED_APPS`.
     45
     46    3. In any template that uses a POST form, first load the 'csrf' template tag
     47       library::
     48
     49           {% load csrf %}
     50
     51       Then use the ``csrf_token`` tag inside the ``<form>`` element, e.g.::
     52
     53           <form action="" method="POST">{% csrf_token %}
     54
     55    4. In the corresponding view functions, ensure that the
     56       ``'django.contrib.csrf.context_processors.csrf'`` is being used. Usually,
     57       this can be done in one of two ways:
     58
     59       1. Using RequestContext:
     60
     61          1. Ensure ``'django.contrib.csrf.context_processors.csrf'`` is present
     62             in your :setting:`TEMPLATE_CONTEXT_PROCESSORS` setting. It is
     63             present by default.
     64
     65          2. Use ``RequestContext`` as the context instance in the relevant
     66             views. If you are using generic views or contrib apps, you are
     67             covered already.
     68
     69       2. Manually import and use the processor to generate the CSRF token and
     70          add it to the template context. e.g.::
     71
     72              from django.contrib.csrf.context_processors import csrf
     73              from django.template import Context
     74              from django.shortcuts import render_to_response
     75              def my_view(request):
     76                  c = Context()
     77                  c.update(csrf(request))
     78                  return render_to_response("a_template.html", context_instance=c)
     79
     80Legacy method
     81-------------
     82
     83In Django 1.0, the template tag did not exist.  Instead, a post-processing
     84middleware that re-wrote POST forms to include the CRSF token was used.  If you
     85are upgrading a site from version 1.0 or earlier, please read this section and
     86the `Upgrading notes`_ below.  The post-processing middleware is still available
     87as ``CsrfResponseMiddleware``, and it can be used by following these steps:
     88
     89    1. Follow step 1 above to install ``CsrfViewMiddleware``.
     90
     91    2. Add ``'django.contrib.csrf.middleware.CsrfResponseMiddleware'`` to your
     92       :setting:`MIDDLEWARE_CLASSES` setting.
     93
     94       ``CsrfResponseMiddleware`` needs to process the response before things
     95       like compression happen to the response, so it must come after
     96       ``GZipMiddleware`` in the list.
     97
     98Use of the ``CsrfResponseMiddleware`` is not recommended, but it can be used as
     99an interim measure until applications have been updated to use the ``{%
     100crsf_token %}`` tag.
     101
     102Django 1.0 provided a single ``CsrfMiddleware`` class.  This is also still
     103available for backwards compatibility.  It combines the functions of the two new
     104middleware.
     105
     106Note also that previous versions of these classes depended on the sessions
     107framework, but this dependency has now been removed, with backward compatibility
     108support so that upgrading will not produce any issues.
     109
     110Upgrading notes
     111---------------
     112
     113When upgrading to version 1.1 or later, you may have applications that rely on
     114the old post-processing functionality for CSRF protection, or you may not have
     115enabled any CSRF protection.  This section outlines the steps necessary for a
     116smooth upgrade, without having to fix all the applications to use the new
     117template tag method immediately.
     118
     119If you are using any of the contrib apps (such as the admin), there are some
     120required steps for these applications to continue working. First, the CSRF
     121application must be added to :setting:`INSTALLED_APPS` (See `How to use it`_
     122above, step 2).  Second, the :setting:`TEMPLATE_CONTEXT_PROCESSORS` setting must
     123be updated (step 4.1.1 above).
     124
     125If you have ``CsrfMiddleware`` in your :setting:`MIDDLEWARE_CLASSES`, you will now
     126have a working installation with CSRF protection.  It is recommended at this
     127point that you replace ``CsrfMiddleware`` with its two components,
     128``CsrfViewMiddleware`` and ``CsrfResponseMiddleware``.
     129
     130If you do not have any of the middleware in your :setting:`MIDDLEWARE_CLASSES`,
     131you will have a working installation but without any CSRF protection (just as
     132you had before). It is recommended to install ``CsrfViewMiddleware`` and
     133``CsrfResponseMiddleware``, but if you are not interested in having any CSRF
     134protection, you can simply stop here.
     135
     136Assuming you have followed the above, all views in your Django site will now be
     137protected by the ``CsrfViewMiddleware``.  Contrib apps meet the requirements
     138imposed by the ``CsrfViewMiddleware`` using the template tag, and other
     139applications in your project will meet its requirements by virtue of the
     140``CsrfResponseMiddleware``.
     141
     142The next step is to update all your applications to use the template tag, as
     143described in `How to use it`_, steps 3-4.  This can be done as soon as is
     144practical. Any applications that are updated will now require Django 1.1 or
     145later, since they will use the CSRF template tag library which was not available
     146in earlier versions.
     147
     148Finally, once all applications are upgraded, ``CsrfResponseMiddleware`` can be
     149removed from your settings.
     150
     151While ``CsrfResponseMiddleware`` is still in use, the ``csrf_response_exempt``
     152decorator, described in `Exceptions`_, may be useful.  The post-processing
     153middleware imposes a performance hit, and any views that have been upgraded to
     154use the new template tag method no longer need it.  Using this decorator will
     155allow you to avoid this performance hit.
     156
    42157Exceptions
    43158----------
    44159
    45160.. versionadded:: 1.1
    46161
    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::
     162To manually exclude a view function from being handled by either of the two CSRF
     163middleware, you can use the ``csrf_exempt`` decorator, found in the
     164``django.contrib.csrf.middleware`` module. For example::
    50165
    51166    from django.contrib.csrf.middleware import csrf_exempt
    52167
     
    54169        return HttpResponse('Hello world')
    55170    my_view = csrf_exempt(my_view)
    56171
    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.
     172Like the middleware, the ``csrf_exempt`` decorator is composed of two parts: a
     173``csrf_view_exempt`` decorator and a ``csrf_response_exempt`` decorator, found
     174in the same module.  These disable the view protection mechanism
     175(``CsrfViewMiddleware``) and the response post-processing
     176(``CsrfResponseMiddleware``) respectively.  They can be used individually if
     177required.
    63178
    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.)
     179You don't have to worry about doing this for most AJAX views. Any request sent
     180with "X-Requested-With: XMLHttpRequest" is automatically exempt. (See the next
     181section.)
    67182
     183Rejected requests
     184=================
     185
     186By default, a '403 Forbidden' response is sent to the user if an incoming
     187request fails the checks performed by ``CsrfViewMiddleware``.  This should
     188usually only be seen when there is a genuine Cross Site Request Forgery, or
     189when, due to a programming error, the CSRF token has not been included with a
     190POST form.
     191
     192No logging is done, and the error message is not very friendly, so you may want
     193to provide your own page for handling this condition.  To do this, simply set
     194the :setting:`CSRF_FAILURE_VIEW` setting to a dotted path to your own view
     195function.
     196
    68197How it works
    69198============
    70199
    71 CsrfMiddleware does two things:
     200The CSRF protection is based on three things:
    72201
    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``).
     2021. A CSRF cookie that is set to a random value, which other sites will not have
     203   access to.
    79204
    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``)
     205   This cookie is set by ``CsrfViewMiddleware``.
    84206
    85 This ensures that only forms that have originated from your Web site
    86 can be used to POST data back.
     2072. A hidden form field with the name 'csrfmiddlewaretoken' present in all
     208   outgoing POST forms.  The value of this field is a hash of the CSRF cookie
     209   plus a site-specific secret.
    87210
     211   This part is done by the template tag (and with the legacy method, it is done
     212   by ``CsrfResponseMiddleware``).
     213
     2143. For all incoming POST requests that have the CSRF cookie set, the
     215   'csrfmiddlewaretoken' must be present and correct. If it isn't, the user will
     216   get a 403 error.
     217
     218   This check is done by ``CsrfViewMiddleware``.
     219
     220This ensures that only forms that have originated from your Web site can be used
     221to POST data back.
     222
    88223It 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.
     224forms). GET requests ought never to have any potentially dangerous side effects
     225(see `9.1.1 Safe Methods, HTTP 1.1, RFC 2616`_), and so a CSRF attack with a GET
     226request ought to be harmless.
    92227
    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.
     228If the user has never visited the site before, and their browser makes a POST
     229request to the site, there will be no CSRF cookie, and no CSRF check will be
     230done. However, this is harmless, since if the user has never visited the site
     231before, they will not have any authentication that could be abused.
    96232
    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.
     233The Content-Type is checked before modifying the response, and only pages that
     234are served as 'text/html' or 'application/xml+xhtml' are modified.
    100235
    101236The middleware tries to be smart about requests that come in via AJAX. Many
    102237JavaScript toolkits send an "X-Requested-With: XMLHttpRequest" HTTP header;
     
    112247Limitations
    113248===========
    114249
    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.
    118 
    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.
     250If you are using ``CsrfResponseMiddleware`` and your app creates HTML pages and
     251forms in some unusual way, (e.g.  it sends fragments of HTML in JavaScript
     252document.write statements) you might bypass the filter that adds the hidden
     253field to the form, in which case form submission will always fail.  It may still
     254be possible to use this middleware, provided you use the template tag or
     255:meth:`django.contrib.csrf.middleware.get_token` to get the CSRF token and
     256ensure that is included when your form is submitted.
  • docs/ref/settings.txt

     
    146146
    147147.. setting:: DATABASE_ENGINE
    148148
     149CSRF_FAILURE_VIEW
     150-----------------
     151
     152Default: ``'django.contrib.csrf.views.csrf_failure'``
     153
     154The name of the view function to be used when an incoming request
     155is rejected by the CSRF protection. See :ref:`ref-contrib-csrf`.
     156
    149157DATABASE_ENGINE
    150158---------------
    151159
     
    762770
    763771    ('django.middleware.common.CommonMiddleware',
    764772     'django.contrib.sessions.middleware.SessionMiddleware',
     773     'django.contrib.csrf.middleware.CsrfViewMiddleware',
    765774     'django.contrib.auth.middleware.AuthenticationMiddleware',)
    766775
    767776A tuple of middleware classes to use. See :ref:`topics-http-middleware`.
Back to Top