Ticket #9977: csrf_template_tag_13.diff

File csrf_template_tag_13.diff, 45.6 KB (added by lukeplant, 6 years ago)

Fixed some issues caused by use of lazy()

  • 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    <input type="hidden" name="next" value="{{ next }}" id="next" />
    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 form.errors %}
    1010    <h1>{% blocktrans count form.errors|length as counter %}Please correct the error below{% plural %}Please correct the errors below{% endblocktrans %}</h1>
    1111    {% else %}
  • 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    <input type="hidden" name="next" value="{{ next }}" id="next" />
    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  {% for field in form %}
    44    {% if field.is_hidden %}
    55      {{ field }}
  • 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    <input type="hidden" name="next" value="{{ next }}" id="next" />
    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 }}
     
    6363        {% endif %}
    6464      {% endblock %}
    6565     
    66       <form action="" method="post"{% if cl.formset.is_multipart %} enctype="multipart/form-data"{% endif %}>
     66      <form action="" method="post"{% if cl.formset.is_multipart %} enctype="multipart/form-data"{% endif %}>{% csrf_token %}
    6767      {% if cl.formset %}
    6868        {{ cl.formset.management_form }}
    6969      {% 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 %}
     
    1414</div>
    1515{% endif %}{% endblock %}
    1616{% block content %}<div id="content-main">
    17 <form action="{{ form_url }}" method="post" id="{{ opts.module_name }}_form">{% block form_top %}{% endblock %}
     17<form action="{{ form_url }}" method="post" id="{{ opts.module_name }}_form">{% csrf_token %}{% block form_top %}{% endblock %}
    1818<div>
    1919{% if is_popup %}<input type="hidden" name="_popup" value="1" />{% endif %}
    2020{% 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/csrf/middleware.py

     
    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
     25def _get_failure_view():
     26    """
     27    Returns the view to be used for CSRF rejections
     28    """
     29    return get_callable(settings.CSRF_FAILURE_VIEW)
     30
     31def _get_validated_session_id(request):
     32    # This function is called by the csrf_token, so we don't make session
     33    # framework required, so that people can disable the session middleware
     34    # without having to change their templates.
     35    if hasattr(request, 'session'):
     36        if request.session.accessed:
     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            # creation of session.
     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):
     50    """
     51    Returns the the CSRF token required for a session,
     52    or None if there is no session active.
     53    """
     54    session_id = _get_validated_session_id(request)
     55    if session_id is None:
     56        # No session
     57        return None
     58    else:
     59        return _make_token(session_id)
     60
    2761def _make_token(session_id):
    28     return md5_constructor(settings.SECRET_KEY + session_id).hexdigest()
     62    return md5_constructor(settings.SECRET_KEY + settings.CSRF_SALT + session_id).hexdigest()
    2963
    3064class CsrfViewMiddleware(object):
    3165    """
     
    4074            if request.is_ajax():
    4175                return None
    4276
    43             try:
    44                 session_id = request.COOKIES[settings.SESSION_COOKIE_NAME]
    45             except KeyError:
     77            csrf_token = get_token(request)
     78            if csrf_token is None:
     79                # Coud happen if session middleware is disabled
     80                assert hasattr(request, 'session'), "The CSRF middleware requires the session middleware to be installed. Edit your MIDDLEWARE_CLASSES setting to insert 'django.contrib.sessions.middleware.SessionMiddleware' after the CsrfViewMiddleware."
    4681                # No session, no check required
    4782                return None
    4883
    49             csrf_token = _make_token(session_id)
    5084            # check incoming token
    5185            try:
    5286                request_csrf_token = request.POST['csrfmiddlewaretoken']
    5387            except KeyError:
    54                 return HttpResponseForbidden(_ERROR_MSG)
     88                return _get_failure_view()(request)
    5589
    5690            if request_csrf_token != csrf_token:
    57                 return HttpResponseForbidden(_ERROR_MSG)
     91                return _get_failure_view()(request)
    5892
    5993        return None
    6094
     
    80114            csrf_token = _make_token(cookie.value)
    81115        except KeyError:
    82116            # Normal case - look for existing session cookie
    83             try:
    84                 session_id = request.COOKIES[settings.SESSION_COOKIE_NAME]
     117            session_id = _get_validated_session_id(request)
     118            if session_id is not None:
    85119                csrf_token = _make_token(session_id)
    86             except KeyError:
     120            else:
    87121                # no incoming or outgoing cookie
    88122                pass
    89123
  • 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 
    912def post_form_response():
    1013    resp = HttpResponse(content="""
    1114<html><body><form method="POST"><input type="text" /></form></body></html>
     
    1518def test_view(request):
    1619    return post_form_response()
    1720
     21def _render_csrf_token_template(req):
     22    context = RequestContext(req, processors=[csrf])
     23    template = Template("{% load csrf %}{% csrf_token %}")
     24    return template.render(context)
     25
     26def test_view_with_session_access(request):
     27    request.session["test value"] = "value"
     28    return HttpResponse(_render_csrf_token_template(request))
     29
     30def test_view_with_late_session_access(request):
     31    # This view creates RequestContext and *then* accesses the
     32    # session.  This will be problematic unless the csrf context
     33    # processor is lazy.
     34    context = RequestContext(request, processors=[csrf])
     35    request.session["test value"] = "value"
     36    template = Template("{% load csrf %}{% csrf_token %}")
     37    return HttpResponse(template.render(context))
     38
    1839class CsrfMiddlewareTest(TestCase):
    1940
    20     _session_id = "1"
     41    def setUp(self, *args, **kwargs):
     42        super(CsrfMiddlewareTest, self).setUp(*args, **kwargs)
     43        # We have to create an actual session in the DB as the
     44        # middleware validates the session
     45        engine = import_module(settings.SESSION_ENGINE)
     46        s = engine.SessionStore(None)
     47        s.create()
     48        self._session_id = s.session_key
    2149
     50    def _apply_request_middleware(self, req):
     51        SessionMiddleware().process_request(req)
     52        return req
     53
    2254    def _get_GET_no_session_request(self):
    23         return HttpRequest()
     55        return self._apply_request_middleware(HttpRequest())
    2456
    2557    def _get_GET_session_request(self):
    26         req = self._get_GET_no_session_request()
     58        req = HttpRequest()
    2759        req.COOKIES[settings.SESSION_COOKIE_NAME] = self._session_id
    28         return req
     60        return self._apply_request_middleware(req)
    2961
    3062    def _get_POST_session_request(self):
    31         req = self._get_GET_session_request()
     63        req = HttpRequest()
     64        req.COOKIES[settings.SESSION_COOKIE_NAME] = self._session_id
    3265        req.method = "POST"
    33         return req
     66        return self._apply_request_middleware(req)
    3467
    3568    def _get_POST_no_session_request(self):
    36         req = self._get_GET_no_session_request()
     69        req = HttpRequest()
    3770        req.method = "POST"
    38         return req
     71        return self._apply_request_middleware(req)
    3972
    4073    def _get_POST_session_request_with_token(self):
    4174        req = self._get_POST_session_request()
     
    142175        req.META['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
    143176        req2 = CsrfMiddleware().process_view(req, self.get_view(), (), {})
    144177        self.assertEquals(None, req2)
     178
     179
     180    def test_token_node_no_session(self):
     181        """
     182        Check that CsrfTokenNode works when no session active
     183        """
     184        req = self._get_GET_no_session_request()
     185        rendered = _render_csrf_token_template(req)
     186        self.assertEquals(u"", rendered)
     187
     188    def test_token_node_with_session(self):
     189        """
     190        Check that CsrfTokenNode works when a session is active
     191        """
     192        req = self._get_GET_session_request()
     193        rendered = _render_csrf_token_template(req)
     194        self.assertNotEqual(u"", rendered)
     195        expected = ("name='csrfmiddlewaretoken' value='%s'" % _make_token(self._session_id))
     196        self.failUnless(expected in rendered)
     197
     198    def test_token_node_with_new_session(self):
     199        """
     200        Check that CsrfTokenNode works when a session is created by
     201        the view
     202        """
     203        req = self._get_GET_no_session_request()
     204        resp = test_view_with_session_access(req)
     205        expected = ("name='csrfmiddlewaretoken' value='%s'" % _make_token(req.session.session_key))
     206        self.assertContains(resp, expected)
     207
     208    def test_token_node_with_late_session_access(self):
     209        """
     210        Check that CsrfTokenNode works when a session is created by
     211        the view *after* the RequestContext has been created
     212        """
     213        req = self._get_GET_no_session_request()
     214        resp = test_view_with_late_session_access(req)
     215        expected = ("name='csrfmiddlewaretoken' value='%s'" % _make_token(req.session.session_key))
     216        self.assertContains(resp, expected)
  • 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/context_processors.py

    Property changes on: django/contrib/csrf/templatetags/csrf.py
    ___________________________________________________________________
    Added: svn:eol-style
       + native
    
    
    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
    
     
    130130    else:
    131131        context_instance['validlink'] = False
    132132        form = None
    133     context_instance['form'] = form   
     133    context_instance['form'] = form
    134134    return render_to_response(template_name, context_instance=context_instance)
    135135
    136136def password_reset_complete(request, template_name='registration/password_reset_complete.html'):
  • django/contrib/auth/tests/views.py

     
    5050        # Lets munge the token in the path, but keep the same length,
    5151        # in case the URL conf will reject a different length
    5252        path = path[:-5] + ("0"*4) + path[-1]
    53 
    5453        response = self.client.get(path)
    5554        self.assertEquals(response.status_code, 200)
    5655        self.assert_("The password reset link was invalid" in response.content)
  • tests/regressiontests/admin_views/tests.py

     
    747747        # 4 action inputs (3 regular checkboxes, 1 checkbox to select all)
    748748        # main form submit button = 1
    749749        # search field and search submit button = 2
    750         # 6 + 2 + 1 + 2 = 11 inputs
    751         self.failUnlessEqual(response.content.count("<input"), 15)
     750        # csrf hidden field = 1
     751        # 6 + 2 + 4 + 1 + 2 + 1 = 16 inputs
     752        self.failUnlessEqual(response.content.count("<input"), 16)
    752753        # 1 select per object = 3 selects
    753754        self.failUnlessEqual(response.content.count("<select"), 4)
    754755
  • 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
    11 `Cross Site Request Forgeries`_.  This type of attack occurs when a malicious
    12 Web 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.
     10The CSRF middleware and template tag provides easy-to-use protection
     11against `Cross Site Request Forgeries`_.  This type of attack occurs
     12when a malicious Web site creates a link or form button that is
     13intended to perform some action on your Web site, using the
     14credentials of a logged-in user who is tricked into clicking on the
     15link in their browser.
    1516
    1617The 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.
     18are side-effect free.  POST requests can then be protected by adding
     19these middleware into your list of installed middleware following the
     20steps below.
    1921
     22.. versionadded:: 1.1
     23    The functionality described here is depended on by the 'contrib'
     24    apps, including the admin, so usage steps 1, 2 and 4.1.1 below are
     25    **required** for these apps to function.
     26
    2027.. _Cross Site Request Forgeries: http://www.squarefree.com/securitytips/web-developers.html#CSRF
    2128
    2229How to use it
    2330=============
     31.. versionchanged:: 1.1
     32    The template tag functionality (the recommended way to use this)
     33    was added in version 1.1. The previous method (still available) is
     34    described under 'Legacy method'.
    2435
    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.
     36Follow these steps:
    3137
    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``.
     38    1. Add the middleware
     39       ``'django.contrib.csrf.middleware.CsrfViewMiddleware'`` to your
     40       list of middleware classes, :setting:`MIDDLEWARE_CLASSES`. It
     41       must come after ``SessionMiddleware`` in the list.
    3742
    38 .. versionchanged:: 1.1
    39     (previous versions of Django did not provide these two components
    40     of ``CsrfMiddleware`` as described above)
     43    2. Add ``'django.contrib.csrf'`` to your :setting:`INSTALLED_APPS`.
    4144
     45    3. In any template that uses a POST form, first load the 'csrf'
     46       template tag library::
     47
     48           {% load csrf %}
     49
     50       Then use the ``csrf_token`` tag inside the ``<form>`` element, e.g.::
     51
     52           <form action="" method="POST">{% csrf_token %}
     53
     54    4. In the corresponding view functions, ensure that the
     55       ``'django.contrib.csrf.context_processors.csrf'`` is being
     56       used. Usually, this can be done in one of two ways:
     57
     58       1. Using RequestContext:
     59
     60          1. Ensure ``'django.contrib.csrf.context_processors.csrf'``
     61             is present in your :setting:`TEMPLATE_CONTEXT_PROCESSORS`
     62             setting. It is present by default.
     63
     64          2. Use ``RequestContext`` as the context instance in the
     65             relevant views. If you are using generic views or contrib
     66             apps, you are covered already.
     67
     68       2. Manually import and use the processor to generate the CSRF
     69          token and add it to the template context. e.g.::
     70
     71              from django.contrib.csrf.context_processors import csrf
     72              from django.template import Context
     73              from django.shortcuts import render_to_response
     74              def my_view(request):
     75                  c = Context()
     76                  c.update(csrf(request))
     77                  return render_to_response("a_template.html", context_instance=c)
     78
     79    5. Ensure that all views render their templates **after**
     80       accessing the session.  Note that sessions can be created
     81       implicitly simply by setting a value or accessing the contents.
     82       If this is done after the template is rendered, the CSRF token
     83       it contains will be incorrect, and the following form
     84       submission will be rejected.
     85
     86Legacy method
     87-------------
     88
     89In Django 1.0, the template tag did not exist.  Instead, a
     90post-processing middleware that re-wrote POST forms to include the
     91CRSF token was used.  This is still available as
     92``CsrfResponseMiddleware``, and it can be used by following these
     93steps:
     94
     95    1. Follow step 1 above to install ``CsrfViewMiddleware``.
     96
     97    2. Add ``'django.contrib.csrf.middleware.CsrfResponseMiddleware'``
     98       to your :setting:`MIDDLEWARE_CLASSES` setting.
     99
     100       ``CsrfResponseMiddleware`` needs to process the response after
     101       the ``SessionMiddleware``, so must come before it in the list.
     102       It also must process the response before things like
     103       compression happen to the response, so it must come after
     104       ``GZipMiddleware`` in the list.
     105
     106Use of the ``CsrfResponseMiddleware`` is not recommended, but it can
     107be used as an interim measure until applications have been updated to use
     108the ``{% crsf_token %}`` tag.
     109
     110Django 1.0 provided a single ``CsrfMiddleware`` class.  This is also
     111still available for backwards compatibility.  It combines the
     112functions of the two new middleware.
     113
     114
    42115Exceptions
    43116----------
    44117
    45118.. versionadded:: 1.1
    46119
    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::
     120To manually exclude a view function from being handled by either of
     121the two CSRF middleware, you can use the ``csrf_exempt`` decorator,
     122found in the ``django.contrib.csrf.middleware`` module. For example::
    50123
    51124    from django.contrib.csrf.middleware import csrf_exempt
    52125
     
    54127        return HttpResponse('Hello world')
    55128    my_view = csrf_exempt(my_view)
    56129
    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.
     130Like the middleware, the ``csrf_exempt`` decorator is composed of two
     131parts: a ``csrf_view_exempt`` decorator and a ``csrf_response_exempt``
     132decorator, found in the same module.  These disable the view
     133protection mechanism (``CsrfViewMiddleware``) and the response
     134post-processing (``CsrfResponseMiddleware``) respectively.  They can
     135be used individually if required.
    63136
    64137You don't have to worry about doing this for most AJAX views. Any
    65138request sent with "X-Requested-With: XMLHttpRequest" is automatically
    66139exempt. (See the next section.)
    67140
     141Rejected requests
     142=================
     143
     144By default, a '403 Forbidden' response is sent to the user if an
     145incoming request fails the checks performed by ``CsrfViewMiddleware``.
     146This should usually only be seen when there is a genuine Cross Site
     147Request Forgery, or when, due to a programming error, the CSRF token
     148has not been included with a POST form.
     149
     150No logging is done, and the error message is not very friendly, so you
     151may want to provide your own page for handling this condition.  To do
     152this, simply set the :setting:`CSRF_FAILURE_VIEW` setting to a dotted
     153path to your own view function.
     154
    68155How it works
    69156============
    70157
    71 CsrfMiddleware does two things:
     158The CSRF protection requires two things:
    72159
    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``).
     1601. A hidden form field with the name 'csrfmiddlewaretoken' must be
     161   added to all outgoing POST forms.  The value of this field is a
     162   hash of the session ID plus a secret. If there is no session ID
     163   set, this modification of the response isn't done, so there is very
     164   little performance penalty for those requests that don't have a
     165   session.
    79166
    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``)
     167   This part is done by the template tag (and with the
     168   legacy method, it is done by ``CsrfResponseMiddleware``).
    84169
     1702. On all incoming POST requests that have the session cookie set, the
     171   'csrfmiddlewaretoken' must be present and correct. If it isn't, the
     172   user will get a 403 error.
     173
     174   This check is done by ``CsrfViewMiddleware``.
     175
    85176This ensures that only forms that have originated from your Web site
    86177can be used to POST data back.
    87178
     
    112203Limitations
    113204===========
    114205
    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.
     206These middleware require Django's session framework to work. If you
     207have a custom authentication system that manually sets cookies and the
     208like, it won't help you.
    118209
    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.
     210If you are using ``CsrfResponseMiddleware`` and your app creates HTML
     211pages and forms in some unusual way, (e.g.  it sends fragments of HTML
     212in JavaScript document.write statements) you might bypass the filter
     213that adds the hidden field to the form, in which case form submission
     214will always fail.  It may still be possible to use the middleware,
     215provided you can find some way to get the CSRF token and ensure that
     216is 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