Protocol-Design

允許多個密碼重置令牌,以及關於隨機數可預測性的問題

  • July 21, 2014

我對密碼重置系統有一些要求,最後還有一些關於其安全性的問題。

要求

目的是提供滿足以下屬性的密碼重置機制:

  1. 每個使用者有多個令牌,以允許電子郵件延遲不會引起混淆。
  2. 令牌是一次性的並且會過期。
  3. 對重置資訊數據庫具有隻讀訪問權限的人無法輕鬆重置使用者密碼。
  4. 抵抗重放攻擊、定時攻擊和(可能)不安全的隨機數生成器。見下文。

假設/細節

  • 有一個在應用程序之外不會知道的秘密隨機值。
  • 一旦使用者使用密碼重置令牌重置其密碼,使用者的所有可用令牌都會從數據庫中刪除。

大綱

請注意,||這裡是串聯。給出的方法是Devise身份驗證庫的修改版本。具體來說,修改是現在有多個token。

讓我們S提前選擇一個固定的秘密。

要為使用者構造一個重置令牌U,請生成一個(安全)隨機數r並考慮該對

(id, r)

其中id從遞增的計數器值中選取。產生

S' = PBKDF2(S)

加鹽,讓S'成為 HMAC 值的關鍵

h = HMAC(S', id || r).

儲存重置資訊

(U, id, h, e),

e到期時間,在發送(id, r)給使用者之前。

當有人嘗試重置密碼時,他們會為我們提供使用者提供的 theid和 for值r

(id_user, r_user).

用於id_user查找以前儲存的(U, id, h, e)資訊。

如果id_user對應沒有這樣的資訊,則無事可做。如果e是過去,則令牌已過期。

再次生成S' = PBKDF2(S),並比較

HMAC(S', id_user || r_user)

與之前的 h 值,即

HMAC(S', id || r).

如果這兩個值匹配(見下面的註釋),那麼令牌是有效的,我們允許使用者U重置他們的密碼。當他們這樣做時,所有儲存的重置資訊((U, id, h, e)給定的條目U)都將被刪除。

筆記

希望前幾個要求顯然得到滿足(多個令牌等)。值得解釋的主要問題可能是:對重置資訊數據庫具有隻讀訪問權限的人無法輕鬆重置使用者密碼。

因為令牌值本身並沒有儲存在數據庫中,只有對應的HMAC,能夠讀取數據庫的人無法構造一個有效的重置密碼URL。

至於上面的相等性檢查:如果使用者篡改 的值(id, r),他們將生成一個完全不同的值,h該值應避免暴露時序資訊。

包含S' = PBKDF(S)(使用鹽)是為了使 HMAC 值的生成成本更高,因為令牌應該具有與密碼相似的屬性。

允許可預測的隨機數

如果隨機數生成器曾經生成攻擊者可以預測的數字,那麼很容易找到正確的 ID 值,從而獲得有效的重置連結。

至少在撰寫本文時,一些數字生成器依賴於使用者空間算法,這可能是一個問題:http ://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers/

為了對此保持偏執(相關係統涉及各種個人資訊)並解決可預測隨機數的問題,我們可以嘗試將 HMAC 值發送給使用者,以便我們驗證真實性。

之前,我們發送

(id, r)

給使用者,這是一個遞增的 ID 計數器值和隨機數。相反,發送使用者

(id, r, h).

在處理重置請求時,我們會收到

(id_user, r_user, h_user).

我們可以取這個值並通過檢查是否等於 來驗證 既沒有id_userr_user沒有被篡改。h_user``HMAC(S', id_user || r_user)

完成該驗證步驟後,我們可以像以前一樣使用id_user查找(U, id, h, e)和繼續。

如果攻擊者曾經預測過隨機數r(因此(id, r)),他們將不知道如何生成有效的 HMAC,因為它需要S'哪個是秘密的,並且這對(id, r)是以前從未見過的。

請注意,我們從不用於h_user查找(U, id, h, e)資訊,因此數據庫不應該在其查找算法中暴露時間攻擊。

奇怪和問題

  1. 它真的可以抵禦定時攻擊、重放攻擊等嗎?這感覺是邊緣滾動你自己的加密貨幣。有問題嗎?
  2. 有沒有更簡單的方法?
  3. 允許攻擊者生成任意數量的重置令牌會降低哪些安全屬性,因為我們允許存在多個令牌並且任何人都可以發送重置?
  4. 嘗試防禦表面上安全的隨機數生成器假設的未來錯誤是否不合理?(編輯:為清楚起見重新措辭。)
  5. 如果這個方案對可預測的r值是安全的,那麼它不等於只使用(id, h)轉換id為 GUID/UUID 的提供嗎?

更新:

我懷疑嘗試防禦例如 OpenSSL 隨機性錯誤實際上是不合理的,這導致我遇到上述問題的另一個問題:在沒有 HMAC 的情況下簡單地儲存(U, PBKDF2(r))和發送給使用者有什麼問題?r如果有足夠的位,r那麼考慮到令牌在 <= 6 小時內到期,這還不夠安全嗎?

有沒有更簡單的方法?

我認同。

讓伺服器以如下形式發送一個重置令牌:

(deadline, HMAC(server key, id_user || S || deadline))

也就是說,伺服器計算一個允許id_userS以前更改其秘密的身份驗證器deadline。使用的密鑰應該只有伺服器知道並且可以經常更改,因為更改它只會使目前活動的重置令牌無效。

(您可以將S其用作 HMAC 密鑰,但是重置令牌將允許對 進行暴力攻擊S,這可能是不可取的。現在它不允許在不知道伺服器密鑰的情況下進行攻擊。)


要實際重置密碼,使用者必須提供上述令牌,他們的id_user(如果需要,可以是令牌的一部分)——S當然還有一個新的。

伺服器根本不需要重置令牌的數據庫,因為他們需要的所有資訊都包含在使用者發送的令牌中。它驗證最後期限是否在未來,然後重新計算 HMAC 並與令牌中的進行比較。


您的要求是:

  1. 每個使用者有多個令牌,以允許電子郵件延遲不會引起混淆。
  2. 令牌是一次性的並且會過期。
  3. 對重置資訊數據庫具有隻讀訪問權限的人無法輕鬆重置使用者密碼。
  4. 抵抗重放攻擊、定時攻擊和(可能)不安全的隨機數生成器。見下文。
  1. 伺服器可以創建任意數量的重置令牌,使用者可以在截止日期之前使用任何一個。
  2. 如果使用者更改了他們的S,即使仍然有效的令牌也將不再起作用。
  3. 沒有重置資訊數據庫,所以不是問題。
  4. 由於與 2 相同的原因,重放攻擊不起作用。為了避免定時攻擊,伺服器所做的所有比較都應該是恆定時間。完全確定性,所以 RNG 無關緊要。

與您的原始提案相比的優勢:

  • 更容易實現和推理。
  • 更快,因為沒有 PBKDF2。
  • 沒有可以被攻擊的數據庫。
  • 不需要每個令牌的隨機性。

您的更新要簡單得多,這很好,但其他三個因素仍然存在。您還可以通過使r不需要 PBKDF2 足夠大來修復“更快”,但是如果您發現有問題,這會使它使用更多的隨機性。

  1. $ ;;; $ 可能只要你比較安全,雖然你正在申請

$ ;;; $ 一個 pbkdf 到什麼應該是一個均勻隨機的長密鑰。 2. $ ;;; $ 不要打擾計算S';letS是一個均勻隨機的密鑰並使用它。

$ ;;; $ 要為使用者構造重置令牌U,請設置h = HMAC(S, 0 || (id,U,e) )

$ ;;; $ 在發送前 設置H = HMAC(S,1||h)並儲存復位資訊(id,e,H,U)

$ ;;; $ (id,h)給使用者。 $ : $ 當有人試圖重置他們的密碼時,他們會給你使用者提供的

$ ;;; $ (id_user,h_user)分別為id和 的值h。 $ : $ 用於id_user查找

$ ;;; $ 以前儲存(id,e,H,U)的資訊。 $ : $ 如果 id_user 對應沒有這樣的資訊,

$ ;;; $ 那麼就沒有什麼可做的了。如果 e 在過去,則令牌已過期。

$ ;;; $ 比較HMAC(S, 1 || h_user ),H這是HMAC(S, 1 || h ).

$ ;;; $ 如果這兩個值匹配,則令牌有效 … 。 $ : $ …

$ ;;; $ 如果重置綁定到一個 id 僅僅是偶然的,而不是

$ ;;; $ 所需的功能,那麼您可以使用(U,e)而不是(id,U,e). 3. $ ;;; $ 你只是失去了量化的安全性。 $ : $ (攻擊者可以對 HMAC 進行更多查詢。) 4. $ ;;; $ 不,因為這很容易做到。 5. $ ;;; $ (id, h)即使id變成GUID/UUID 也不等同於只使用,

$ ;;; $ 因為只要您重用任何idGUID/UUID.

引用自:https://crypto.stackexchange.com/questions/18247