聊一聊隨機數安全
0x00 簡介
和朋友聊到一個比較有意思的現象,在最近兩年的校招面試中,大部分同學連一點基礎的密碼學知識都沒有, 即便是有一些滲透功底的同學。
所以這裡想和大家聊一些簡單的密碼學基礎知識,不涉及演算法實現,更多的是和常見的漏洞場景聯絡起來,讓問題更容易理解,有點拋磚引玉的意思。
本文主要聊一下隨機數,隨機數其實是非常廣泛的,可以說也是密碼技術的基礎。
對隨機數的使用不當很可能會導致一些比較嚴重的安全問題, 並且這些安全問題通常會比較隱蔽。
0x01 隨機數
概述
隨機數在計算機應用中使用的比較廣泛,最為熟知的便是在密碼學中的應用。本文主要是講解隨機數使用導致的一些Web安全風。
我們先簡單瞭解一下隨機數
分類
隨機數分為真隨機數和偽隨機數,我們程式使用的基本都是偽隨機數,其中偽隨機又分為強偽隨機數和弱偽隨機數。
- 真隨機數,透過物理實驗得出,比如擲錢幣、骰子、轉輪、使用電子元件的噪音、核裂變等
- 偽隨機數,透過一定演算法和種子得出。軟體實現的是偽隨機數
- 強偽隨機數,難以預測的隨機數
- 弱偽隨機數,易於預測的隨機數
特性
隨機數有3個特性,具體如下:
- 隨機性:不存在統計學偏差,是完全雜亂的數列
- 不可預測性:不能從過去的數列推測出下一個出現的數
- 不可重現性:除非將數列本身儲存下來,否則不能重現相同的數列
隨機數的特性和隨機數的分類有一定的關係,比如,弱偽隨機數只需要滿足隨機性即可,而強位隨機數需要滿足隨機性和不可預測性,真隨機數則需要同時滿足3個特性。
引發安全問題的關鍵點在於不可預測性。
偽隨機數的生成
我們平常軟體和應用實現的都是偽隨機數,所以本文的重點也就是偽隨機數。
偽隨機數的生成實現一般是演算法+種子。
具體的偽隨機數生成器PRNG一般有:
- 線性同餘法
- 單向雜湊函式法
- 密碼法
- ANSI X9.17
比較常用的一般是線性同餘法,比如我們熟知的C語言的rand庫和Java的java.util.Random類,都採用了線性同餘法生成隨機數。
應用場景
隨機數的應用場景比較廣泛,以下是隨機數常見的應用場景:
- 驗證碼生成
- 抽獎活動
- UUID生成
- SessionID生成
- Token生成
- CSRF Token
- 找回密碼Token
- 遊戲(隨機元素的生成)
- 洗牌
- 俄羅斯方塊出現特定形狀的序列
- 遊戲爆裝備
- 密碼應用場景
- 生成金鑰:對稱密碼,訊息認證
- 生成金鑰對:公鑰密碼,數字簽名
- 生成IV: 用於分組密碼的CBC,CFB和OFB模式
- 生成nonce: 用於防禦重放攻擊; 分組密碼的CTR模式
- 生成鹽:用於基於口令的密碼PBE等
0x02 隨機數的安全性
相比其他密碼技術,隨機數很少受到關注,但隨機數在密碼技術和計算機應用中是非常重要的,不正確的使用隨機數會導致一系列的安全問題。
隨機數的安全風險
隨機數導致的安全問題一般有兩種
- 應該使用隨機數,開發者並沒有使用隨機數;
- 應該使用強偽隨機數,開發者使用了弱偽隨機數。
第一種情況,簡單來講,就是我們需要一個隨機數,但是開發者沒有使用隨機數,而是指定了一個常量。當然,很多人會義憤填膺的說,sb才會不用隨機數。但是,請不要忽略我朝還是有很多的。主要有兩個場景:
開發者缺乏基礎常識不知道要用隨機數;
一些應用場景和框架,介面文件不完善或者開發者沒有仔細閱讀等原因。
比如找回密碼的token,需要一個偽隨機數,很多業務直接根據使用者名稱生成token;
比如OAuth2.0中需要第三方傳遞一個state引數作為CSRF Token防止CSRF攻擊,很多開發者根本不使用這個引數,或者是傳入一個固定的值。由於認證方無法對這個值進行業務層面有效性的校驗,導致了OAuth的CSRF攻擊。
第二種情況,主要區別就在於偽隨機數的強弱了,大部分(所有?)語言的API文件中的基礎庫(常用庫)中的random庫都是弱偽隨機,很多開發自然就直接使用。但是,最重要也最致命的是,弱偽隨機數是不能用於密碼技術的。
還是第一種情況中的找回密碼場景,關於token的生成, 很多開發使用了時間戳作為隨機數(md5(時間戳),md5(時間戳+使用者名稱)),但是由於時間戳是可以預測的,很容易就被猜解。不可預測性是區分弱偽隨機數和強偽隨機數的關鍵指標。
當然,除了以上兩種情況,還有一些比較特別的情況,通常情況下比較少見,但是也不排除:
- 種子的洩露,演算法很多時候是公開的,如果種子洩露了,相當於隨機數已經洩露了;
- 隨機數池不足。這個嚴格來說也屬於弱偽隨機數,因為隨機數池不足其實也導致了隨機數是可預測的,攻擊者可以直接暴力破解。
漏洞例項
wooyun上有很多漏洞,還蠻有意思的,都是和隨機數有關的。
PS:個人實力有限,以下例項基本都來自wooyun漏洞例項,在這裡謝謝各位大牛,如有侵權,請聯絡刪除。
1.應該使用隨機數而未使用隨機數
Oauth2.0的這個問題特別經典,除了wooyun例項列出來的,其實很多廠商都有這個問題。
Oauth2.0中state引數要求第三方應用的開發者傳入一個CSRF Token(隨機數),如果沒有傳入或者傳入的不是隨機數,會導致CSRF登陸任意帳號:
2.使用弱偽隨機數
1) 密碼取回
很多密碼找回的場景,會傳送給使用者郵件一個url,中間包含一個token,這個token如果猜測,那麼就可以找回其他使用者的密碼。
1.Shopex 4.8.5密碼取回處新生成密碼可預測漏洞
直接使用了時間函式microtime()作為隨機數,然後獲取MD5的前6位。
#!php
substr(md5(print_r(microtime(),true)),0,6);
PHP 中microtime()的值除了當前伺服器的秒數外,還有微秒數,微妙數的變化範圍在0.000000 -- 0.999999 之間,一般來說,伺服器的時間可以透過HTTP返回頭的DATE欄位來獲取,因此我們只需要遍歷這1000000可能值即可。但我們要使用暴力破解的方式發起1000000次網路請求的話,網路請求數也會非常之大。可是shopex非常貼心的在生成密碼前再次將microtime() 輸出了一次:
#!php
$messenger = &$this->system->loadModel('system/messenger');echo microtime()."<br/>";
直接是MD5(unix時間戳)
關於找回密碼隨機數的問題強烈建議大家參考拓哥的11年的文章《利用系統時間可預測破解java隨機數| 空虛浪子心的靈魂》
2) 其他隨機數驗證場景
弱偽隨機數被繞過
Espcms中一處SQL隱碼攻擊漏洞的利用,利用時發現espcms對傳值有加密並且隨機key,但是這是一個隨機數池固定的弱偽隨機數,可以被攻擊者遍歷繞過
使用了microtime()作為隨機數,可以被預測暴力破解
Android 4.4之前版本的Java加密架構(JCA)中使用的Apache Harmony 6.0M3及其之前版本的SecureRandom實現存在安全漏洞,具體位於classlib/modules/security/src/main/java/common/org/apache/harmony/security/provider/crypto/SHA1PRNG_SecureRandomImpl.java
類的engineNextBytes函式里,當使用者沒有提供用於產生隨機數的種子時,程式不能正確調整偏移量,導致PRNG生成隨機序列的過程可被預測。
安全建議
上面講的隨機數基礎和漏洞例項更偏重是給攻擊者一些思路,這裡更多的是一些防禦和預防的建議。
- 業務場景需要使用隨機數,一定要使用隨機數,比如Token的生成;
- 隨機數要足夠長,避免暴力破解;
- 保證不同用處的隨機數使用不同的種子
- 對安全性要求高的隨機數(如密碼技術相關)禁止使用的弱偽隨機數:
- 不要使用時間函式作為隨機數(很多程式設計師喜歡用時間戳) Java:system.currenttimemillis() php:microtime()
- 不要使用弱偽隨機數生成器 Java: java.util.Random PHP: rand() 範圍很小,32767 PHP: mt_rand() 存在缺陷
- 強偽隨機數CSPRNG(安全可靠的偽隨機數生成器(Cryptographically Secure Pseudo-Random Number Generator)的各種參考
Platform | CSPRNG |
---|---|
PHP | mcrypt_create_iv, openssl_random_pseudo_bytes |
Java | java.security.SecureRandom |
Dot NET (C#, VB) | System.Security.Cryptography.RNGCryptoServiceProvider |
Ruby | SecureRandom |
Python | os.urandom |
Perl | Math::Random::Secure |
C/C++ (Windows API) | CryptGenRandom |
Any language on GNU/Linux or Unix | Read from /dev/random or /dev/urandom |
6.強偽隨機數生成(不建議開發自己實現)
產生高強度的隨機數,有兩個重要的因素:種子和演算法。演算法是可以有很多的,通常如何選擇種子是非常關鍵的因素。 如Random,它的種子是System.currentTimeMillis(),所以它的隨機數都是可預測的, 是弱偽隨機數。
強偽隨機數的生成思路:收集計算機的各種資訊,鍵盤輸入時間,記憶體使用狀態,硬碟空閒空間,IO延時,程式數量,執行緒數量等資訊,CPU時鐘,來得到一個近似隨機的種子,主要是達到不可預測性。
0x03 附
參考資料:
- http://www.inbreak.net/archives/349
- /papers/?id=1066
- 《白帽子講Web安全》
- 《圖解密碼技術》
相關文章
- 隨便聊一聊&最近做的專案2020-10-29
- 聊一聊Jmeter的引數化2021-05-01JMeter
- 聊一聊HTTP快取機制2018-03-25HTTP快取
- 聊一聊 RestTemplate2018-10-20REST
- 聊一聊Puzzle:從幻方到數獨2020-04-02
- 聊一聊 Spring 中的擴充套件機制(一)2018-08-19Spring套件
- 聊一聊 TLS/SSL2023-09-22TLS
- 聊一聊Integer的快取機制問題2024-03-06快取
- 聊一聊Puzzle:創造了「數獨」的Nikoli(下)2020-04-20
- 聊一聊Greenplum與PostgreSQL2023-11-09SQL
- 聊一聊模板方法模式2023-05-15模式
- 聊一聊 JVM 的 GC2021-05-22JVMGC
- 聊一聊測試流程2020-12-25
- 聊一聊前端換膚2019-04-03前端
- 聊一聊session和cookie2018-05-12SessionCookie
- 聊一聊SQL最佳化2024-08-01SQL
- 聊一聊介面卡模式2023-05-17模式
- 聊一聊過度設計!2023-02-27
- 聊一聊裝飾者模式2022-11-25模式
- 聊一聊系統重構2023-03-20
- 聊一聊責任鏈模式2022-11-01模式
- Nginx-01-聊一聊 nginx2024-05-13Nginx
- 聊一聊容器暫停退出2022-05-26
- 聊一聊 Javascript 中的 AST2019-10-10JavaScriptAST
- 面試官:聊一聊SpringBoot服務監控機制2021-04-06面試Spring Boot
- 聊一聊 Spring 中的擴充套件機制(二) - NamespaceHandler2018-08-26Spring套件namespace
- 一百個不重複隨機數(無聊的時候看見一個app想到的)2024-12-08隨機APP
- 聊一聊MySQL的直方圖2023-03-28MySql直方圖
- 聊一聊Redis的離線分析2022-04-18Redis
- 面試官:聊一聊索引吧2021-09-14面試索引
- 聊一聊遊戲版本運營2022-03-29遊戲
- 聊一聊MySQL的字符集2022-01-24MySql
- 聊一聊MySQL的儲存引擎2022-01-24MySql儲存引擎
- 聊一聊Java的列舉enum2019-08-01Java
- 聊一聊評分模型校準2020-11-10模型
- 聊一聊微服務元件區別2020-11-08微服務元件
- 聊一聊遊戲的壓測2020-04-18遊戲
- 面試官(7): 聊一聊 Babel?2019-05-23面試Babel