Django中csrf token驗(yàn)證原理

我多年沒維護(hù)的博客園,有一篇初學(xué)Django時(shí)的筆記,記錄了關(guān)于django-csrftoekn使用筆記,當(dāng)時(shí)幾乎是照抄官網(wǎng)的使用示例,后來工作全是用的flask。博客園也沒有維護(hù)。直到我的博客收到了如下評(píng)論,確實(shí)把我給問倒了,而且我也仔細(xì)研究了這個(gè)問題。
1. Django是怎么驗(yàn)證csrfmiddlewaretoken合法性的?
2. 每次刷新頁面的時(shí)候<input>中的csrf的value都會(huì)更新,每次重復(fù)登錄的時(shí)候cookie的csrf令牌都會(huì)刷新,那么這兩個(gè)csrf-token有什么區(qū)別?

image.png

CSRF(Cross Site Request Forgery protection),中文簡稱跨站請(qǐng)求偽造。
django 第一次響應(yīng)來自某個(gè)客戶端的請(qǐng)求時(shí),會(huì)在服務(wù)器端隨機(jī)生成一個(gè) token,把這個(gè) token 放在 cookie 里。然后每次 POST 請(qǐng)求都會(huì)帶上這個(gè) token,
這樣就能避免被 CSRF 攻擊。

這樣子看起來似乎沒毛病,但是評(píng)論中的第三個(gè)問題,每次刷新頁面,form表單中的token都會(huì)刷新,而cookie中的token卻只在每次登錄時(shí)刷新。我對(duì)csrftoken的驗(yàn)證方式起了疑問,后來看了一段官方文檔的解釋。

When validating the ‘csrfmiddlewaretoken’ field value, only the secret, not the full token, is compared with the secret in the cookie value. This allows the use of ever-changing tokens. While each request may use its own token, the secret remains common to all.
This check is done by CsrfViewMiddleware.

官方文檔中說到,檢驗(yàn)token時(shí),只比較secret是否和cookie中的secret值一樣,而不是比較整個(gè)token。
我又有疑問了,同一次登錄,form表單中的token每次都會(huì)變,而cookie中的token不便,django把那個(gè)salt存儲(chǔ)在哪里才能保證驗(yàn)證通過呢。直到看到源碼。

def _compare_salted_tokens(request_csrf_token, csrf_token):
    # Assume both arguments are sanitized -- that is, strings of
    # length CSRF_TOKEN_LENGTH, all CSRF_ALLOWED_CHARS.
    return constant_time_compare(
        _unsalt_cipher_token(request_csrf_token),
        _unsalt_cipher_token(csrf_token),
    )

def _unsalt_cipher_token(token):
    """
    Given a token (assumed to be a string of CSRF_ALLOWED_CHARS, of length
    CSRF_TOKEN_LENGTH, and that its first half is a salt), use it to decrypt
    the second half to produce the original secret.
    """
    salt = token[:CSRF_SECRET_LENGTH]
    token = token[CSRF_SECRET_LENGTH:]
    chars = CSRF_ALLOWED_CHARS
    pairs = zip((chars.index(x) for x in token), (chars.index(x) for x in salt))
    secret = ''.join(chars[x - y] for x, y in pairs)  # Note negative values are ok
    return secret

token字符串的前32位是salt, 后面是加密后的token, 通過salt能解密出唯一的secret。
django會(huì)驗(yàn)證表單中的token和cookie中token是否能解出同樣的secret,secret一樣則本次請(qǐng)求合法。
同樣也不難解釋,為什么ajax請(qǐng)求時(shí),需要從cookie中拿取token添加到請(qǐng)求頭中。

網(wǎng)上有不少關(guān)于django csrf token驗(yàn)證原理的文章都是錯(cuò)的,是因?yàn)樗麄兏静恢纁srf-token的結(jié)構(gòu)組成,我也是卡在第三條評(píng)論那.然后看了官方文檔,和CsrfViewMiddleware中間件源碼然后才恍然大悟。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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