解決Django提交表單報錯:CSRF token missing or incorrect的問題
1、在Django提交表單時報錯:Django提交表單報錯:
CSRF token missing or incorrect
具體報錯頁面如下:
2、有道詞典翻譯後如下:
通常,當存在真正的跨站點請求偽造時,或者Django的CSRF機制沒有被正確使用時,就會出現這種情況。至於郵遞表格,你須確保:
您的瀏覽器正在接受cookie。
檢視函式將一個請求傳遞給模板的呈現方法。
在模板中,每個POST表單中都有一個{% csrf_token %}模板標記,目標是一個內部URL。
如果您沒有使用CsrfViewMiddleware,那麼您必須在任何使用csrf_token模板標籤的檢視以及那些接受POST資料的檢視上使用csrf_protect。
該表單有一個有效的CSRF令牌。在登入另一個瀏覽器選項卡或登入後單擊back按鈕之後,您可能需要使用表單重新載入頁面,因為登入後令牌會旋轉。
您將看到這個頁面的幫助部分,因為在Django設定檔案中有DEBUG = True。將其更改為False,將只顯示初始錯誤訊息。
您可以使用CSRF_FAILURE_VIEW設定自定義這個頁面。
3、解決辦法:
(1)、確定專案底下的settings.py檔案,是否存在django.middleware.csrf.CsrfViewMiddleware:
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware','django.contrib.sessions.middleware.SessionMiddleware','django.middleware.common.CommonMiddleware','django.middleware.csrf.CsrfViewMiddleware','django.contrib.auth.middleware.AuthenticationMiddleware','django.contrib.messages.middleware.MessageMiddleware','django.middleware.clickjacking.XFrameOptionsMiddleware',]
(2)、如果確定settings.py檔案有配置了,還是報錯,就要在form表單底下加一行程式碼:
{% csrf_token %}
這樣應該就不會報上面錯誤了,以上內容僅供學習參考,謝謝!
補充知識:Django中csrf token驗證原理
我多年沒維護的部落格園,有一篇初學Django時的筆記,記錄了關於django-csrftoekn使用筆記,當時幾乎是照抄官網的使用示例,後來工作全是用的flask。部落格園也沒有維護。直到我的部落格收到了如下評論,確實把我給問倒了,而且我也仔細研究了這個問題。
1. Django是怎麼驗證csrfmiddlewaretoken合法性的?
2. 每次重新整理頁面的時候<input>中的csrf的value都會更新,每次重複登入的時候cookie的csrf令牌都會重新整理,那麼這兩個csrf-token有什麼區別?
image.png
CSRF(Cross Site Request Forgery protection),中文簡稱跨站請求偽造。
django 第一次響應來自某個客戶端的請求時,會在伺服器端隨機生成一個 token,把這個 token 放在 cookie 裡。然後每次 POST 請求都會帶上這個 token,
這樣就能避免被 CSRF 攻擊。
這樣子看起來似乎沒毛病,但是評論中的第三個問題,每次重新整理頁面,form表單中的token都會重新整理,而cookie中的token卻只在每次登入時重新整理。我對csrftoken的驗證方式起了疑問,後來看了一段官方文件的解釋。
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.
官方文件中說到,檢驗token時,只比較secret是否和cookie中的secret值一樣,而不是比較整個token。
我又有疑問了,同一次登入,form表單中的token每次都會變,而cookie中的token不便,django把那個salt儲存在哪裡才能保證驗證通過呢。
直到看到原始碼。
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會驗證表單中的token和cookie中token是否能解出同樣的secret,secret一樣則本次請求合法。
同樣也不難解釋,為什麼ajax請求時,需要從cookie中拿取token新增到請求頭中。
網上有不少關於django csrf token驗證原理的文章都是錯的,是因為他們根本不知道csrf-token的結構組成,我也是卡在第三條評論那.然後看了官方文件,和CsrfViewMiddleware中介軟體原始碼然後才恍然大悟。
以上這篇解決Django提交表單報錯:CSRF token missing or incorrect的問題就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。