是否可以從弱熵源創建 128 位 UUID?
我正在查看一段看似流行的 JavaScript 程式碼來生成一個應該是 128 位數字的UUID :
function uuidv4() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); }
這使用瀏覽器的
Math.random()
. 為了進一步剖析這一點,它似乎主要是用x
單獨呼叫 Math.random API 來替換字元串中的每個字元,以創建一個十六進制數字(4 位),例如:function getRandomHexChar() { let randomChar = Math.random(); // 0.6429364007765519 randomChar = randomChar * 16; // 10.28698241242483 randomChar = randomChar | 0; // 10 randomChar = randomChar.toString(16); // a return randomChar; }
對於我們的應用程序,我假設我們絕對需要 UUID 是唯一的,否則如果重複它可能會發生壞事。但是我想知道的是它是否需要使用加密安全的 PRNG 來保證它是唯一的?
顯然Math.random 曾經返回的隨機數限制為 $ 2^{32} $ . 不過現在在 Chrome、Firefox 和 Safari 中稍微好一點,它們能夠返回限制為的數字 $ 2^{128} $ (但它現在使用不安全的 xorshift128+ 算法)。此外,這當然不是“所有”瀏覽器,所以估計 Math.random 只給出可能是安全的 $ 2^{32} $ 一點點的熵。
所以我想我的問題真的可以歸結為:重複呼叫 Math.random (即非加密安全的 128 位 RNG 或 $ 2^{32} $ 熵位)像這樣,例如
getRandomHexChar() + getRandomHexChar() + ...
一次連接 4 位偽隨機性,直到獲得 128 位數字,這真的會給出 128 位的安全唯一 UUID 嗎?還是產生的 UUID 中的熵要低得多?
熵永遠不會高於您輸入的數量。因此,如果您需要 128 - 4 = 124 位並且輸入 32 位,則可以放心,剩下的數量最多為 32 位。真的就是這麼簡單。在這種情況下,由於生日限制,很有可能發生碰撞。
現在,通常您在正常使用期間可能不會發現受騙者,但對手可能會簡單地嘗試看看是否可以進行碰撞。在那種情況下,所有的賭注都沒有了,因為最終 RNG 根本就不是加密安全的。
我也會擔心熵源。如果它是從系統時鐘中獲取的 32 位,那麼它實際上根本就不是熵,僅舉一個常見的選項。
盡量避免在客戶端完全生成 UID。
如果這確實是您需要的東西,那麼現在瀏覽器中的 JavaScript有微妙的加密,請改用加密安全的隨機數生成器。不過要小心龍:“Web 密碼學規範沒有規定最小的熵度。” …這可能尤其是非標準/嵌入式瀏覽器的問題。