1. 程式人生 > >csrf_token(跨站偽造)

csrf_token(跨站偽造)

render 響應 相關 $.ajax 依賴 sta .html 實現 print

Django跨站請求偽造

跨站請求偽造(Cross-site request forgery),也被稱為one-click attack或者session riding,通常縮寫為CSRF或者XSRF, 是一種挾制用戶在當前已登錄的Web應用程序上執行非本意的操作的攻擊方法。
跟跨網站腳本(XSS)相比,XSS利用的是用戶對指定網站的信任,CSRF 利用的是網站對用戶網頁瀏覽器的信任。

例如:
如果用戶登錄網絡銀行去查看其存款余額,他沒有退出網絡銀行系統就去了自己喜歡的論壇去灌水,如果攻擊者在論壇中精心構造了一個惡意的鏈接並誘使該用戶點擊了該鏈接,那麽該用戶在網絡銀行帳戶中的資金就有可能被轉移到攻擊者指定的帳戶中。

造成CSRF的原因

跨站請求偽造能否得逞,與以下幾個方面密不可分,分別是瀏覽器對會話的處理,攻擊者對Web應用有關URL的了解,應用程序賴以管理會話的信息對瀏覽器的透明性以及各種能夠引發資源請求HTML標簽等。

正常:
a. 先GET請求:
    頁面
    隱藏:input 隨機字符串
b. POST
    數據
    input 隨機字符串

非法:
b. POST
    數據

首先,我們來了解一些Web瀏覽器對於Cookie和HTTP身份驗證信息之類的會話信息的處理方式。目前,瀏覽器會自動地發送標識用戶對話的信息,而無需用戶幹預,換句話說,當瀏覽器發送這些身份信息的時候,用戶根本感覺不到。假設站點A上有一個Web應用程序,並且受害者正好已經在該站點上通過了身份認證,這時,站點會向受害者發送一個cookie作為響應,這個cookie的作用是什麽呢?主要是被站點作為用戶會話的標誌,即如果站點收到了帶有受害者的cookie的請求,那麽它就會把這個請求看作是已登錄的受害者發來的。一般情況下,瀏覽器收到站點設置的cookie之後,每當向該站點發送請求的時候,瀏覽器都會“自動地”連同該cookie一起發出。

然後,我們再來討論一下攻擊者對Web應用程序URL的了解。如果應用程序沒有在URL中使用跟會話有關的信息的話,那麽通過代碼分析或者通過訪問該應用程序並查看嵌入HTML/JavaScript中的URL以及表單來了解應用程序有關的URL、參數和容許值。

接下來,我們討論一下應用程序賴以管理會話的信息對瀏覽器的透明性問題。我們知道,為了提高Web應用的便利性,用來管理會話的信息,例如Cookie或者基於HTTP的身份驗證(例如HTTP基本認證、非基於表單的認證)等敏感信息,都是由瀏覽器來存放的,並在每當向需要身份驗證的應用程序發送請求時自動捎帶上這些信息。也就是說,瀏覽器可以訪問會話管理信息,如果Web應用程序完全依賴於這類信息來識別一個用戶會話,這就為跨站請求偽造創造了條件。

上面所說的三個因素,是跨站請求偽造攻擊的必要的條件,而下面所說的,是一個“錦上添花”的因素,即沒有它也能發動跨站請求偽造攻擊,但是有了它能使該攻擊更加容易。這就是存在多種HTML標簽,如果頁面內出現這些標簽,會立刻引起瀏覽器對http[s]資源的訪問,例如圖像標簽img便是其中之一。

在Django中

django為用戶實現防止跨站請求偽造的功能,通過中間件 django.middleware.csrf.CsrfViewMiddleware 來完成。而對於django中設置防跨站請求偽造功能有分為全局和局部。

全局:
中間件 django.middleware.csrf.CsrfViewMiddleware

局部:

  • @csrf_protect,為當前函數強制設置防跨站請求偽造功能,即便settings中沒有設置全局中間件。
  • @csrf_exempt,取消當前函數防跨站請求偽造功能,即便settings中設置了全局中間件。

註:from django.views.decorators.csrf import csrf_exempt,csrf_protect

應用
1、普通表單

veiw中設置返回值:
  return render_to_response(Account/Login.html,data,context_instance=RequestContext(request))  
     或者
     return render(request, xxx.html, data)
  
html中設置Token:
  {% csrf_token %}

 Form提交:

  
<form action="/icbc.html" method="POST">
    {% csrf_token %}
    <input type=‘text‘ name=‘from‘  />
    <input type=‘text‘ name=‘to‘ />
    <input type=‘text‘  name=‘money‘ />
    <input type=‘submit‘ value=‘轉賬‘ />

2、Ajax
對於傳統的form,可以通過表單的方式將token再次發送到服務端,而對於ajax的話,使用如下方式。

技術分享
from django.template.context import RequestContext
# Create your views here.
  
def test(request):
  
    if request.method == POST:
        print request.POST
        return HttpResponse(ok)
    return  render_to_response(app01/test.html,context_instance=RequestContext(request))
views.py

技術分享
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    {% csrf_token %}
  
    <input type="button" onclick="Do();"  value="Do it"/>
  
    <script src="/static/plugin/jquery/jquery-1.8.0.js"></script>
    <script src="/static/plugin/jquery/jquery.cookie.js"></script>
    <script type="text/javascript">
        var csrftoken = $.cookie(csrftoken);
  
        function csrfSafeMethod(method) {
            // these HTTP methods do not require CSRF protection
            return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
        }
        $.ajaxSetup({
            beforeSend: function(xhr, settings) {
                if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
                    xhr.setRequestHeader("X-CSRFToken", csrftoken);
                }
            }
        });
        function Do(){
  
            $.ajax({
                url:"/app01/test/",
                data:{id:1},
                type:POST,
                success:function(data){
                    console.log(data);
                }
            });
  
        }
    </script>
</body>
</html>
test.html

Ajax提交:
1)基於請求體:

function ajaxSubmit() {
    $.ajax({
        url: "/icbc.html",
        type: ‘POST‘,
        data: {‘k1‘:‘v1‘,‘k2‘:‘v2‘,‘csrfmiddlewaretoken‘:$(‘input[name="csrfmiddlewaretoken"]‘).val() },
        success:function (arg) {
            console.log(arg)
        }
    })
}

// 只能寫在模板中
function ajaxSubmit() {
    $.ajax({
        url: "/icbc.html",
        type: ‘POST‘,
        data: {‘k1‘:‘v1‘,‘k2‘:‘v2‘,‘csrfmiddlewaretoken‘:"{{ csrf_token }}" },
        success:function (arg) {
            console.log(arg)
        }
    })
}

function ajaxSubmit() {
    $.ajax({
        url: "/icbc.html",
        type: ‘POST‘,
        data: $(‘#f1‘).serialize(),
        success:function (arg) {
            console.log(arg)
        }
    })
}
// 以上都是放在請求體中

2)基於請求頭:

a. 在cookie中獲取csrftoken對應的值 l2kEqQLhR1gH0hh3ioZ1dfxT3iSwjXoKTf7GNFggJZ7E6DROB6k33L7vdqe5lV1v
b. 發送請求時,放在請求頭中也可以

function ajaxSubmit() {
    $.ajax({
        url: "/icbc.html",
        type: ‘POST‘,
        data: {‘k1‘:‘v1‘,‘k2‘:‘v2‘},
        headers: {"X-CSRFToken": $.cookie(‘csrftoken‘)},
        success:function (arg) {
            console.log(arg)
        }
    })
}

跨站請求偽造對策

跨站請求偽造的危害非常之大,所以無論是用戶還是開發人員都應該引起足夠的重視,下面是給Web應用程序終端用戶和Web應用程序開發人員的一些有用的建議。

用戶:
因為CSRF漏洞有流行之趨勢,所以建議用戶遵循最佳實踐來降低風險,可以降低風險的習慣包括:

使用Web應用程序之後立即登出

不要讓瀏覽器保存用戶名/口令,也不要讓站點“記住”您不要使用同一個瀏覽器同時訪問敏感的應用程序和隨意沖浪;如果必須同時做多件事情的話,最好單獨使用不同的瀏覽器。

對於支持HTM格式郵件/瀏覽器集成式軟件以及集成了新聞閱讀程序/瀏覽器的軟件都會帶來額外的風險,因為只要查看郵件或者新聞就有可能被迫執行一次攻擊,所以使用這類軟件時格外小心。

開發人員:
開發人員應當向URL添加跟會話有關信息。該攻擊類型之所以得逞,是因為會話是由cookie唯一標識的,並且該cookie是由瀏覽器自動發送的。

如果我們在URL級別為會話生成其它相關信息,那麽就會給攻擊者為發動攻擊而了解URL的結構造成更多的障礙。

至於其它的對策,雖然也無法解決該問題,但是能夠使得利用該漏洞更加困難,例如使用POST而不是GET。雖然POST請求可以通過JavaScript進行模仿,但是它提高了發動這種攻擊的難度。使用中間確認頁也能帶來相同的效果,比如“您確信要這樣做嗎?”之類的頁面。雖然攻擊者可以繞過這些措施,但是這些措施提供了實施攻擊的難度。因此,不能完全依賴這些手段來保護您的應用程序。自動登出機制也能減輕這種攻擊帶來的危害,但這最終依賴於具體情況(一個整天跟有這種漏洞的網絡銀行程序打交道的用戶所面臨的風險要遠遠大於臨時使用同一網絡銀行的用戶所面臨的風險)。

參考博客

csrf_token(跨站偽造)