Chinaunix首页 | 论坛 | 博客
  • 博客访问: 663498
  • 博文数量: 198
  • 博客积分: 4256
  • 博客等级: 上校
  • 技术积分: 1725
  • 用 户 组: 普通用户
  • 注册时间: 2009-12-15 13:12
文章分类

全部博文(198)

文章存档

2012年(12)

2011年(39)

2010年(135)

2009年(12)

我的朋友

分类: 系统运维

2011-06-17 13:58:06

The CSRF middleware and template tag provides easy-to-use protection against Cross Site Request Forgeries. This type of attack occurs when a malicious Web site contains a link, a form button or some javascript that is intended to perform some action on your Web site, using the credentials of a logged-in user who visits the malicious site in their browser. A related type of attack, ‘login CSRF’, where an attacking site tricks a user’s browser into logging into a site with someone else’s credentials, is also covered.

The first defense against CSRF attacks is to ensure that GET requests are side-effect free. POST requests can then be protected by following the steps below.

New in Django 1.2: The ‘contrib’ apps, including the admin, use the functionality described here. Because it is security related, a few things have been added to core functionality to allow this to happen without any required upgrade steps.
How to use it
Changed in Django 1.2: The template tag functionality (the recommended way to use this) was added in version 1.2. The previous method (still available) is described under Legacy method.
To enable CSRF protection for your views, follow these steps:

Add the middleware 'django.middleware.csrf.CsrfViewMiddleware' to your list of middleware classes, MIDDLEWARE_CLASSES. (It should come before CsrfResponseMiddleware if that is being used, and before any view middleware that assume that CSRF attacks have been dealt with.)

Alternatively, you can use the decorator django.views.decorators.csrf.csrf_protect on particular views you want to protect (see below).

In any template that uses a POST form, use the csrf_token tag inside the
element if the form is for an internal URL, e.g.:

{% csrf_token %}
This should not be done for POST forms that target external URLs, since that would cause the CSRF token to be leaked, leading to a vulnerability.

In the corresponding view functions, ensure that the 'django.core.context_processors.csrf' context processor is being used. Usually, this can be done in one of two ways:

Use RequestContext, which always uses 'django.core.context_processors.csrf' (no matter what your TEMPLATE_CONTEXT_PROCESSORS setting). If you are using generic views or contrib apps, you are covered already, since these apps use RequestContext throughout.

Manually import and use the processor to generate the CSRF token and add it to the template context. e.g.:

from django.core.context_processors import csrf
from django.shortcuts import render_to_response

def my_view(request):
    c = {}
    c.update(csrf(request))
    # ... view code here
    return render_to_response("a_template.html", c)
You may want to write your own render_to_response wrapper that takes care of this step for you.

The utility script extras/csrf_migration_helper.py can help to automate the finding of code and templates that may need to be upgraded. It contains full help on how to use it.

AJAX
While the above method can be used for AJAX POST requests, it has some inconveniences: you have to remember to pass the CSRF token in as POST data with every POST request. For this reason, there is an alternative method: on each XMLHttpRequest, set a custom X-CSRFToken header to the value of the CSRF token. This is often easier, because many javascript frameworks provide hooks that allow headers to be set on every request. In jQuery, you can use the ajaxSend event as follows:

$(document).ajaxSend(function(event, xhr, settings) {
    function getCookie(name) {
        var cookieValue = null;
        if (document.cookie && document.cookie != '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) == (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
    function sameOrigin(url) {
        // url could be relative or scheme relative or absolute
        var host = document.location.host; // host + port
        var protocol = document.location.protocol;
        var sr_origin = '//' + host;
        var origin = protocol + sr_origin;
        // Allow absolute or scheme relative URLs to same origin
        return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
            (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
            // or any other URL that isn't scheme relative or absolute i.e relative.
            !(/^(\/\/|http:|https:).*/.test(url));
    }
    function safeMethod(method) {
        return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
    }

    if (!safeMethod(settings.type) && sameOrigin(settings.url)) {
        xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
    }
});
Adding this to a javascript file that is included on your site will ensure that AJAX POST requests that are made via jQuery will not be caught by the CSRF protection.

The decorator method
Rather than adding CsrfViewMiddleware as a blanket protection, you can use the csrf_protect decorator, which has exactly the same functionality, on particular views that need the protection. It must be used both on views that insert the CSRF token in the output, and on those that accept the POST form data. (These are often the same view function, but not always). It is used like this:

from django.views.decorators.csrf import csrf_protect
from django.template import RequestContext

@csrf_protect
def my_view(request):
    c = {}
    # ...
    return render_to_response("a_template.html", c,
                               context_instance=RequestContext(request))
Use of the decorator is not recommended by itself, since if you forget to use it, you will have a security hole. The 'belt and braces' strategy of using both is fine, and will incur minimal overhead.

Legacy method
In Django 1.1, the template tag did not exist. Instead, a post-processing middleware that re-wrote POST forms to include the CSRF token was used. If you are upgrading a site from version 1.1 or earlier, please read this section and the Upgrading notes below. The post-processing middleware is still available as CsrfResponseMiddleware, and it can be used by following these steps:

Follow step 1 above to install CsrfViewMiddleware.

Add 'django.middleware.csrf.CsrfResponseMiddleware' to your MIDDLEWARE_CLASSES setting.

CsrfResponseMiddleware needs to process the response before things like compression or setting ofETags happen to the response, so it must come after GZipMiddleware, CommonMiddleware and ConditionalGetMiddleware in the list. It also must come after CsrfViewMiddleware.

Use of the CsrfResponseMiddleware is not recommended because of the performance hit it imposes, and because of a potential security problem (see below). It can be used as an interim measure until applications have been updated to use the csrf_token tag. It is deprecated and will be removed in Django 1.4.

Django 1.1 and earlier provided a single CsrfMiddleware class. This is also still available for backwards compatibility. It combines the functions of the two middleware.

Note also that previous versions of these classes depended on the sessions framework, but this dependency has now been removed, with backward compatibility support so that upgrading will not produce any issues.

Security of legacy method
The post-processing CsrfResponseMiddleware adds the CSRF token to all POST forms (unless the view has been decorated with csrf_response_exempt). If the POST form has an external untrusted site as its target, rather than an internal page, that site will be sent the CSRF token when the form is submitted. Armed with this leaked information, that site will then be able to successfully launch a CSRF attack on your site against that user. The @csrf_response_exempt decorator can be used to fix this, but only if the page doesn't also contain internal forms that require the token.
官方文档:
阅读(2372) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~