1

我在Django REST框架中使用TokenAuthentication來讓腳本遠程訪問我的API。運行API的域落後於TLS證書。與CSRF/CORS的TokenAuthentication問題的Django REST框架

我已經搜遍了很多來源,並且在來這裏弄清楚我的問題是什麼之前嘗試了很多選擇。總之,當我嘗試發佈時,我仍然會收到CSRF verification failed. Request aborted.錯誤。

這是我的觀點:

# @csrf_exempt 
@api_view(['POST']) 
@authentication_classes((TokenAuthentication,)) 
@permission_classes((permissions.IsAuthenticated,)) 
def create_object(request): 

csrf_exempt裝飾無關這裏完成。所以,我也試了一下我的urls.py

url(r'^create_object/', csrf_exempt(views.create_object),), 

我甚至嘗試寫一個定製的裝飾,並採用this suggestion。即使當我這樣做,我甚至不能在得到失敗之前讓裝飾器執行。也許我的中間件訂購有問題?

'sslify.middleware.SSLifyMiddleware', 
'django.middleware.security.SecurityMiddleware', 
'django.contrib.sessions.middleware.SessionMiddleware', 

'corsheaders.middleware.CorsMiddleware', 

'django.middleware.common.CommonMiddleware', 
'django.middleware.csrf.CsrfViewMiddleware', 

'corsheaders.middleware.CorsPostCsrfMiddleware', 

'django.contrib.auth.middleware.AuthenticationMiddleware', 
'django.contrib.auth.middleware.RemoteUserMiddleware', 
'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 
'django.contrib.messages.middleware.MessageMiddleware', 
'django.middleware.clickjacking.XFrameOptionsMiddleware', 

這裏是我的Django CORS設置:

CORS_ORIGIN_ALLOW_ALL = False 
CORS_ORIGIN_WHITELIST = ('example.com',) 
CORS_REPLACE_HTTPS_REFERER = True 
+0

我的解決方案(因爲我找不出原因)是添加一些在csrf之前執行的中間件,它在請求路徑上檢查請求對象以設置標記以跳過保護。明天我會有機會發布代碼作爲答案。 –

回答

1

正如承諾的,這裏是我提出的解決方案。無可否認,這並不完美。我無法確定潛在的問題(爲什麼在HTTPS上應用程序沒有響應csrf_exemptCORS_REPLACE_HTTPS_REFERER),但想出了這個有限的解決方案。

STEP 1

首先,我子類整個CsrfViewMiddleware類到我自己的版本,並把它放在了我的中間件(從原來的quertion變化標記):

'sslify.middleware.SSLifyMiddleware', 
'django.middleware.security.SecurityMiddleware', 
'django.contrib.sessions.middleware.SessionMiddleware', 

'corsheaders.middleware.CorsMiddleware', 

'django.middleware.common.CommonMiddleware', 
#'django.middleware.csrf.CsrfViewMiddleware', ##CHANGE 
'myapp.csrf.CsrfViewMiddleware', ##CHANGE 

'corsheaders.middleware.CorsPostCsrfMiddleware', 

'django.contrib.auth.middleware.AuthenticationMiddleware', 
'django.contrib.auth.middleware.RemoteUserMiddleware', 
'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 
'django.contrib.messages.middleware.MessageMiddleware', 
'django.middleware.clickjacking.XFrameOptionsMiddleware', 

在約行160 我的版本CsrfViewMiddleware,我將現有條件替換爲:

  acceptable_referers = ['https://%s' % u for u in settings.CORS_ORIGIN_WHITELIST] + ['http://%s' % u for u in settings.CORS_ORIGIN_WHITELIST] 
      if not same_origin(referer, good_referer) and referer not in acceptable_referers: 

這讓我越過了無效的referer問題,這很好,因爲我將域名列入白名單。它基本上與CORS_REPLACE_HTTPS_REFERER的結果相同。我的版本與settings.CORS_ORIGIN_WHITELIST交叉引用referer頭,而CORS_REPLACE_HTTPS_REFERER方法臨時更改request引用者。我認爲沒有足夠的安全解決方案 - 但這是另一次談話。

STEP 2

在這一點上,我仍然得到未找到錯誤的CSRF的cookie。爲了解決這個問題,而且由於csrf_exempt沒有respoding(它好像中間件正在執行太早),我添加了一個新的中間件的:

'sslify.middleware.SSLifyMiddleware', 
'django.middleware.security.SecurityMiddleware', 
'django.contrib.sessions.middleware.SessionMiddleware', 

'myapp.csrf.CsrfSkipMiddleware' ##ADDED 

'corsheaders.middleware.CorsMiddleware', 

'django.middleware.common.CommonMiddleware', 
#'django.middleware.csrf.CsrfViewMiddleware', ##REMOVED 
'myapp.csrf.CsrfViewMiddleware', ##ADDED 

'corsheaders.middleware.CorsPostCsrfMiddleware', 

'django.contrib.auth.middleware.AuthenticationMiddleware', 
'django.contrib.auth.middleware.RemoteUserMiddleware', 
'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 
'django.contrib.messages.middleware.MessageMiddleware', 
'django.middleware.clickjacking.XFrameOptionsMiddleware', 

這個新的中間件的一塊基本上是設置一個標誌上請求對象(_dont_enforce_csrf_checks),該對象已存在於CsrfViewMiddleware的股票版本中,並通知腳本忽略csrf檢查的其餘部分。爲此,它會根據我選擇從settings.CSRF_SKIP_URLS中的csrf中刪除的路徑列表來檢查頁面路徑。

class CsrfSkipMiddleware(object): 

    def process_request(self, request): 
     CSRF_SKIP_URLS = [re.compile(expr) for expr in settings.CSRF_SKIP_URLS] 
     path = request.path_info.lstrip('/') 

     if any(m.match(path) for m in CSRF_SKIP_URLS): 
      setattr(request, '_dont_enforce_csrf_checks', True) 

思考

同樣,不是最好的實現。但是,爲了我的目的,它是有效的。思想仍然受歡迎。

0

我看到你使用Django CORS標頭。 我正面臨類似的問題,並指定: CORS_REPLACE_HTTPS_REFERER = Truesettings.py解決了這個問題。

+0

好點。這就是爲什麼我把CORS的東西放在那裏。我編輯了我的問題以包含我的CORS設置。我有''CORS_REPLACE_HTTPS_REFERER = True'' –