框架與CSRF防護

框架與CSRF防護

CSRF***的目標,通常都會產生「寫數據」操做的URL,好比「增」、「刪」、「改」;而「讀數據」操做並非CSRF***的目標,由於在CSRF的***過程當中***者沒法獲取到服務器端返回的數據,***者只是借用戶之手觸發服務器動做,因此讀數據對於CSRF來講並沒有直接的意義(可是若是同時存在XSS漏洞或者其餘的跨域漏洞,則可能會引發別的問題,在這裏,僅僅就CSRF對抗自己進行討論)。 php

所以,在Web應用開發中,有必要對「讀操做」和「寫操做」予以區分,好比要求全部的「寫操做」都使用HTTP POST html

在不少講述CSRF防護的文章中,都要求使用HTTP POST進行防護,但實際上POST自己並不足以對抗CSRF,由於POST也是能夠自動提交的。可是POST的使用,對於保護token有着積極的意義,而security token的私密性(不可預測性原則),是防護CSRF***的基礎。 程序員

對於Web框架來講,能夠自動地在全部涉及POST的代碼中添加token,這些地方包括全部的form表單、全部的Ajax POST請求等。 ajax

完整的CSRF防護方案,對於Web框架來講有如下幾處地方須要改動。 django

1)在Session中綁定token。若是不能保存到服務器端Session中,則能夠替代爲保存到Cookie裏。 跨域

2)在form表單中自動填入token字段,好比 <input type=hidden name="anti_csrf_token" value="$token" /> 安全

3)在Ajax請求中自動添加token,這可能須要已有的Ajax封裝實現的支持。 服務器

4)在服務器端對比POST提交參數的tokenSession中綁定的token是否一致,以驗證CSRF***。 cookie

Rails 中,要作到這一切很是簡單,只須要在Application Controller中增長一行便可: session

protect_from_forgery :secret => "123456789012345678901234567890..."

它將根據secret和服務器端的隨機因子自動生成token,並自動添加到全部form和由Rails生成的Ajax請求中。經過框架實現的這一功能大大簡化了程序員的開發工做。

Django中也有相似的功能,可是配置稍微要複雜點。

先,將 django.middleware.csrf.CsrfViewMiddleware 添加到 MIDDLEWARE_CLASSES中。

('django.middleware.common.CommonMiddleware',

 'django.contrib.sessions.middleware.SessionMiddleware',

 'django.middleware.csrf.CsrfViewMiddleware',

 'django.contrib.auth.middleware.AuthenticationMiddleware',

 'django.contrib.messages.middleware.MessageMiddleware',)

而後,在form表單的模板中添加token

<form action="." method="post">{% csrf_token %}

接下來,確認在View層的函數中使用了django.core.context_processors.csrf,若是使用的是 RequestContext,則默認已經使用了,不然須要手動添加。

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)

這樣就配置成功了,能夠享受CSRF防護的效果了。

Ajax請求中,通常是插入一個包含了tokenHTTP頭,使用HTTP頭是爲了防止token泄密,由於通常的JavaScript沒法獲取到HTTP頭的信息,可是在存在一些跨域漏洞時可能會出現例外。

下面是一個在Ajax中添加自定義token的例子。

$(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'));

    }

});

Spring MVC以及一些其餘的流行Web框架中,並無直接提供針對CSRF的保護,所以這些功能須要本身實現。

 

本文節選自《白帽子講Web安全》一書。

圖書詳細信息:http://bvbroadview.blog.51cto.com/addblog.php

相關文章
相關標籤/搜索