Django中如何防範CSRF跨站點請求偽造攻擊

pythontab發表於2018-05-29

CSRF概念

CSRF跨站點請求偽造(Cross—Site Request Forgery)。

攻擊者盜用了你的身份,以你的名義傳送惡意請求,對伺服器來說這個請求是完全合法的,但是卻完成了攻擊者所期望的一個操作,比如以你的名義傳送郵件、發訊息,盜取你的賬號,新增系統管理員,甚至於購買商品、虛擬貨幣轉賬等。


CSRF攻擊原理以及過程

使用者C開啟瀏覽器,訪問受信任網站A,輸入使用者名稱和密碼請求登入網站A;

2.在使用者資訊透過驗證後,網站A產生Cookie資訊並返回給瀏覽器,此時使用者登入網站A成功,可以正常傳送請求到網站A;


使用者未退出網站A之前,在同一瀏覽器中,開啟一個TAB頁訪問網站B;


網站B接收到使用者請求後,返回一些攻擊性程式碼,併發出一個請求要求訪問第三方站點A;


瀏覽器在接收到這些攻擊性程式碼後,根據網站B的請求,在使用者不知情的情況下攜帶Cookie資訊,向網站A發出請求。網站A並不知道該請求其實是由B發起的,所以會根據使用者C的Cookie資訊以C的許可權處理該請求,導致來自網站B的惡意程式碼被執行。


CSRF攻擊例項

受害者 Bob 在銀行有一筆存款,透過對銀行的網站傳送請求 http://bank.example/withdraw?account=bob&amount=1000000&for=bob2可以使 Bob 把 1000000 的存款轉到 bob2 的賬號下。通常情況下,該請求傳送到網站後,伺服器會先驗證該請求是否來自一個合法的 session,並且該 session 的使用者 Bob 已經成功登陸。


駭客 Mallory 自己在該銀行也有賬戶,他知道上文中的 URL 可以把錢進行轉帳操作。Mallory 可以自己傳送一個請求給銀行:http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory。但是這個請求來自 Mallory 而非 Bob,他不能透過安全認證,因此該請求不會起作用。


這時,Mallory 想到使用 CSRF 的攻擊方式,他先自己做一個網站,在網站中放入如下程式碼:src=”http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory ”,並且透過廣告等誘使 Bob 來訪問他的網站。當 Bob 訪問該網站時,上述 url 就會從 Bob 的瀏覽器發向銀行,而這個請求會附帶 Bob 瀏覽器中的 cookie 一起發向銀行伺服器。大多數情況下,該請求會失敗,因為他要求 Bob 的認證資訊。但是,如果 Bob 當時恰巧剛訪問他的銀行後不久,他的瀏覽器與銀行網站之間的 session 尚未過期,瀏覽器的 cookie 之中含有 Bob 的認證資訊。這時,悲劇發生了,這個 url 請求就會得到響應,錢將從 Bob 的賬號轉移到 Mallory 的賬號,而 Bob 當時毫不知情。等以後 Bob 發現賬戶錢少了,即使他去銀行查詢日誌,他也只能發現確實有一個來自於他本人的合法請求轉移了資金,沒有任何被攻擊的痕跡。而 Mallory 則可以拿到錢後逍遙法外。


Django中如何防範CSRF

Django使用專門的中介軟體(CsrfMiddleware)來進行CSRF防護。具體的原理如下:


1.它修改當前處理的請求,向所有的 POST 表單增添一個隱藏的表單欄位,使用名稱是 csrfmiddlewaretoken ,值為當前會話 ID 加上一個金鑰的雜湊值。 如果未設定會話 ID ,該中介軟體將不會修改響應結果,因此對於未使用會話的請求來說效能損失是可以忽略的。


2.對於所有含會話 cookie 集合的傳入 POST 請求,它將檢查是否存在 csrfmiddlewaretoken 及其是否正確。 如果不是的話,使用者將會收到一個 403 HTTP 錯誤。 403 錯誤頁面的內容是檢測到了跨域請求偽裝。 終止請求。


該步驟確保只有源自你的站點的表單才能將資料 POST 回來。


另外要說明的是,未使用會話 cookie 的 POST 請求無法受到保護,但它們也不 需要 受到保護,因為惡意網站可用任意方法來製造這種請求。為了避免轉換非 HTML 請求,中介軟體在編輯響應結果之前對它的 Content-Type 頭標進行檢查。 只有標記為 text/html 或 application/xml+xhtml 的頁面才會被修改。


Django防範CSRF的具體操作

1. 將'django.middleware.csrf.CsrfViewMiddleware'新增到Django的settings.py檔案中的MIDDLEWARE_CLASSES列表中(預設已經新增)。 該中介軟體必須在 SessionMiddleware 之後執行,因此在列表中 CsrfMiddleware 必須出現在SessionMiddleware 之前 (因為響應中介軟體是自後向前執行的)。 同時,它也必須在響應被壓縮或解壓之前對響應結果進行處理,因此CsrfMiddleware必須在GZipMiddleware之後執行。

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',
    # Uncomment the next line for simple clickjacking protection:
    # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
)


2. 在使用到POST方法提交FORM的頁面中,新增csrf_token標籤,例如:

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

3. 在相應的view中,確保“django.core.context_processors.csrf” 上下文處理器被正確使用,有兩種方法實現這一點,一是使用RequestContext,它內部會自動使用到“django.core.context_processors.csrf”。另一種方法是手動使用這個處理器,示例程式碼如下:

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)


相關文章