簡體   English   中英

在 cookie 中保存身份驗證令牌(Django Rest Framework + React)

[英]saving authentication token in cookie (Django Rest Framework + React)

所以,正如標題所說,我正在使用 Django Rest Framework,結合 React。

我使用令牌身份驗證對用戶進行身份驗證。 現在我面臨一個問題。 當我重新加載頁面(例如按 F5 鍵)時,所有狀態都消失了,在這種情況下我無法保存令牌,需要用戶再次登錄。

我想過將令牌存儲在 cookie 中,但這似乎不太安全。

還有其他類似的問題,但沒有答案真正解釋這是多大的安全風險。 我認為它相當高,因為擁有令牌似乎足以作為后端的某個人進行身份驗證。

所以,我的問題是:我假設將我的身份驗證令牌存儲在 cookie 中是不安全的嗎?

注意:我正在考慮切換到基於會話的身份驗證,但我寧願保護我的工作並保留令牌身份驗證。

我忘記了我的舊答案仍然在互聯網上獲得了一些牽引力……而且我后來意識到這部分是錯誤的。

更新答案:

I thought about storing the token in a cookie, but that doesn't seem very safe.

如果操作正確,它就足夠安全了。 是的,任何對系統有物理訪問權限的人仍然可以讀取 cookie。 更多關於這個下面。

讓我們澄清一件事,絕對有必要在客戶端(在本例中為瀏覽器)存儲一些數據,並通過 API 調用發送這些數據以驗證用戶身份。 讓我們稱這些數據為“令牌”。

當您在 API 調用中發送此令牌時,對系統具有物理訪問權限的任何人都可以查看它。 此外,沒有必要對其進行加密,因為...

  1. 您需要在發送之前對其進行解密,這使得未加密的字符串可讀。
  2. 您還需要在客戶端存儲解密密鑰,這讓我們回到了同樣的問題。

有什么選擇? 老實說,就這樣吧。 大多數網站都是這樣工作的(幾乎)。 除非該網站持有一些非常敏感的信息。 在這種情況下,可能會研究基於時間的密碼、基於硬件的密碼、生物特征? 這些方法主要將安全保存密鑰的責任轉嫁給用戶。

你當然可以,讓它更安全。 以下是一些提示:

  1. 在一段時間/不活動后從服務器中刪除令牌。
  2. 更新隨機請求的令牌,並使之前的無效。
  3. 允許用戶查看活動會話並刪除它們。
  4. 將它綁定到用戶 IP,或者一些難以復制的東西。 每次用戶使用不同的IP登錄時,都要求輸入密碼。

考慮到這一點,讓我們談談存儲令牌。

我們只需要確保其他網站、惡意腳本和軟件無法訪問存儲的令牌。 (如上所述,用戶始終可以讀取令牌。)

您可以將其存儲在cookieslocalStorage 兩者都可以正常工作,但localStore旨在存儲更大的數據。 Cookies最多可以存儲 4096 字節的數據 - 這足以存儲令牌。 Cookies在處理 SSR(服務器端渲染)時也有幫助。 不過,在 React 中處理 cookie 可能會很棘手。 (提示:試試 next.js,它內置了對帶有 React 的 cookie 和 SSR 的支持。)

如果有幫助,您還可以在 cookie 中指定過期時間。

TL;DR:使用Cookies非常好。 只要正確使用它。

感謝@ShayanSalehian 指出這一點: LocalStorage is subject to XSS and cookie is subject to CSRF. So I think using cookies + CSRF is the most secure way even in TokenAuthentication for storing tokens on client... LocalStorage is subject to XSS and cookie is subject to CSRF. So I think using cookies + CSRF is the most secure way even in TokenAuthentication for storing tokens on client...


舊答案(劇透警告,部分錯誤。):

這也是我不得不面對的事情。 在這個過程中失去了幾個晚上的睡眠。

免責聲明:我不是任何安全專家。 只是有點痴迷(閱讀:偏執)。

簡短版本(回答您的問題):我最終使用 window.localStorage 來存儲令牌。 雖然我不相信這是最好的做法,但這不僅僅是關於“存儲”部分 - 閱讀長版以了解更多信息。

長版:首先,讓我們澄清一些事情。 React 更像是一個移動應用程序,而不是一個網頁/網站。 我不是在談論 React Native - 我的意思是React.js

為什么我說它更像是一個移動應用程序而不是一個網站? 傳統網站通常使用基於會話的身份驗證,瀏覽器/服務器通常為此准備。 顯然,這是一項毫不費力且無縫的任務。

在移動應用程序(或客戶端獨立應用程序)中,您需要維護某種令牌來基本上告訴服務器“嘿,是我!我前段時間訪問過。這是我的身份證。請讓我進去好嗎?” . 問題是,很難在客戶端保持令牌安全。 在 Android v4.3 之前,Android 本身並沒有提供任何安全的方式來存儲身份驗證令牌。 這也不夠安全,所以他們不久前引入了硬件支持的密鑰庫。 這就是為什么某些應用程序不能(並且仍然不能)在有 root 權限的設備上運行的原因。 在此處閱讀更多相關信息: https : //stackoverflow.com/a/19669719/3341737

與 React/獨立 Web 應用程序相比,谷歌(在某種程度上)控制着 Android 客戶端。 他們實現基於硬件的密鑰庫相對容易。 對於網絡應用程序,有大量的瀏覽器,有數百個版本等等。

回到 window.localStorage。 與 Cookie 類似,localStorage 對每個域都是隔離的。 由於它是一個較新的 API,因此它的設計方式比舊的 Cookie 更好。

加密密鑰沒有意義(盡管您可能會混淆它),因為您還需要將解密密鑰存儲在本地某個地方。 因此,如果有人可以訪問令牌,他們也可以訪問解密密鑰。

這個問題的第二個方面(以及為什么“存儲”不是唯一的問題)是 - 你真的想保護誰的令牌?

  1. 中間的人? 使用 SSL。
  2. 其他網站? 他們無法訪問您域的 localStorage。
  3. 一些人? 真的。 如果他們可以物理訪問 PC,他們可以輕松獲得令牌。 物理訪問實際上使他們成為用戶(您想保護令牌不受用戶影響?)。 考慮到此人具有物理訪問權限,即使您以某種方式安全地存儲它,您也無法保護它。

為什么不? 因為您需要隨每個請求發送令牌 - 每個請求發送的數據在瀏覽器網絡檢查器中可用。 因此,無論您在何處以及如何存儲令牌,它都可能被具有 PC 物理訪問權限的人竊取。

為什么不是餅干? 兩個原因(實際上是 1 個):

  1. 默認情況下,每個請求都會發送 Cookie。 你真的不需要這個,因為你只需要在 API 調用(而不是頁面加載)期間發送令牌。 此外,由於您使用的是 DRF(適用於任何 RESTful API 后端),您可能需要以特定方式向服務器發送令牌 - 這需要以任何方式自定義方法。
  2. window.localStorage 是一個簡潔的小 API(只是window.localStorage.setItem('key', 'value') )。 此外,與 Cookie 相比,最大大小限制要高得多。

因此,window.localStorage 對我來說似乎是一個可行的選擇。 如果您有更好的解決方案,請啟發我。

話雖如此,這並不意味着您不能提高安全性。 以下是一些建議:

  1. 在一段時間或一段時間不活動后,從 DB 中使令牌無效/刪除。
  2. 使用足夠隨機的請求發送更新的令牌(也使前一個無效),並用新的令牌替換存儲的令牌。
  3. 授予用戶刪除其帳戶保存的令牌以及每個令牌的最后活動的權限。
  4. 如果您真的(真的)擔心,請將令牌與用戶 IP(或其他無法克隆到另一個系統的內容)綁定。 如果用戶從新設備/位置/瀏覽器登錄,請使用 2FA。

下一個方法是什么:在 OAuth https://auth0.com/docs/tokens/refresh-token/current 中存儲不是令牌而是refresh_token

您應該決定為您的安全需要保留哪些超時,因此每次令牌死亡或為空后,您都可以嘗試恢復會話是存儲在 cookie 中的refresh_token

即使潛在的破解者會在 const 超時后獲得 refresh_token 也沒有意義

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM