1. 程式人生 > 程式設計 >解決Django提交表單報錯:CSRF token missing or incorrect的問題

解決Django提交表單報錯:CSRF token missing or incorrect的問題

1、在Django提交表單時報錯:Django提交表單報錯:

CSRF token missing or incorrect

具體報錯頁面如下:

解決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有什麼區別?

解決Django提交表單報錯:CSRF token missing or incorrect的問題

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的問題就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。