使用包含 userId 的密鑰的對稱加密是否通過身份驗證?
場景:
有一個 Web 應用程序,其中所有權檢查的時間很昂貴,因此在開發過程中,所有使用者都能夠通過更改 REST url 中的 id 來訪問所有其他使用者的對象(比如蘋果)。
通過向客戶端發出簽名(未加密)JWT 來驗證使用者身份,其中聲明之一是 userId。
最初嘗試對伺服器進行適當的所有權檢查,但由於速度非常慢,現在每個人都在尋找解決方法。
團隊已做出決定——我反對——改為實施以下解決方案:
- 使用者不是向使用者發送他的蘋果的 id,而是在伺服器上接收對稱加密的 id。這應該可以防止使用者隨機猜測 id(id 是自動遞增的數字)。
- 當使用者請求一個特定的蘋果時,他使用他收到的加密 id 請求它,伺服器解密該 id 並通過它獲取資源。
- 為了防止一個使用者重複使用其他使用者的 id,加密和解密是使用一個密鑰完成的,該密鑰將來自 JWT 令牌的 userId 連接到它。這樣,您必須有一個匹配的 JWT 令牌才能使您的令牌可解密。
- 加密由Jasypt的 BasicBinaryEncryptor 完成,其中明文 id 被轉換為字節,生成的字節被 base64 編碼。反向解密也是一樣。
我的問題:
除了背誦諸如“不要發明自己的安全”之類的話,我沒有正確反對這一點的知識,但這似乎是一場等待發生的可怕災難。
簽名聲明部分的 JWT 令牌對我來說似乎不太可疑。它們儲存在localstorage中,簽名算法由伺服器設置,秘密很長,其中有過期。
對我來說似乎有問題的是密文沒有簽名,所以如果使用者可以以某種方式偽造請求,他仍然可以訪問所有其他使用者數據。
是否有可能以某種方式在這裡偽造請求?例如,通過弄亂這些位,看看伺服器是否拋出錯誤(或什麼樣的錯誤)。
我正在尋找易於理解的理由來說明為什麼這樣做是一個壞主意,以便向我的同事提出一個可靠的論點(或確信它不是)。
首先也是最重要的:停止使用 JWT 進行會話以及為什麼不能將其破解為工作。
除了背誦諸如“不要發明自己的安全”之類的話,我沒有正確反對這一點的知識,但這似乎是一場等待發生的可怕災難。
所以你的主要問題是如何讓你的同事相信這是一個糟糕的計劃?
如果告訴他們不應該編寫自己的密碼學還不夠,請告訴他們他們的定制解決方案比其他解決方案更昂貴、更複雜和更不安全。請參閱下面的替代方案。
對我來說似乎有問題的是密文沒有簽名,所以如果使用者可以以某種方式偽造請求,他仍然可以訪問所有其他使用者數據。
簽名是不對稱的(昂貴的)並且(通常)比對稱的 MAC 大。改用對稱解決方案會更好。同樣,加密不是驗證,複製粘貼密文也不是證明權威。
是否有可能以某種方式在這裡偽造請求?例如,通過弄亂這些位,看看伺服器是否拋出錯誤(或什麼樣的錯誤)。
如果這些對象 ID 是使用 CTR 模式加密的,那麼增加密文仍然會為您提供下一個 ID。相反,如果對象 ID 是使用 PRP 加密的,那麼您可以在 $ 2^{b/2}/n $ 猜測假設 $ b $ -位塊大小和 $ n $ 存在有效的 ID。如果你有 10 億個 ID,那麼這只是 $ 18446744 \approx 2^{24} $ 嘗試。(有人可以驗證嗎?)
從密碼學上講,這很弱。在實踐中,您應該有速率限制,並且應該減慢重複嘗試無效 ID 的使用者,所以這可能不會太糟糕,但只有 $ 18 $ 百萬猜測 $ 1 $ 十億的可能性 這真的取決於你認為這些蘋果有多敏感。如果它們沒有價值,沒有人會嘗試。如果他們很敏感,那隻是時間問題。
我正在尋找易於理解的理由來說明為什麼這樣做是一個壞主意,以便向我的同事提出一個可靠的論點(或確信它不是)。
它是定制的、緩慢的、昂貴的、未經驗證的和不必要的!
備選方案 1:每個使用者隔離的蘋果集
如果蘋果不能在使用者之間共享,則只顯示與相關使用者相關的 ID。即如果愛麗絲有 $ 3 $ 蘋果,它們是 $ 0 $ , $ 1 $ , 和 $ 2 $ . 如果鮑勃有 $ 2 $ 蘋果,它們是 $ 0 $ , 和 $ 1 $ .
此外,這可以綁定到 HTTP cookie,這樣惡意 JavaScript 就無法洩露儲存在 LocalStorage 中的 JWT。更好的是,這根本不依賴於 JavaScript。
備選方案 2:基於能力的蘋果共享
如果蘋果可以在使用者之間共享,請查看功能和杏仁餅。
能力是一種不可偽造、不可猜測和可交流的權威令牌。你只能從已經擁有它的人那裡獲得能力。能力比密碼學更強大,但它們依賴於受信任的系統。使用密鑰作為上限,密碼學可以模擬基於知識(而不是擁有)的較弱形式的能力。Macaroon 是一種僅依賴於安全密鑰雜湊 (HMAC) 的加密功能。沒有昂貴的非對稱加密或簽名。
範例蛋白杏仁餅乾(近似範例,請參閱論文以獲得更好的定義):
$$ \begin{aligned} s &= \text{new_macaroon}(\text{server_secret}, \text{nonce})\ &= (nonce, \text{HMAC}(\text{server_secret}, n))\ a &= \text{add_caveat}(\text{authority}, \text{caveat})\ &= (\text{authority}0, \text{authority}{n-1}, \dots, 0 | \text{caveat}, \text{HMAC}(\text{authority}_n, 0 | \text{caveat})\ i &= \text{invoke}(\text{authority}, \text{message})\ &= (\text{authority}0, \text{authority}{n-1}, \dots, 1 | \text{message},\text{HMAC}(\text{authority}_n, 1 | \text{message}) \end{aligned} $$ $ s $ 是不受限制的憑證。它總是有效的。從技術上講,伺服器可以通過 $ nonce $ ,但這不是假設的。 $ a $ 添加了額外的警告。即在一段時間後使憑證過期,或者限制可以訪問或呼叫的對像或功能。最後 $ i $ 呼叫授權向伺服器發送一些消息。如果所有警告評估均未失敗,則消息被批准和評估。
任何時候共享未呼叫的權限時,我們都必須使用安全傳輸來防止 MiTM 學習密鑰。呼叫時,我們僅顯示公共資訊和將權限與消息綁定的證明。方便的是,這也使 CSRF 令牌過時,但它不會阻止按原樣重放。
請注意,macaroon 不假定係統具有“使用者”或需要撤銷或到期。伺服器負責選擇初始警告,使用者可以在共享憑證時添加他們想要的任何警告。如果 Alice 與 Bob 共享她的憑證以訪問 $ \text{apple}_5 $ ,那麼 Bob 只能訪問這個蘋果,而不能訪問 Alice 的任何其他蘋果。此憑證也不假定簽名。
只有當大量(或未知)受眾需要離線驗證完整性時,簽名才有意義。您的伺服器是唯一生成並驗證這些憑據是否正確的伺服器?如果您的使用者需要授權第三方服務代表他們執行某些操作,他們將共享一個預置的憑據以及他們想要的任何警告。此外,使用者可以包含一種特殊的警告,它會 ping 回他們自己的伺服器以請求執行某些操作的權限。這使使用者能夠撤銷這些能力。
使用者可以添加警告並離線分發它們,而無需與您的伺服器互動。