偽隨機數與真正隨機數的差異 - 如何區分的整理
· 小村 豪 · 偽隨機數, 真隨機數, RNG, CSPRNG, 資安
討論亂數的時候,許多本質上相當不同的東西都被以 隨機 一詞帶過,因此話題很容易就歪掉。像 Math.random() 這種用計算產生的數列,和從熱雜訊、時鐘抖動這種物理現象取得的數列,光看外觀都會顯得散得差不多。
但在實務上,如果讓這個差異一直模糊著,就容易在下面這些判斷上出錯:
- 在模擬中想重現結果,但每次跑出來都會晃
- 用容易預測的亂數做出密碼重設 token
- 只因為通過統計檢定就以為「這是真正的隨機數」
- 反過來,一聽到
偽就誤以為全部都不安全
本文嘗試以實務上容易判斷的形式,整理 什麼是偽隨機數、什麼是真正的隨機數、該如何區分。重點放在不是看輸出的外觀,而是看產生器的結構。
文中內容以 2026 年 4 月時點可確認的 NIST、IETF、OS、語言官方資料為前提來整理。
1. 先下結論(一句話)
雖然有點粗略,但先用實務上比較管用的說法,可以這樣講:
- 偽隨機數是從內部狀態與演算法確定性地產生的數列
- 真正的隨機數是把熱雜訊、抖動等物理現象當作熵源的數列
- 不過,實務上常用的安全亂數 API,大多並不是直接把物理亂數回傳,而是用熵源來 seed 一個
DRBG / CSPRNG後再回傳 - 因此,光看
外觀是否隨機沒辦法區分。要看的是產生器的結構、seed 如何進來、reseed、health test - 在模擬或重現測試中,偽隨機數的可重現性是一項武器
- 在金鑰、token、nonce 這類資安用途中,原則上要用作業系統或語言提供的安全亂數 API
總之,先分開以下 3 件事來想,比較不會偏掉:
- 它討論的是
普通的 PRNG嗎 - 它討論的是
密碼學用的 PRNG / CSPRNG / DRBG嗎 - 它討論的是
具有物理熵源的 NRBG / TRNG嗎
2. 本文所說的「偽隨機數」與「真正的隨機數」
在這個話題裡,單純說「亂數」的範圍太大。所以先把定義固定下來。
- 偽隨機數(PRNG):根據 seed 與內部狀態,以確定性步驟產生數列。同樣條件下會產生相同的數列
- 密碼學用偽隨機數(CSPRNG / DRBG):雖然也是偽隨機數的一種,但強調不可預測性。NIST SP 800-90A 就是在定義這類 deterministic random bit generator
- 真正的隨機數:在日常用語裡,通常指的是
真隨機數或物理隨機數。NIST 用語中較接近的是NRBG(non-deterministic random bit generator),其說明是持續參考熵源,在正常情況下具有 full entropy 輸出的產生器
這裡的重點是,偽隨機數 並不等於 危險的亂數。
例如,線性同餘法或單純的 xorshift 這類高速 PRNG,和 CTR_DRBG、HMAC_DRBG 這類 CSPRNG,雖然同樣都是確定性的,但在資安意義上差別相當大。
3. 先用一張圖整理
3.1. 關係圖
先用一張圖看看觀念之間的相對位置:
flowchart LR
NOISE["物理現象<br/>熱雜訊、抖動等"] --> ENT["熵源"]
ENT --> SEED["seed / reseed"]
SEED --> DRBG["DRBG / CSPRNG<br/>高速展開亂數"]
DRBG --> API["OS / 函式庫回傳的亂數"]
STATE["內部狀態 + 數學式"] --> PRNG["一般的 PRNG"]
PRNG --> OUT["外觀像是隨機的數列"]
這裡的重點是,應用程式拿到的 安全亂數 API 輸出,和右側的 一般 PRNG、左側的 原始物理雜訊 都有點不同。
多數實作是用左側的熵源做 seed / reseed,再以 DRBG / CSPRNG 高速展開後的數值回傳。NIST SP 800-90B 與 800-90C,正是在整理這種 entropy source + deterministic generator 結構的文件。
3.2. 術語最短整理
| 種類 | 用什麼做 | 同樣條件可重現 | 特別要求的是什麼 | 適合的用途 |
|---|---|---|---|---|
| 一般的 PRNG | 數學式與內部狀態 | 可以 | 速度、可重現性 | 模擬、遊戲、測試 |
| CSPRNG / DRBG | 密碼演算法 + seed | 可以 | 不可預測性 | 金鑰、token、nonce、連線 ID |
| 真正的隨機數 / NRBG | 物理熵源 | 基本上不行 | 物理上的不確定性、熵量 | seed 供應、認證裝置、需高度稽核的抽籤 |
最短的記法是:
- 一般的 PRNG:
可以重現的亂數 - CSPRNG:
可以重現,但設計成外部難以預測的亂數 - 真正的隨機數:
從物理現象中取出熵的亂數
4. 什麼是偽隨機數
4.1. 一句話說明
偽隨機數是在更新內部狀態的同時,用計算做出 看起來像是亂數的數列。
只要放進同樣的 seed、使用同樣的演算法、取出同樣的次數,就會得到同樣的數值序列。這乍看像是缺點,但在模擬、測試、除錯中反而是很大的優點。
正因為可以重現,用這個 seed 會重現 bug、想把昨天的結果再比對一次 這種運用才能成立。
4.2. 把一般的 PRNG 與 CSPRNG 分開看
這邊是最常被誤解的地方。偽隨機數 = 假貨 = 不能用,是不對的。
NIST SP 800-90A 所定義的,就是以雜湊函式或區塊密碼為基礎的 deterministic random bit generator。也就是說,資安用途中使用的亂數,其核心很大一部分也是確定性的產生器。
兩者的差別不是單純的 看起來像亂數,而是從攻擊者視角看的不可預測性。
- 一般的 PRNG
- 快
- 容易重現
- 內部狀態或 seed 外洩後,容易被預測
- CSPRNG / DRBG
- 也是確定性的
- 但在假設內部狀態未知的前提下,設計上要讓輸出難以被預測
- 資安用途下應使用這種
所以光用 是不是偽隨機數 判斷安全性,幾乎一定會踩雷。該看的是 是哪一種偽隨機數。
5. 什麼是真正的隨機數
5.1. 一句話說明
真正的隨機數是從熱雜訊、振盪器的抖動、雪崩雜訊、量子現象這類物理上的不確定性中取出熵。
日常上稱為 真隨機數 或 物理隨機數。在 NIST 用語中較接近的是 NRBG,定位為 持續存取熵源,只要運作正常就能具有 full entropy 輸出的產生器。
5.2. 物理隨機數不見得會直接使用
這邊也很重要。就算是真正的隨機數,也不一定會把原始量測值直接交給應用程式。
物理源在實務上會有下列這些難處:
- 有偏差
- 會受到溫度、電源、故障、劣化的影響
- 原始輸出速度可能不太高
- 沒有健康檢查的話,壞掉也很難察覺
因此在 NIST SP 800-90B 中,很重視熵源的設計原則、min-entropy 的概念、validation test、health testing。從整個實作來看,像 NIST SP 800-90C 那樣以 entropy source + DRBG 的方式使用,才是常見做法。
換句話說,真正的隨機數 不是那種 raw 的神祕物,而是連同物理源、評估、監視、後處理一起處理的東西。
6. 到底差在哪裡
亂數的差異,光看 看起來是不是隨機 並不足以整理清楚。至少從下面 4 個面向切,比較容易看清楚:
6.1. 產生來源
- 偽隨機數:演算法與內部狀態
- 真正的隨機數:物理熵源
這是本質上最大的差別。
6.2. 可重現性
- 偽隨機數:同樣的 seed 可以重現
- 真正的隨機數:在同樣條件下重新取,也不太會得到相同的數值序列
可重現性在測試中是優點,在抽籤中則可能是缺點。
6.3. 可預測性
- 一般的 PRNG:seed 或內部狀態被讀到之後,下一個值相當容易推出
- CSPRNG:在內部狀態被保護的前提下,設計成難以提前讀出
- 真正的隨機數:只要物理源健康就難以預測,但感測器故障或設計不良就是另一回事
在資安領域中,這個面向最重要。比起表面上的分佈,更關鍵的是「能不能猜到下一個值」。
6.4. 速度與運用
- 偽隨機數:高速、穩定、容易實作
- 真正的隨機數:需要收集熵並進行監視,速度與實作成本會受限
因此在正式系統中,不是 只用真正隨機數 或 只用偽隨機數 的二擇一,而是 以物理熵做 seed 的 CSPRNG 最為實際。
7. 該如何區分
7.1. 原則上光看輸出無法區分
最重要的答案就是這一點。光靠有限筆數的輸出序列,沒辦法斷定 這是真正的隨機數。
理由很簡單:要做出一個能回傳和目前觀察到的有限長度完全相同序列的確定性程式,隨時都可以。極端一點講,把那個序列放進陣列或 ROM,依序回傳就好了。
因此,不能因為 看起來自然 就說是 真的。NIST SP 800-22 也明言,統計檢定頂多是第一步,不能單靠它來絕對證明產生器的正當性。
反過來說,設計良好的 CSPRNG,光看輸出也會讓你很難把它和真正的隨機源區分開。這裡的 難以區分,其實是設計目標之一。
7.2. 首先要看的是產生器的設計
要區分的時候,與其看輸出的外觀,不如先確認下列項目,會更本質:
- 產生演算法是什麼
- 是單純的 PRNG,還是 DRBG / CSPRNG
- seed 來自哪裡
- 是固定 seed、時間、PID 這類
- 還是來自 OS 的熵源
- 是否會 reseed
- 只在啟動時 seed 一次就結束了嗎
- 運作中是否也會重新灌入
- 熵源是否經過驗證
- 有沒有 min-entropy 的評估
- 有沒有 health test
- 是否偵測故障
- 使用了哪個 API
- 是自己寫的嗎
- 還是 OS / 語言標準 API
從這些面向來看,多數情況其實都能分辨:
只要固定 seed,每次都產生一樣的序列→ 偽隨機數具有物理熵源、以 validation / health test 為前提→ 帶真正亂數源的設計呼叫的是 OS 的 secure RNG API→ 大多是物理熵 + CSPRNG的混合架構
7.3. 其次,用統計檢定找出明顯的瑕疵
統計檢定並非不必要,反而很重要。只是它的角色比較接近 偵測瑕疵,而不是 證明。
典型的觀察角度包含:
- 0 與 1 的偏差
- run 的偏差
- 週期性
- 相關性
- 近似熵
- 線性複雜度
代表性參考有 NIST SP 800-22,日本則常參照 CRYPTREC 的亂數檢定最低組合。它們對於 檢查該序列是否有明顯偏差或結構 很有用。
但就算通過,也不能說「這是真正的隨機數」。設計良好的 CSPRNG 也很有可能通過;反過來,物理隨機源也可能因為感測器偏差或故障而失敗。
檢定的定位大致如下:
- 通過:目前還看不到明顯缺陷
- 失敗:大概率有問題
- 所以它能證明是真正的隨機數:做不到這一點
7.4. 在資安用途中要以攻擊者視角來看
在密碼重設 token、連線 ID、nonce、金鑰生成這類用途中,光問 是真的嗎 是不夠的。
真正要看的是「攻擊者能不能預測下一個值」。
例如:
- 只用目前時間做 seed
- 只把 PID 或流水號混進去
- 自己實作又沒評估 seed 的品質
- 把
random系列 API 拿來當資安用途
這類做法,光靠 看起來像那麼一回事 是擋不住的。
日本 IPA 也建議先掌握資安相關 API 與現有函式庫,避免輕易地自行實作。Python 文件中明確指出,要用 secrets 模組優先於 random。在 Java 中,對應的位置就是 SecureRandom。
結論是:在資安裡,是偽隨機還是真的 並不是核心,有沒有使用安全的 seed / entropy 與安全的 API 才更為重要。
8. 不同用途分別該用哪種
| 用途 | 適合的選擇 | 原因 |
|---|---|---|
| 模擬、Monte Carlo、遊戲邏輯 | 一般的 PRNG | 快、可用 seed 重現 |
| 測試重現、bug 重現 | 一般的 PRNG | 可以重現相同輸入 |
| 金鑰、token、nonce、連線 ID | CSPRNG / OS 的 secure RNG API | 需要不可預測性 |
| seed 供應、需高稽核與說明責任的抽籤 | 具物理隨機源的設計,或可稽核的機制 | 物理熵或紀錄可追溯性很重要 |
一般應用開發中需要 安全的亂數 |
OS / 語言標準的 secure RNG | 比自行實作更不易出錯 |
在實作層次上,下面的選法通常比較穩:
- Windows 原生:
BCryptGenRandom - .NET:
System.Security.Cryptography.RandomNumberGenerator - Linux:
getrandom() - Python:
secrets - Java:
SecureRandom
Windows 的 BCryptGenRandom,在 Microsoft Learn 文件中說明預設提供者符合 NIST SP800-90 的 CTR_DRBG。Linux 的 getrandom() 也被文件化為可用於 cryptographic purposes。.NET 的 RandomNumberGenerator、Python 的 secrets、Java 的 SecureRandom 也都是以密碼學用途為前提設計的 API。
9. 常見的誤解
9.1. 通過統計檢定,就是真正的隨機數
並非如此。它頂多能讓你說:目前還看不到明顯偏差。
9.2. 只要是真正的隨機數,就一定安全
並非如此。物理源若故障、偏差,加上實作不當、缺乏 health test,品質照樣會崩掉。
9.3. 偽隨機數全都不安全
並非如此。CSPRNG / DRBG 反而是實務上安全亂數 API 的核心。
9.4. 在資安用途中,必須直接使用原始物理隨機數
不必然。實務上最常見的是「物理熵源 + CSPRNG」的組合。
9.5. 反正 random 或 Math.random() 看起來也很散,就可以拿來做 token
用途不一樣。外觀上的分佈和對攻擊者的不可預測性,是兩件事。
10. 實務上猶豫時的判斷表
猶豫時,依下列順序判斷會比較快:
- 是否希望能重現同樣的結果
- 是 → 一般的 PRNG
- 否 → 往下
- 被攻擊者預測會不會造成問題
- 會 → OS / 語言標準的 secure RNG
- 不會 → 視品質需求與速度挑選
- 亂數源本身是否需要說明責任或稽核
- 是 → 考慮物理隨機源或通過驗證的服務
- 是否想自己實作
- 心情可以理解,但亂數很容易做錯,原則上先用標準 API
照這個順序看,比起只在 偽 vs 真 二擇一上糾結,方向會快很多。
11. 結語
如果要用最粗但實務上好用的方式,講出偽隨機數與真正隨機數的差別,大概就是這樣:
- 偽隨機數是用計算做的
- 真正的隨機數是從物理現象中取出熵
- 但實務上的安全亂數 API,主角是介於兩者之間的
entropy source + CSPRNG
也就是說,該看的不是 外觀,而是 結構。
- 無法只看輸出就斷定是否為真正的隨機數
- 統計檢定在偵測瑕疵上有用,但不是證明
- 資安中真正的戰場是
能不能被預測 - 需要可重現性就用 PRNG,需要不可預測性就用 OS / 語言標準的 secure RNG
順這條思路,就可以跳脫 偽隨機數是不是假貨 這種粗糙的對立。
12. 參考資料
-
NIST SP 800-90A Rev. 1: Recommendation for Random Number Generation Using Deterministic Random Bit Generators
deterministic random bit generator 的基礎文件。 -
NIST SP 800-90B: Recommendation for the Entropy Sources Used for Random Bit Generation
整理熵源、驗證、health testing 的概念。 -
NIST SP 800-90C: Recommendation for Random Bit Generator (RBG) Constructions
整理entropy source + DRBG的結構。 -
NIST SP 800-22 Rev. 1a: A Statistical Test Suite for Random and Pseudorandom Number Generators for Cryptographic Applications
說明統計檢定的定位。檢定是第一步,不等於證明,這一點很重要。 -
NIST Glossary: Non-deterministic Random Bit Generator (NRBG)
確認接近true random的 NIST 術語定義。 -
RFC 4086: Randomness Requirements for Security
整理資安用途中的亂數與熵源注意事項。 -
Microsoft Learn: BCryptGenRandom function
說明 Windows 的 secure RNG API 以及預設提供者的CTR_DRBG。 -
Linux man page: getrandom(2)
在 Linux 可用於cryptographic purposes的亂數 API。 -
Microsoft Learn: RandomNumberGenerator 類別
.NET 上具密碼強度的 RNG API。 -
Python 文件:secrets — Generate secure random numbers for managing secrets
Python 中處理資安用亂數的基礎。 -
Oracle Java Documentation: SecureRandom
整理 Java 的 secure RNG 與 seed / entropy 的概念。 -
IPA: 第3章 3.不易被破解的密碼技術與偽隨機數的使用
以日文整理 seed 的重要性、檢定、API 使用注意事項。
相關文章
共用相同標籤的最新文章。能以相近的主題延伸理解。
從雜湊值的字串表示判斷雜湊方式 - 以長度、字元集、前綴縮小候選的實務步驟
本文整理從雜湊字串判斷演算法的實務步驟。先看前綴與分隔符,再以字元集和長度縮小候選,最後依來源系統與保存格式做最終特定。以 bcrypt、Argon2、sha512crypt、LDAP 標籤為例,說明帶格式標籤的字串為何容易判定,避免只憑長度誤判。
Windows 的 DLL 名稱解析機制 - 以實務角度整理搜尋順序、Known DLLs、API set、SxS
從實務角度整理 Windows 的 DLL 名稱解析,說明 loader 在掃描檔案系統前會先處理 DLL redirection、API set、SxS、Known DLLs,並用 SetDefaultDllDirectories 與 LoadLibraryEx 旗標縮小...
Windows 什麼時候需要系統管理員權限 - UAC、保護區、設計上的分辨方式
從邊界與儲存位置的角度,整理 Windows 何時真正需要系統管理員權限:UAC、保護區、HKLM、服務、驅動、防火牆。同時說明 per-user 與 per-machine 的差異,以及把管理員處理切成獨立 EXE、服務或工作的設計取捨,幫讀者判斷該不該提權。
Windows 應用程式中把「僅需要系統管理員權限的處理」分離出來的具體寫法
本文以 .NET 8 桌面應用程式為例,具體展示如何讓 UI 保持 asInvoker,把僅需系統管理員權限的處理切到 helper EXE。涵蓋 manifest、runas 啟動、具名管道 ACL、PID 驗證、固定 operation 與請求驗證,以及 Explore...
Windows 應用程式不要把機密資訊以明文存進設定檔的最佳實踐
本文整理 Windows 桌面應用程式儲存連線憑證或 API Token 時的實務做法,說明為何 DPAPI 與 ProtectedData 比明文或自做加密更能切斷檔案外流即等同機密外流的鏈條,並比較 CurrentUser 與 LocalMachine 的適用情境、優先...
相關主題
與本文相近的主題頁面。以本文為起點,可進一步連到相關服務與其他文章。
Windows 技術主題
彙整 KomuraSoft LLC 關於 Windows 開發、故障調查與既有資產活用文章的主題中心。
作者檔案
本文作者的個人檔案頁面。
Go Komura
小村軟體有限公司 代表
以 Windows 軟體開發、技術諮詢與故障調查為中心,在難以重現的故障調查與既有資產仍在運作的專案上具有優勢。