令牌生成器

在瀏覽器中生成密碼學強度高的隨機令牌、API 金鑰、金鑰與 nonce。可選擇長度、字元集與生成數量。

隨機、不可預測的令牌。 所有隨機性都來自瀏覽器的 crypto.getRandomValues,與瀏覽器生成 TLS 金鑰用的是同一來源。資料不會離開你的裝置。

什麼樣的令牌才算安全

隨機不等於不可預測

大多數語言都提供兩種截然不同的隨機數生成器。Math.random()rand() 這一類是速度優先的偽隨機生成器,種子往往來自時鐘這種廉價來源。用它們打亂播放列表沒問題,用來生成令牌則是災難:攻擊者只要觀察到少量輸出,通常就能還原內部狀態,進而復現該生成器今後產生的每一個值。

密碼學安全的生成器在設計上保證:看到過去的輸出無法推斷未來的輸出。在瀏覽器中它就是 crypto.getRandomValues(),資料取自作業系統的熵池。本工具只使用它。如果你要在自己的程式碼裡生成令牌,對應的選擇是 Python 的 secrets、Go 的 crypto/rand、Java 的 java.security.SecureRandom——絕不要用普通的 random 模組或 Math.random()

避免取模偏差

拿到高質量隨機位元組只完成了一半。最直覺的取字元方式是 bytes[i] % alphabet.length,但只要字母表大小不能整除 256,結果就會悄悄偏斜。以 62 字元的字母表為例,前 8 個字元出現的機率會略高於其餘字元——偏差不大,卻實實在在削弱了熵,而且完全可以避免。

解決辦法是拒絕取樣:落在最後那個不完整區間裡的位元組直接丟棄,重新取一個。本工具正是這麼做的,因此所選字母表中的每個字元出現機率完全相等。

長度怎麼選

熵值等於 log2(字母表大小) × 長度 位元。62 字元的字母表每個字元約 5.95 位元,因此 22 位令牌約攜帶 131 位元,暴力破解已無從下手。凡是用於保護真實訪問許可權的場景,128 位元是通行下限;低於約 64 位元時,攻擊者只要有一個響應夠快的介面,威脅就變得真實。

字母表的選擇主要取決於令牌要經過哪些環節。Base64url 和十六進位制可以原樣穿過 URL、檔名和 HTTP 頭。無歧義字母表剔除了 0/O、1/l/I 這類易混字元,凡是需要人念出來或照著螢幕重新輸入的場景都值得使用。

開源說明:使用瀏覽器原生的 crypto.getRandomValues API 實現,不依賴任何第三方庫。

常見問題

令牌是在我的裝置上生成的嗎?
是的,完全在瀏覽器內通過 crypto.getRandomValues() 生成。不會發送到任何伺服器,也不會記錄日誌,你看到的值只有你自己知道。
令牌應該多長?
凡是用於保護訪問許可權的場景,至少要有 128 位元熵:62 字元字母表下取 22 位,或 32 位十六進位制。僅作非安全標識用途時可以更短。
為什麼不能用 Math.random()?
它是速度優先的偽隨機生成器,種子往往來自時鐘這類廉價來源。攻擊者只要觀察到少量輸出,通常就足以還原內部狀態並預測今後的每一個值。
「無歧義字元」選項有什麼用?
它會剔除 0/O 與 1/l/I,讓令牌在被念出來、抄在紙上或照著螢幕重新輸入時不會因為字形混淆而出錯。
可以用它生成密碼重置連結嗎?
可以,但你需要只儲存令牌的雜湊、設定較短的有效期,並在使用一次後立即作廢。隨機性這裡已經足夠,生命週期管理是你的應用要負責的部分。
同一個令牌會不會再次出現?
在 128 位元熵下重複的機率低到可以忽略,但本工具不儲存任何歷史記錄,因此無法替你驗證多次生成之間的唯一性。