用於往返驗證的 HMAC
我需要生成 URL 以允許下載單個文件,無需身份驗證。這些連結將通過電子郵件發送,我理解並接受給定連結被其收件人共享(或在傳輸過程中被截獲)的風險。
每個文件都由一個 UUID 標識,在 SQL Server 中使用 NEWID() 生成。我需要防止知道連結格式的攻擊者暴力猜測其他 UUID 並訪問以這種方式共享的其他文件。另請注意,連結會自動過期。
我目前的連結方案將 UUID 與 HMAC 一起發送。HMAC 是使用以下方法生成的:
- 由系統級 salt + 每個文件的 nonce salt + UUID 組成的有效負載
- 用於計算 SHA2-512 HMAC 的 128 字節系統級密鑰
這其中的任何部分是多餘的還是過度的?在這種情況下,使用 HMAC 是否比簡單的強雜湊獲得任何額外的安全性?
有關 T-SQL NEWID() 的討論,請參閱SQL Server:NEWID() 是否總是提供唯一 ID?在 StackOverflow 上。
如果您查看RFC 4122,那麼您可以看到哪些位不是隨機的。我認為 UUID 中有 128 位,其中 6 位是非隨機的以指示使用的方案。剩下 122 位的 UUID,這可能足以將它們視為相對隨機的。只有當你生成數以百萬計的它們時,才有可能發生碰撞。但是,由於生日悖論,雜湊通常具有兩倍於所需安全級別的輸出大小是有原因的。並且 122 / 2 = 61 位安全性,這是偏低的。因此,至少擴展值的隨機性可能是一個好主意。
當然,您始終可以向它們添加隨機位,使用密鑰的 MAC 就可以了。它可以讓你相對自信地拒絕嘗試。此外,您可以在數據庫查找之前拒絕這些。可信度的多少取決於 MAC 的安全性,通常受限於 MAC 的輸出大小。當然,它確實需要額外的密鑰管理負擔。
或者,您可以簡單地向 UUID 添加更多隨機位或生成專有的 256 位 UUID。但是,我認為 UUID 上的 MAC 方案相對優雅,因為 MAC 可以在 UUID 上,同時保持 UUID 方案不變,並且可以通過添加鹽來擴展它。當然,密鑰必須保密,否則對手可以生成相同的密鑰。
缺點是與 MAC 和可能的鹽一起發送的 UUID不再標準化,因此您必須考慮另一種 UUID 和 MAC 的規範編碼。
如果我理解正確,您的目標是創建一個不可偽造的不記名令牌,您將發送給使用者,使用者稍後可以將其呈現給您以獲取對資源的訪問權限,例如文件。對手應該無法猜出他們沒有直接給出的任何令牌,即使他們得到了很多很多的令牌。
為了辨識文件,您似乎受到了使用 UUID 作為令牌的一部分的限制。這裡有兩種可能:
- 您只需要使用 UUID語法。
如果您只需要使用 UUID 語法,並且您可以為每個文件重新決定 UUID 獲取的內容(一旦您實現了新的不記名令牌設計),您可以簡單地選擇一個統一的隨機版本 4 UUID與加密安全隨機數生成器,以便 UUID 不可預測。 SQL Server 的 NEWUUID() 是否能做到這一點我不能告訴你。
有 $ 2^{122} $ 版本 4 UUID。即使你發出一個 quintillion 不同的 UUID,大約 $ 2^{50} $ ,即使攻擊者嘗試查詢 quintillion 不同的 UUID,攻擊者成功偽造甚至一個 UUID 的機率也小於 $ 2^{100}!/2^{122} = 1/2^{22} $ ——不到百萬分之一。當然,您應該調整這些數字,以獲得您的應用程序將擁有的最大可能的線上頻寬。
碰撞怎麼辦?好吧,暫時先把安全性放在一邊——如果 UUID 之間發生衝突,您的應用程序會為合法使用者做什麼?即使您有一個 quintillion 不同的文件,衝突的機率仍然小於百萬分之一。一般來說,如果有 $ n $ 文件,碰撞的機率小於 $ n^2!/2^{122} $ ,由生日悖論。如果這是一個非常龐大的分佈式系統,那可能是一個問題——也許您應該使用 256 位令牌而不是 ≈128 位令牌作為數據庫鍵。 2. 您實際上需要使用特定的 UUID生成器,並且不能保證 UUID 生成器在密碼學上是不可預測的。
在這種情況下,您需要的不僅僅是 UUID - 您需要附加一個不可偽造的身份驗證器,例如您建議的 HMAC。
您可能需要在不記名令牌上使用身份驗證器還有其他原因。例如,您可能希望對資源進行額外的訪問控制:您可能希望限制對使用者指定的特定目的的訪問,或限制對特定時間段的訪問——並且由於某種原因,您不能將這些訪問控制儲存在旁邊資源本身。也許不記名代幣的經銷商在管理上與文件的保管人分開,他們決定哪些方應該在何時訪問哪些資源。
身份驗證器或消息身份驗證程式碼的標準安全概念是 EUF-CMA,或*(自適應)選擇消息攻擊下的存在不可偽造性*。威脅模型是,攻擊者可以將您的系統作為預言機查詢他們選擇的任何消息的身份驗證器,然後如果他們在沒有向預言機查詢的任何消息上找到身份驗證器,他們就會獲勝。** 合法使用者——不記名令牌的經銷商、文件的保管者——必須維護一個對手當然無法預測的秘密密鑰,否則所有安全措施都是無效的。
當文件的保管者收到不記名令牌時 $ (m, a) $ 在哪裡 $ m $ 是一條消息並且 $ a $ 是身份驗證者,他們可以將消息放在地板上,如果 $ a $ 不是消息的正確身份驗證器 $ m $ . 部分消息可能是隱含的。例如,登錄使用者可能有一個使用者名 $ u $ , 並且可能提供一個 UUID $ i $ 與驗證器一起 $ a $ ; 文件的保管人可能會考慮(唯一編碼的)連接 $ (u, i) $ 成為消息 $ a $ 是一個假定的驗證器。
**HMAC-SHA512 是身份驗證器功能的安全選擇,**儘管它不必要地長——截斷為 256 位是安全的,或者使用 HMAC-SHA256 代替,實際上,如果截斷為 128 位仍然足夠。(衝突與驗證器無關。)在任何情況下都應該使用 256 位密鑰(即使對於 HMAC-MD5)。較長的密鑰沒有優勢,但是由於 HMAC 設計的一個怪癖,很長的密鑰可能會導致麻煩。您還可以使用 SHA-3 KMAC128,或鍵控 BLAKE2,或您喜歡的任何其他基於 PRF 的 MAC。(關於像 Poly1305-AES 這樣的 MAC 的警告:這些本質上是一次性 MAC,需要消息序列號才能安全。我不建議在這裡這樣做。)
剩下的問題是:驗證者的資訊是什麼?通常,您應始終確保身份驗證器涵蓋您將採取行動的所有資訊。 顯然,這包括 UUID 和使用者提供的任何其他內容。
你還加了鹽。鹽有什麼作用? *salt的主要目的是通過分離輸入空間來減輕*對密鑰的多目標攻擊。例如,如果 1000 個不同的站點安裝了您的應用程序,並且出於某種原因在相同 UUID (以及訪問控制時間等)上使用 自己的密鑰發布身份驗證器,那麼攻擊者可以通過並行的彩虹表獲得批量優勢機器以一次僅對單個站點進行攻擊的成本的 1/1000找到站點的密鑰之一。因此,在這種情況下,可能值得在每個身份驗證器中使用 UUID 散列每個站點的鹽。 **但是每個文件的鹽呢?每個文件已經有一個唯一的標識符。所以不需要每個文件的鹽。