Django CSRF防御具體流程

?Django對CSRF的防御主要django.middleware.csrf.CsrfViewMiddleware中間件來實現(xiàn)。通過在settings.pyMIDDLEWARE_CLASSES(新版的Django該項改為MIDDLEWARE)加上django.middleware.csrf.CsrfViewMiddleware來啟用這個中間件。通過Django源碼的django/middleware/csrf.py文件,調(diào)試程序來分析了Django CSRF防御流程。這篇文章記下我的理解。

版本說明:

Django Version:1.9.5
Python Version:2.7

Django CSRF防御具體流程

?首先要清楚Django是怎么驗證一個請求不是CSRF:Django會從請求頭cookie取csrftoken這一項的值,再從POST表單里取csrfmiddlewaretoken這一項(或從請求頭X-CSRFToken?。┑闹担ㄟ^比對兩者是否一致來判斷這個請求是不是非法,非法就返回403狀態(tài)碼。這里的“是否一致”,并不是判斷兩者的值是否相等,而是判斷_unsalt_cipher_token(csrfmiddlewaretoken)_unsalt_cipher_token(csrftoken)是否相等,具體留在后面說。

?而生成csrftokencsrfmiddlewaretoken的代碼在get_token(request)函數(shù)

def get_token(request):
    if "CSRF_COOKIE" not in request.META:
        csrf_secret = _get_new_csrf_string()
        request.META["CSRF_COOKIE"] = _salt_cipher_secret(csrf_secret)
    else:
        csrf_secret = _unsalt_cipher_token(request.META["CSRF_COOKIE"])
    request.META["CSRF_COOKIE_USED"] = True
    return _salt_cipher_secret(csrf_secret)

這個函數(shù)會在渲染模板的時候調(diào)用,具體來說是由csrf context processor調(diào)用。
如果request.META["CRSF_COOKIE"]不存在,就調(diào)用_get_new_csrf_string()函數(shù)來生成一串隨機字符(32個字符,大小寫字母和數(shù)字),賦給csrf_secret,再調(diào)用_salt_cipher_secret(scrf_secret)生成64個字符的字符串賦給request.META["CSRF_COOKIE"],而這個request.META["CSRF_COOKIE"]之后用來設(shè)置COOKIE 的csrftoken。
最后的返回值_salt_cipher_secret(csrf_secret)就渲染到POST表單的csrfmiddlewaretoken。值得一提的是_salt_cipher_secret(csrf_secret)每次的返回值都不一樣,而csrf_secret == _unsalt_cipher_token(_salt_cipher_secret(csrf_secret))

?總的來說,涉及到三個值,csrftoken、csrfmiddlewaretokencsrf_secret,還有兩個函數(shù),_unsalt_cipher_token(token)_salt_cipher_secret(token)。用圖來說明下這兩個過程:

  1. 生成csrftokencsrfmiddlewaretoken。
  2. 驗證csrftokencsrfmiddlewaretoken是否一致。
生成csrftoken和csrfmiddlewaretoken.png

?那_unsalt_cipher_token_salt_cipher_secret這兩個函數(shù)具體怎么實現(xiàn)呢?怎么做到_salt_cipher_secret(csrf_secret)每次返回的token值不同,調(diào)用_unsalt_cipher_token(token)就返回原來的csrf_secret?

?用圖來表示(簡化下,把csrf_secret長度改為3)

?

Django CSRF TOKEN具體生成和驗證算法.png

?上面的過程主要涉及到的數(shù)值運算就這兩條式子(下面的符號都表示一個整數(shù)):

1. Cipher = (Secret + Salt) mod N
2. (Cipher - Salt) mod N 會等于 Secret

其它

  1. django/middleware/csrf.py文件里有個函數(shù):rotate_token(request),這個函數(shù)用來改變csrftoken這個COOKIE。 在用戶登錄后(是指 django.contrib.auth這個組件的登錄)調(diào)用,主要從安全考慮,避免這個COOKIE跟登錄前的一樣。 如果自己實現(xiàn)的登錄邏輯,可以調(diào)用這個函數(shù)提高點安全性。
  2. 一般csrftoken這個COOKIE是不會變的,除了第一點說的登錄,和不存在時重新生成一個。有時候會出現(xiàn)登錄后csrftoken失效的情況。官網(wǎng)一個FAQ
  3. 為什么Django要把csrftokencsrfmiddlewaretoken設(shè)置成不相等,直接生成的時候讓它們相等,驗證的時候判斷是否相等不就好了?個人覺得這樣做有個好處,有時候csrftoken這個COOKIE前端不需要獲取,可以設(shè)置成HTTP ONLY,提高點安全性。 大家怎么看?
  4. 從上面分析的算法來看,csrftokencsrfmiddlewaretoken相同也可以通過CSRF驗證。所以在AJAX請求中,直接取csrftoken值加到請求中就好了。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 此段內(nèi)容簡要來自自強學(xué)堂的教程詳情請查詢自強學(xué)堂 一、 后臺的運作流程 接收request請求 處理數(shù)據(jù) 獲取請求...
    coder_ben閱讀 5,337評論 6 56
  • Refer to: www.threemeal.com/blog/12/ 中間件 中間件是一個鉤子框架,它們可以介...
    蘭山小亭閱讀 16,757評論 9 164
  • 1、不安全的隨機數(shù)生成,在CSRF TOKEN生成、password reset token生成等,會造成toke...
    nightmare丿閱讀 3,990評論 0 1
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,502評論 19 139
  • 22年12月更新:個人網(wǎng)站關(guān)停,如果仍舊對舊教程有興趣參考 Github 的markdown內(nèi)容[https://...
    tangyefei閱讀 35,388評論 22 257

友情鏈接更多精彩內(nèi)容