Ticket #9977: csrf_template_tag_18.diff

File csrf_template_tag_18.diff, 61.9 KB (added by Luke Plant, 15 years ago)

Added docs about upgrading, used csrf_response_exempt in admin, removed duplicated code

  • 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
     390# Some 'salt' to stop CSRF middleware being abused into generating and
     391# returning md5hash(SECRET_KEY + user supplied string).  This probably
     392# is not needed with built-in session backends. It does not matter if
     393# this setting is not changed in individual settings files, because
     394# the SECRET_KEY is also used for hashing.
     395CSRF_SALT = 'g7x2(s0$h!^^_ykw81nm383yl58#@lpkfw_yv_yf'
     396
    380397###########
    381398# TESTING #
    382399###########
  • 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/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/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/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
    1010try:
    1111    from functools import wraps
    1212except ImportError:
    1313    from django.utils.functional import wraps  # Python 2.3, 2.4 fallback.
    1414
    1515from django.conf import settings
    16 from django.http import HttpResponseForbidden
     16from django.core.urlresolvers import get_callable
    1717from django.utils.hashcompat import md5_constructor
    1818from django.utils.safestring import mark_safe
    1919
    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 
    2220_POST_FORM_RE = \
    2321    re.compile(r'(<form\W[^>]*\bmethod=(\'|"|)POST(\'|"|)\b[^>]*>)', re.IGNORECASE)
    2422
    2523_HTML_TYPES = ('text/html', 'application/xhtml+xml')
    2624
    27 def _make_token(session_id):
    28     return md5_constructor(settings.SECRET_KEY + session_id).hexdigest()
     25def _get_failure_view():
     26    """
     27    Returns the view to be used for CSRF rejections
     28    """
     29    return get_callable(settings.CSRF_FAILURE_VIEW)
    2930
     31def _get_validated_session_id(request):
     32    # This function is called by the csrf_token. So, we don't make the
     33    # session framework a requirement, otherwise people would have to change
     34    # their templates if they disabled the session middleware
     35    if hasattr(request, 'session'):
     36        if request.session.accessed or request.session.modified:
     37            # Could be a new session, need to use new session ID
     38            return request.session.session_key
     39        else:
     40            # Avoid use of session.session_key, which can trigger
     41            # unecessary work
     42            session_id = request.COOKIES.get(settings.SESSION_COOKIE_NAME, None)
     43            if session_id is not None and request.session.exists(session_id):
     44                return session_id
     45            else:
     46                return None # not a valid session
     47    return None
     48
     49def get_token(request, salt=None):
     50    """
     51    Returns the the CSRF token required for a session,
     52    or None if there is no session active.
     53
     54    'salt' parameter is designed for internal use only.
     55    """
     56    session_id = _get_validated_session_id(request)
     57    if session_id is None:
     58        # No session
     59        return None
     60    else:
     61        return _make_token(session_id, salt=salt)
     62
     63def _make_token(session_id, salt=None):
     64    # 'salt' was added in case the session_id is not validated by the
     65    # backend, which would create a potential vulnerability whereby an
     66    # attacker could generate md5hash(SECRETE_KEY + arbitrary string),
     67    # which could be useful to circumvent other protections.
     68    if salt is None:
     69        salt = settings.CSRF_SALT
     70
     71    return md5_constructor(settings.SECRET_KEY + salt + session_id).hexdigest()
     72
    3073class CsrfViewMiddleware(object):
    3174    """
    3275    Middleware that requires a present and correct csrfmiddlewaretoken
    3376    for POST requests that have an active session.
     77
     78    This middleware should be used in conjunction with the csrf_token template
     79    tag.
    3480    """
    3581    def process_view(self, request, callback, callback_args, callback_kwargs):
    3682        if request.method == 'POST':
     
    4086            if request.is_ajax():
    4187                return None
    4288
    43             try:
    44                 session_id = request.COOKIES[settings.SESSION_COOKIE_NAME]
    45             except KeyError:
     89            csrf_token = get_token(request)
     90            if csrf_token is None:
     91                # Coud happen if session middleware is disabled
     92                assert hasattr(request, 'session'), "The CSRF middleware requires the session middleware to be installed. Edit your MIDDLEWARE_CLASSES setting to add 'django.contrib.sessions.middleware.SessionMiddleware'."
    4693                # No session, no check required
    4794                return None
    4895
    49             csrf_token = _make_token(session_id)
    5096            # check incoming token
    5197            try:
    5298                request_csrf_token = request.POST['csrfmiddlewaretoken']
    5399            except KeyError:
    54                 return HttpResponseForbidden(_ERROR_MSG)
     100                return _get_failure_view()(request)
    55101
    56102            if request_csrf_token != csrf_token:
    57                 return HttpResponseForbidden(_ERROR_MSG)
     103                # Earlier versions of Django did not use 'salt' in
     104                # generating the token.  On upgrading, a form
     105                # generated by such a version will produce a
     106                # different token, so to avoid upgrade bumps, we
     107                # accept the old tokens
     108                old_csrf_token = get_token(request, salt="")
     109                if request_csrf_token != old_csrf_token:
     110                    return _get_failure_view()(request)
    58111
    59112        return None
    60113
     
    63116    Middleware that post-processes a response to add a
    64117    csrfmiddlewaretoken if the response/request have an active
    65118    session.
     119
     120    It is recommended to use the csrf_token template tag instead of
     121    this middleware.
    66122    """
    67123    def process_response(self, request, response):
    68124        if getattr(response, 'csrf_exempt', False):
     
    80136            csrf_token = _make_token(cookie.value)
    81137        except KeyError:
    82138            # Normal case - look for existing session cookie
    83             try:
    84                 session_id = request.COOKIES[settings.SESSION_COOKIE_NAME]
     139            session_id = _get_validated_session_id(request)
     140            if session_id is not None:
    85141                csrf_token = _make_token(session_id)
    86             except KeyError:
     142            else:
    87143                # no incoming or outgoing cookie
    88144                pass
    89145
    90146        if csrf_token is not None and \
    91                 response['Content-Type'].split(';')[0] in _HTML_TYPES:
     147            response['Content-Type'].split(';')[0] in _HTML_TYPES:
    92148
    93             # ensure we don't add the 'id' attribute twice (HTML validity)
    94             idattributes = itertools.chain(("id='csrfmiddlewaretoken'",),
    95                                             itertools.repeat(''))
     149        # ensure we don't add the 'id' attribute twice (HTML validity)
     150            idattributes = itertools.chain(("id='csrfmiddlewaretoken'", ),
     151                itertools.repeat(''))
    96152            def add_csrf_field(match):
    97153                """Returns the matched <form> tag plus the added <input> element"""
    98154                return mark_safe(match.group() + "<div style='display:none;'>" + \
     
    109165    Request Forgeries by adding hidden form fields to POST forms and
    110166    checking requests for the correct value.
    111167
    112     In the list of middlewares, SessionMiddleware is required, and
    113     must come after this middleware.  CsrfMiddleWare must come after
    114     compression middleware.
     168    CsrfMiddleWare is composed of two middleware, CsrfViewMiddleware
     169    and CsrfResponseMiddleware which can be used independently.
     170    It is recommended to use only CsrfViewMiddleware and use the
     171    csrf_token template tag in templates for inserting the token.
    115172
    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.
    120 
    121173    If you are setting cookies directly, instead of using Django's
    122174    session framework, this middleware will not work.
    123 
    124     CsrfMiddleWare is composed of two middleware, CsrfViewMiddleware
    125     and CsrfResponseMiddleware which can be used independently.
    126175    """
    127176    pass
    128177
     
    132181    from the post-processing of the CSRF middleware.
    133182    """
    134183    def wrapped_view(*args, **kwargs):
    135         resp = view_func(*args, **kwargs)
     184        resp = view_func( * args, ** kwargs)
    136185        resp.csrf_exempt = True
    137186        return resp
    138187    return wraps(view_func)(wrapped_view)
     
    145194    # are nicer if they don't have side-effects, so we return a new
    146195    # function.
    147196    def wrapped_view(*args, **kwargs):
    148         return view_func(*args, **kwargs)
     197        return view_func( * args, ** kwargs)
    149198    wrapped_view.csrf_exempt = True
    150199    return wraps(view_func)(wrapped_view)
    151200
  • 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
    
     
    33from django.test import TestCase
    44from django.http import HttpRequest, HttpResponse, HttpResponseForbidden
    55from django.contrib.csrf.middleware import CsrfMiddleware, _make_token, 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_view(request):
    1620    return post_form_response()
    1721
     22# Response/views used for template tag tests
     23def _token_template():
     24    return Template("{% load csrf %}{% csrf_token %}")
     25
     26def _render_csrf_token_template(req):
     27    context = RequestContext(req, processors=[csrf])
     28    template = _token_template()
     29    return template.render(context)
     30
     31def token_view(request):
     32    return HttpResponse(_render_csrf_token_template(request))
     33
     34def token_view_with_session_access(request):
     35    request.session["test value"] = "value"
     36    return HttpResponse(_render_csrf_token_template(request))
     37
     38def token_view_with_late_session_access(request):
     39    # This view creates RequestContext and *then* accesses the
     40    # session.  This will be problematic unless the csrf context
     41    # processor is lazy.
     42    assert not (request.session.accessed or request.session.modified)
     43    context = RequestContext(request, processors=[csrf])
     44    request.session["test value"] = "value"
     45    assert (request.session.accessed or request.session.modified)
     46    template = _token_template()
     47    return HttpResponse(template.render(context))
     48
     49def token_view_with_new_session(request):
     50    # View deliberately cycles the session key
     51    request.session.create()
     52    return HttpResponse(_render_csrf_token_template(request))
     53
    1854class CsrfMiddlewareTest(TestCase):
    1955
    20     _session_id = "1"
     56    def setUp(self, *args, **kwargs):
     57        super(CsrfMiddlewareTest, self).setUp(*args, **kwargs)
     58        # We have to create an actual session in the DB as the
     59        # middleware validates the session
     60        engine = import_module(settings.SESSION_ENGINE)
     61        s = engine.SessionStore(None)
     62        s.create()
     63        self._session_id = s.session_key
    2164
     65    def _apply_request_middleware(self, req):
     66        SessionMiddleware().process_request(req)
     67        return req
     68
    2269    def _get_GET_no_session_request(self):
    23         return HttpRequest()
     70        return self._apply_request_middleware(HttpRequest())
    2471
    2572    def _get_GET_session_request(self):
    26         req = self._get_GET_no_session_request()
     73        req = HttpRequest()
    2774        req.COOKIES[settings.SESSION_COOKIE_NAME] = self._session_id
    28         return req
     75        return self._apply_request_middleware(req)
    2976
    3077    def _get_POST_session_request(self):
    31         req = self._get_GET_session_request()
     78        req = HttpRequest()
     79        req.COOKIES[settings.SESSION_COOKIE_NAME] = self._session_id
    3280        req.method = "POST"
    33         return req
     81        return self._apply_request_middleware(req)
    3482
    3583    def _get_POST_no_session_request(self):
    36         req = self._get_GET_no_session_request()
     84        req = HttpRequest()
    3785        req.method = "POST"
    38         return req
     86        return self._apply_request_middleware(req)
    3987
    4088    def _get_POST_session_request_with_token(self):
    4189        req = self._get_POST_session_request()
    4290        req.POST['csrfmiddlewaretoken'] = _make_token(self._session_id)
    4391        return req
    4492
    45     def _get_post_form_response(self):
    46         return post_form_response()
    47 
    4893    def _get_new_session_response(self):
    49         resp = self._get_post_form_response()
     94        resp = post_form_response()
    5095        resp.cookies[settings.SESSION_COOKIE_NAME] = self._session_id
    5196        return resp
    5297
    5398    def _check_token_present(self, response):
    5499        self.assertContains(response, "name='csrfmiddlewaretoken' value='%s'" % _make_token(self._session_id))
    55100
    56     def get_view(self):
    57         return test_view
    58 
    59101    # Check the post processing
    60102    def test_process_response_no_session(self):
    61103        """
    62104        Check the the post-processor does nothing if no session active
    63105        """
    64106        req = self._get_GET_no_session_request()
    65         resp = self._get_post_form_response()
     107        resp = post_form_response()
    66108        resp_content = resp.content # needed because process_response modifies resp
    67109        resp2 = CsrfMiddleware().process_response(req, resp)
    68110        self.assertEquals(resp_content, resp2.content)
     
    72114        Check that the token is inserted if there is an existing session
    73115        """
    74116        req = self._get_GET_session_request()
    75         resp = self._get_post_form_response()
     117        resp = post_form_response()
    76118        resp_content = resp.content # needed because process_response modifies resp
    77119        resp2 = CsrfMiddleware().process_response(req, resp)
    78120        self.assertNotEqual(resp_content, resp2.content)
     
    94136        Check that no post processing is done for an exempt view
    95137        """
    96138        req = self._get_POST_session_request()
    97         resp = csrf_exempt(self.get_view())(req)
     139        resp = csrf_exempt(post_form_view)(req)
    98140        resp_content = resp.content
    99141        resp2 = CsrfMiddleware().process_response(req, resp)
    100142        self.assertEquals(resp_content, resp2.content)
     
    106148        to the incoming request.
    107149        """
    108150        req = self._get_POST_no_session_request()
    109         req2 = CsrfMiddleware().process_view(req, self.get_view(), (), {})
     151        req2 = CsrfMiddleware().process_view(req, post_form_view, (), {})
    110152        self.assertEquals(None, req2)
    111153
    112154    def test_process_request_session_no_token(self):
     
    114156        Check that if a session is present but no token, we get a 'forbidden'
    115157        """
    116158        req = self._get_POST_session_request()
    117         req2 = CsrfMiddleware().process_view(req, self.get_view(), (), {})
     159        req2 = CsrfMiddleware().process_view(req, post_form_view, (), {})
    118160        self.assertEquals(HttpResponseForbidden, req2.__class__)
    119161
    120162    def test_process_request_session_and_token(self):
     
    122164        Check that if a session is present and a token, the middleware lets it through
    123165        """
    124166        req = self._get_POST_session_request_with_token()
    125         req2 = CsrfMiddleware().process_view(req, self.get_view(), (), {})
     167        req2 = CsrfMiddleware().process_view(req, post_form_view, (), {})
    126168        self.assertEquals(None, req2)
    127169
     170    def test_process_request_old_token_compat(self):
     171        """
     172        Check that the view middleware accepts tokens generated by
     173        previous version of response middleware.
     174        """
     175        req = self._get_POST_session_request_with_token()
     176        # Previous versions did not use 'salt' in _make_token
     177        req.POST['csrfmiddlewaretoken'] = _make_token(self._session_id, salt="")
     178        req2 = CsrfMiddleware().process_view(req, post_form_view, (), {})
     179        self.assertEquals(None, req2)
     180
    128181    def test_process_request_session_no_token_exempt_view(self):
    129182        """
    130183        Check that if a session is present and no token, but the csrf_exempt
    131184        decorator has been applied to the view, the middleware lets it through
    132185        """
    133186        req = self._get_POST_session_request()
    134         req2 = CsrfMiddleware().process_view(req, csrf_exempt(self.get_view()), (), {})
     187        req2 = CsrfMiddleware().process_view(req, csrf_exempt(post_form_view), (), {})
    135188        self.assertEquals(None, req2)
    136189
    137190    def test_ajax_exemption(self):
     
    140193        """
    141194        req = self._get_POST_session_request()
    142195        req.META['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
    143         req2 = CsrfMiddleware().process_view(req, self.get_view(), (), {})
     196        req2 = CsrfMiddleware().process_view(req, post_form_view, (), {})
    144197        self.assertEquals(None, req2)
     198
     199    # Tests for the template tag method
     200    def test_token_node_no_session(self):
     201        """
     202        Check that CsrfTokenNode works when no session is active
     203        """
     204        req = self._get_GET_no_session_request()
     205        resp = token_view(req)
     206        self.assertEquals(u"", resp.content)
     207
     208    def test_token_node_with_session(self):
     209        """
     210        Check that CsrfTokenNode works when a session is active
     211        """
     212        req = self._get_GET_session_request()
     213        resp = token_view(req)
     214        self._check_token_present(resp)
     215
     216    def test_token_node_with_new_session(self):
     217        """
     218        Check that CsrfTokenNode works when a session is created by
     219        the view (when one was not already active)
     220        """
     221        req = self._get_GET_no_session_request()
     222        resp = token_view_with_session_access(req)
     223        # view will have caused new session to be created
     224        self._session_id = req.session.session_key
     225        self._check_token_present(resp)
     226
     227    def test_token_node_with_changed_session(self):
     228        """
     229        Check that CsrfTokenNode works when a session is deliberately
     230        created by the view (though one was already active)
     231        """
     232        req = self._get_GET_session_request()
     233        resp = token_view_with_new_session(req)
     234        # View will have modified session key
     235        self._session_id = req.session.session_key
     236        self._check_token_present(resp)
     237
     238    def test_token_node_with_modified_session_data(self):
     239        """
     240        Check that CsrfTokenNode works when session data is modified
     241        by the view
     242        """
     243        req = self._get_GET_session_request()
     244        resp = token_view_with_session_access(req)
     245        # View should not have modified session key
     246        self._check_token_present(resp)
     247
     248    def test_token_node_with_late_session_access(self):
     249        """
     250        Check that CsrfTokenNode works when a session is created by
     251        the view *after* the RequestContext has been created
     252        """
     253        req = self._get_GET_no_session_request()
     254        resp = token_view_with_late_session_access(req)
     255        # view will have caused new session to be created
     256        self._session_id = req.session.session_key
     257        self._check_token_present(resp)
     258
  • 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 lazy, 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 an empty dict.
     15            return 'NOTNEEDED'
     16        else:
     17            return token
     18    # We need to generate the value as late as possible, in case the
     19    # user creates RequestContext early in the view. But we also want
     20    # to memoize so that we don't call this many times.
     21    cache = {}
     22    _get_val = lazy(memoize(_get_val, cache, 0), str)
     23
     24    return {'csrf_token': _get_val() }
  • django/contrib/auth/views.py

    Property changes on: django/contrib/csrf/context_processors.py
    ___________________________________________________________________
    Added: svn:eol-style
       + native
    
     
    137137    else:
    138138        context_instance['validlink'] = False
    139139        form = None
    140     context_instance['form'] = form   
     140    context_instance['form'] = form
    141141    return render_to_response(template_name, context_instance=context_instance)
    142142
    143143def password_reset_complete(request, template_name='registration/password_reset_complete.html'):
  • django/contrib/auth/tests/views.py

     
    5353        # Let's munge the token in the path, but keep the same length,
    5454        # in case the URLconf will reject a different length.
    5555        path = path[:-5] + ("0"*4) + path[-1]
    56 
    5756        response = self.client.get(path)
    5857        self.assertEquals(response.status_code, 200)
    5958        self.assert_("The password reset link was invalid" in response.content)
  • tests/regressiontests/admin_views/tests.py

     
    803803        # 4 action inputs (3 regular checkboxes, 1 checkbox to select all)
    804804        # main form submit button = 1
    805805        # search field and search submit button = 2
    806         # 6 + 2 + 1 + 2 = 11 inputs
    807         self.failUnlessEqual(response.content.count("<input"), 15)
     806        # csrf hidden field = 1
     807        # 6 + 2 + 4 + 1 + 2 + 1 = 16 inputs
     808        self.failUnlessEqual(response.content.count("<input"), 16)
    808809        # 1 select per object = 3 selects
    809810        self.failUnlessEqual(response.content.count("<select"), 4)
    810811
  • 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():
  • 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
     80    5. Ensure that any code in a view which could create a new session executes
     81       **before** any templates containing a ``csrf_token`` tag are
     82       rendered. Note that sessions can be created implicitly simply by setting
     83       a value or accessing the contents.  If this is done after the template is
     84       rendered, the CSRF token it contains could be incorrect, and the
     85       following form submission will be rejected.
     86
     87Legacy method
     88-------------
     89
     90In Django 1.0, the template tag did not exist.  Instead, a post-processing
     91middleware that re-wrote POST forms to include the CRSF token was used.  If you
     92are upgrading a site from version 1.0 or earlier, please read this section and
     93the `Upgrading notes`_ below.  The post-processing middleware is still available
     94as ``CsrfResponseMiddleware``, and it can be used by following these steps:
     95
     96    1. Follow step 1 above to install ``CsrfViewMiddleware``.
     97
     98    2. Add ``'django.contrib.csrf.middleware.CsrfResponseMiddleware'`` to your
     99       :setting:`MIDDLEWARE_CLASSES` setting.
     100
     101       ``CsrfResponseMiddleware`` needs to process the response after the
     102       ``SessionMiddleware``, so must come before it in the list.  It also must
     103       process the response before things like compression happen to the
     104       response, so it must come after ``GZipMiddleware`` in the list.
     105
     106Use of the ``CsrfResponseMiddleware`` is not recommended, but it can be used as
     107an interim measure until applications have been updated to use the ``{%
     108crsf_token %}`` tag.
     109
     110Django 1.0 provided a single ``CsrfMiddleware`` class.  This is also still
     111available for backwards compatibility.  It combines the functions of the two new
     112middleware.
     113
     114Upgrading notes
     115---------------
     116
     117When upgrading to version 1.1 or later, you may have applications that rely on
     118the old post-processing functionality for CSRF protection, or you may not have
     119enabled any CSRF protection.  This section outlines the steps necessary for a
     120smooth upgrade, without having to fix all the applications to use the new
     121template tag method immediately.
     122
     123If you are using any of the contrib apps (such as the admin), there are some
     124required steps for these applications to continue working. First, the CSRF
     125application must be added to :setting:`INSTALLED_APPS` (See `How to use it`_
     126above, step 2).  Second, the :setting:`TEMPLATE_CONTEXT_PROCESSORS` setting must
     127be updated (step 4.1.1 above).
     128
     129If you have ``CsrfMiddleware`` in your :setting:`MIDDLEWARE_CLASSES`, you will now
     130have a working installation with CSRF protection.  It is recommended at this
     131point that you replace ``CsrfMiddleware`` with its two components,
     132``CsrfViewMiddleware`` and ``CsrfResponseMiddleware``.
     133
     134If you do not have any of the the middleware in your :setting:`MIDDLEWARE_CLASSES`,
     135you will have a working installation but without any CSRF protection (just as
     136you had before). It is recommended to install ``CsrfViewMiddleware`` and
     137``CsrfResponseMiddleware``, but if you are not interested in having any CSRF
     138protection, you can simply stop here.
     139
     140Assuming you have followed the above, all views in your Django site will now be
     141protected by the ``CsrfViewMiddleware``.  Contrib apps meet the requirements
     142imposed by the ``CsrfViewMiddleware`` using the template tag, and other
     143applications in your project will meet its requirements by virtue of the
     144``CsrfResponseMiddleware``.
     145
     146The next step is to update all your applications to use the template tag, as
     147described in `How to use it`_, steps 3-5.  This can be done as soon as is
     148practical. Any applications that are updated will now require Django 1.1 or
     149later, since they will use the CSRF template tag library which was not available
     150in earlier versions.
     151
     152Finally, once all applications are upgraded, the ``CsrfResponseMiddleware`` can
     153be removed.
     154
     155While in the process of upgrading, the ``csrf_response_exempt`` decorator,
     156described in `Exceptions`_, may be useful.  The post-processing middleware
     157imposes a performance hit, and any views that have been upgraded to use the new
     158template tag method no longer need it.  Using this decorator will allow you to
     159avoid this performance hit.
     160
    42161Exceptions
    43162----------
    44163
    45164.. versionadded:: 1.1
    46165
    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::
     166To manually exclude a view function from being handled by either of the two CSRF
     167middleware, you can use the ``csrf_exempt`` decorator, found in the
     168``django.contrib.csrf.middleware`` module. For example::
    50169
    51170    from django.contrib.csrf.middleware import csrf_exempt
    52171
     
    54173        return HttpResponse('Hello world')
    55174    my_view = csrf_exempt(my_view)
    56175
    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.
     176Like the middleware, the ``csrf_exempt`` decorator is composed of two parts: a
     177``csrf_view_exempt`` decorator and a ``csrf_response_exempt`` decorator, found
     178in the same module.  These disable the view protection mechanism
     179(``CsrfViewMiddleware``) and the response post-processing
     180(``CsrfResponseMiddleware``) respectively.  They can be used individually if
     181required.
    63182
    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.)
     183You don't have to worry about doing this for most AJAX views. Any request sent
     184with "X-Requested-With: XMLHttpRequest" is automatically exempt. (See the next
     185section.)
    67186
     187Rejected requests
     188=================
     189
     190By default, a '403 Forbidden' response is sent to the user if an incoming
     191request fails the checks performed by ``CsrfViewMiddleware``.  This should
     192usually only be seen when there is a genuine Cross Site Request Forgery, or
     193when, due to a programming error, the CSRF token has not been included with a
     194POST form.
     195
     196No logging is done, and the error message is not very friendly, so you may want
     197to provide your own page for handling this condition.  To do this, simply set
     198the :setting:`CSRF_FAILURE_VIEW` setting to a dotted path to your own view
     199function.
     200
    68201How it works
    69202============
    70203
    71 CsrfMiddleware does two things:
     204The CSRF protection requires two things:
    72205
    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``).
     2061. A hidden form field with the name 'csrfmiddlewaretoken' must be added to all
     207   outgoing POST forms.  The value of this field is a hash of the session ID
     208   plus a secret. If there is no session ID set, this modification of the
     209   response isn't done, so there is very little performance penalty for those
     210   requests that don't have a session.
    79211
    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``)
     212   This part is done by the template tag (and with the legacy method, it is done
     213   by ``CsrfResponseMiddleware``).
    84214
    85 This ensures that only forms that have originated from your Web site
    86 can be used to POST data back.
     2152. On all incoming POST requests that have the session cookie set, the
     216   'csrfmiddlewaretoken' must be present and correct. If it isn't, the user will
     217   get a 403 error.
    87218
     219   This check is done by ``CsrfViewMiddleware``.
     220
     221This ensures that only forms that have originated from your Web site can be used
     222to POST data back.
     223
    88224It 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.
     225forms). GET requests ought never to have any potentially dangerous side effects
     226(see `9.1.1 Safe Methods, HTTP 1.1, RFC 2616`_), and so a CSRF attack with a GET
     227request ought to be harmless.
    92228
    93229POST 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.
     230but they do not need to be protected, since the 'attacking' Web site could make
     231these kind of requests anyway.
    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.
     250These middleware require Django's session framework to work. If you have a
     251custom authentication system that manually sets cookies and the like, it won't
     252help you.
    118253
    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
     254If you are using ``CsrfResponseMiddleware`` and your app creates HTML pages and
     255forms in some unusual way, (e.g.  it sends fragments of HTML in JavaScript
     256document.write statements) you might bypass the filter that adds the hidden
     257field to the form, in which case form submission will always fail.  It may still
     258be possible to use the middleware, provided you can find some way to get the
    124259CSRF token and ensure 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
     157CSRF_SALT
     158---------
     159
     160Some additional 'salt' used by the CSRF middleware when hashing, to
     161avoid a potential security problem.  Does not need to be changed.  See
     162source for more details.
     163
    149164DATABASE_ENGINE
    150165---------------
    151166
     
    762777
    763778    ('django.middleware.common.CommonMiddleware',
    764779     'django.contrib.sessions.middleware.SessionMiddleware',
     780     'django.contrib.csrf.middleware.CsrfViewMiddleware',
    765781     'django.contrib.auth.middleware.AuthenticationMiddleware',)
    766782
    767783A tuple of middleware classes to use. See :ref:`topics-http-middleware`.
Back to Top