mirror of https://github.com/django/django.git
Added CsrfMiddleware to contrib, and documentation.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@2868 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
f0141f1c1c
commit
8eecb95ec8
|
@ -0,0 +1,84 @@
|
||||||
|
"""
|
||||||
|
Cross Site Request Forgery Middleware.
|
||||||
|
|
||||||
|
This module provides a middleware that implements protection
|
||||||
|
against request forgeries from other sites.
|
||||||
|
|
||||||
|
"""
|
||||||
|
from django.conf import settings
|
||||||
|
from django.http import HttpResponseForbidden
|
||||||
|
import md5
|
||||||
|
import re
|
||||||
|
|
||||||
|
_ERROR_MSG = "<h1>403 Forbidden</h1><p>Cross Site Request Forgery detected. Request aborted.</p>"
|
||||||
|
|
||||||
|
_POST_FORM_RE = \
|
||||||
|
re.compile(r'(<form\W[^>]*\bmethod=(\'|"|)POST(\'|"|)\b[^>]*>)', re.IGNORECASE)
|
||||||
|
|
||||||
|
_HTML_TYPES = ('text/html', 'application/xhtml+xml')
|
||||||
|
|
||||||
|
def _make_token(session_id):
|
||||||
|
return md5.new(settings.SECRET_KEY + session_id).hexdigest()
|
||||||
|
|
||||||
|
class CsrfMiddleware(object):
|
||||||
|
"""Django middleware that adds protection against Cross Site
|
||||||
|
Request Forgeries by adding hidden form fields to POST forms and
|
||||||
|
checking requests for the correct value.
|
||||||
|
|
||||||
|
In the list of middlewares, SessionMiddleware is required, and must come
|
||||||
|
after this middleware. CsrfMiddleWare must come after compression
|
||||||
|
middleware.
|
||||||
|
|
||||||
|
If a session ID cookie is present, it is hashed with the SECRET_KEY
|
||||||
|
setting to create an authentication token. This token is added to all
|
||||||
|
outgoing POST forms and is expected on all incoming POST requests that
|
||||||
|
have a session ID cookie.
|
||||||
|
|
||||||
|
If you are setting cookies directly, instead of using Django's session
|
||||||
|
framework, this middleware will not work.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def process_request(self, request):
|
||||||
|
if request.POST:
|
||||||
|
try:
|
||||||
|
session_id = request.COOKIES[settings.SESSION_COOKIE_NAME]
|
||||||
|
except KeyError:
|
||||||
|
# No session, no check required
|
||||||
|
return None
|
||||||
|
|
||||||
|
csrf_token = _make_token(session_id)
|
||||||
|
# check incoming token
|
||||||
|
try:
|
||||||
|
request_csrf_token = request.POST['csrfmiddlewaretoken']
|
||||||
|
except KeyError:
|
||||||
|
return HttpResponseForbidden(_ERROR_MSG)
|
||||||
|
|
||||||
|
if request_csrf_token != csrf_token:
|
||||||
|
return HttpResponseForbidden(_ERROR_MSG)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def process_response(self, request, response):
|
||||||
|
csrf_token = None
|
||||||
|
try:
|
||||||
|
cookie = response.cookies[settings.SESSION_COOKIE_NAME]
|
||||||
|
csrf_token = _make_token(cookie.value)
|
||||||
|
except KeyError:
|
||||||
|
# No outgoing cookie to set session, but
|
||||||
|
# a session might already exist.
|
||||||
|
try:
|
||||||
|
session_id = request.COOKIES[settings.SESSION_COOKIE_NAME]
|
||||||
|
csrf_token = _make_token(session_id)
|
||||||
|
except KeyError:
|
||||||
|
# no incoming or outgoing cookie
|
||||||
|
pass
|
||||||
|
|
||||||
|
if csrf_token is not None and \
|
||||||
|
response['Content-Type'].split(';')[0] in _HTML_TYPES:
|
||||||
|
|
||||||
|
# Modify any POST forms
|
||||||
|
extra_field = "<div style='display:none;'>" + \
|
||||||
|
"<input type='hidden' name='csrfmiddlewaretoken' value='" + \
|
||||||
|
csrf_token + "' /></div>"
|
||||||
|
response.content = _POST_FORM_RE.sub('\\1' + extra_field, response.content)
|
||||||
|
return response
|
|
@ -57,6 +57,16 @@ See the `syndication documentation`_.
|
||||||
|
|
||||||
.. _syndication documentation: http://www.djangoproject.com/documentation/syndication/
|
.. _syndication documentation: http://www.djangoproject.com/documentation/syndication/
|
||||||
|
|
||||||
|
csrf
|
||||||
|
====
|
||||||
|
|
||||||
|
A middleware for preventing Cross Site Request Forgeries
|
||||||
|
|
||||||
|
See the `csrf documentation`_.
|
||||||
|
|
||||||
|
.. _csrf documentation: http://www.djangoproject.com/documentation/csrf/
|
||||||
|
|
||||||
|
|
||||||
Other add-ons
|
Other add-ons
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
=====================================
|
||||||
|
Cross Site Request Forgery Protection
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
The CsrfMiddleware class provides easy-to-use protection against
|
||||||
|
`Cross Site Request Forgeries`_. This type of attack occurs when a malicious
|
||||||
|
web site creates a link or form button that is intended to perform some action
|
||||||
|
on your web site, using the credentials of a logged-in user who is tricked
|
||||||
|
into clicking on the link in their browser.
|
||||||
|
|
||||||
|
The first defense against CSRF attacks is to ensure that GET requests
|
||||||
|
are side-effect free. POST requests can then be protected by adding this
|
||||||
|
middleware into your list of installed middleware.
|
||||||
|
|
||||||
|
|
||||||
|
.. _Cross Site Request Forgeries: http://www.squarefree.com/securitytips/web-developers.html#CSRF
|
||||||
|
|
||||||
|
How to use it
|
||||||
|
=============
|
||||||
|
Add the middleware ``"django.contrib.csrf.middleware.CsrfMiddleware"`` to
|
||||||
|
your list of middleware classes, ``MIDDLEWARE_CLASSES``. It needs to process
|
||||||
|
the response after the SessionMiddleware, so must come before it in the
|
||||||
|
list. It also must process the response before things like compression
|
||||||
|
happen to the response, so it must come after GZipMiddleware in the list.
|
||||||
|
|
||||||
|
How it works
|
||||||
|
============
|
||||||
|
CsrfMiddleware does two things:
|
||||||
|
|
||||||
|
1. It modifies outgoing requests by adding a hidden form field to all
|
||||||
|
'POST' forms, with the name 'csrfmiddlewaretoken' and a value which is
|
||||||
|
a hash of the session ID plus a secret. If there is no session ID set,
|
||||||
|
this modification of the response isn't done, so there is very little
|
||||||
|
performance penalty for those requests that don't have a session.
|
||||||
|
|
||||||
|
2. On all incoming POST requests that have the session cookie set, it
|
||||||
|
checks that the 'csrfmiddlewaretoken' is present and correct. If it
|
||||||
|
isn't, the user will get a 403 error.
|
||||||
|
|
||||||
|
This ensures that only forms that have originated from your web site
|
||||||
|
can be used to POST data back.
|
||||||
|
|
||||||
|
It deliberately only targets HTTP POST requests (and the corresponding
|
||||||
|
POST forms). GET requests ought never to have side effects (if you are
|
||||||
|
using HTTP GET and POST correctly), and so a CSRF attack with a GET
|
||||||
|
request will always be harmless.
|
||||||
|
|
||||||
|
POST requests that are not accompanied by a session cookie are not protected,
|
||||||
|
but they do not need to be protected, since the 'attacking' web site
|
||||||
|
could make these kind of requests anyway.
|
||||||
|
|
||||||
|
The Content-Type is checked before modifying the response, and only
|
||||||
|
pages that are served as 'text/html' or 'application/xml+xhtml'
|
||||||
|
are modified.
|
||||||
|
|
||||||
|
Limitations
|
||||||
|
===========
|
||||||
|
CsrfMiddleware requires Django's session framework to work. If you have
|
||||||
|
a custom authentication system that manually sets cookies and the like,
|
||||||
|
it won't help you.
|
||||||
|
|
||||||
|
If your app creates HTML pages and forms in some unusual way, (e.g.
|
||||||
|
it sends fragments of HTML in javascript document.write statements)
|
||||||
|
you might bypass the filter that adds the hidden field to the form,
|
||||||
|
in which case form submission will always fail. It may still be possible
|
||||||
|
to use the middleware, provided you can find some way to get the
|
||||||
|
CSRF token and ensure that is included when your form is submitted.
|
||||||
|
|
Loading…
Reference in New Issue