在前段時間挖了不少跟mt_rand()相關的安全漏洞,基本上都是錯誤理解隨機數用法導致的。這裡又要提一下php官網manual的一個坑,看下關於mt_rand()的介紹:中文版^cn 英文版^en,可以看到英文版多了一塊黃色的 Caution 警告。 mt_rand()使用mersennetwister演算法傳回隨機整數,這個大家都知道,但下面這篇文章主要給大家介紹的是關於PHP中mt_rand()隨機數安全的相關資料,文中介紹的非常詳細,需要的朋友可以參考借鑒,下面隨著小編來一起學習學習吧。
很多國內開發者估計都是看的中文版的介紹而在程式中使用了mt_rand()來產生安全令牌、核心加解密key等等導致嚴重的安全問題。
偽隨機數
mt_rand()並不是一個真·隨機數產生函數,實際上絕大多數程式語言中的隨機數函數所產生的都是偽隨機數。關於真隨機數和偽隨機數的區別這裡不展開解釋,只需要簡單了解一點
偽隨機是由可確定的函數(常用線性同餘),透過一個種子(常用時鐘),產生的偽隨機數。這意味著:如果知道了種子,或已經產生的隨機數,都可能獲得接下來隨機數序列的資訊(可預測性)。
簡單假設 mt_rand()內部產生隨機數的函數為: rand = seed+(i*10) 其中 seed 是隨機數種子, i 是第幾次呼叫這個隨機數字函數。當我們同時知道 i 和 rand 兩個值的時候,就能很容易的算出seed的值來。例如 rand=21 , i=2 代入函數 21=seed+(2*10) 得到 seed=1 。是不是很簡單,拿到seed之後,就能計算出當 i 為任意值時候的 rand 的值了。
PHP的自動播種
從上一節我們已經知道每一次mt_rand()被呼叫都會根據seed和目前呼叫的次數i來計算出一個偽隨機數。而且seed是自動播種的:
Note: 自 PHP 4.2.0 起,不再需要用 srand() 或 mt_srand() 給隨機數產生器播種 ,因為現在是由系統自動完成的。
那麼問題就來了,到底系統自動完成播種是在什麼時候,如果每次呼叫mt_rand()都會自動播種那麼破解seed也就沒意義了。關於這一點manual並沒有給出詳細資訊。網路上找了一圈也沒可靠的答案 只能去翻原始碼^mtrand了:
PHPAPI void php_mt_srand(uint32_t seed) { /* Seed the generator with a simple uint32 */ php_mt_initialize(seed, BG(state)); php_mt_reload(); /* Seed only once */ BG(mt_rand_is_seeded) = 1; } /* }}} */ /* {{{ php_mt_rand */ PHPAPI uint32_t php_mt_rand(void) { /* Pull a 32-bit integer from the generator state Every other access function simply transforms the numbers extracted here */ register uint32_t s1; if (UNEXPECTED(!BG(mt_rand_is_seeded))) { php_mt_srand(GENERATE_SEED()); } if (BG(left) == 0) { php_mt_reload(); } --BG(left); s1 = *BG(next)++; s1 ^= (s1 >> 11); s1 ^= (s1 > 18) ); }
可以看到每次呼叫mt_rand()都會先檢查是否已經播種。如果已經播種就直接產生隨機數,否則會呼叫php_mt_srand來播種。也就是說每個php cgi進程期間,只有第一次呼叫mt_rand()會自動播種。接下來都會根據這個第一次播種的種子來產生隨機數。而php的幾種運行模式中除了CGI(每個請求啟動一個cgi進程,請求結束後關閉。每次都要重新讀取php.ini 環境變量等導致效率低下,現在用的應該不多了)以外,基本上都是一個進程處理完請求之後standby等待下一個,處理多個請求之後才會回收(超時也會回收)。
寫個腳本測試一下
<?php //pid.php echo getmypid();
<?php //test.php $old_pid = file_get_contents('http://localhost/pid.php'); $i=1; while(true){ $i++; $pid = file_get_contents('http://localhost/pid.php'); if($pid!=$old_pid){ echo $i; break; } }
測試結果:(windows+phpstudy)
apache 1000請求
nginx 500請求
#當然這個測試只是確認了apache和nginx一個進程可以處理的請求數,再來驗證一下剛才關於自動播種的結論:
<?php //pid1.php if(isset($_GET['rand'])){ echo mt_rand(); }else{ echo getmypid(); }
<?php //pid2.php echo mt_rand();
<?php //test.php $old_pid = file_get_contents('http://localhost/pid1.php'); echo "old_pid:{$old_pid}\r\n"; while(true){ $pid = file_get_contents('http://localhost/pid1.php'); if($pid!=$old_pid){ echo "new_pid:{$pid}\r\n"; for($i=0;$i<20;$i++){ $random = mt_rand(1,2); echo file_get_contents("http://localhost/pid".$random.".php?rand=1")." "; } break; } }
透過pid來判斷,當新進程開始的時候,隨機獲取兩個頁面其中一個的mt_rand() 的輸出:
old_pid:972 new_pid:7752 1513334371 2014450250 1319669412 499559587 117728762 1465174656 1671827592 1703046841 464496438 1974338231 46646067 981271768 1070717272 571887250 922467166 606646473 134605134 857256637 1971727275 2104203195
拿第一個隨機數1513334371 去爆破種子:
smldhz@vm:~/php_mt_seed-3.2$ ./php_mt_seed 1513334371 Found 0, trying 704643072 - 738197503, speed 28562751 seeds per second seed = 735487048 Found 1, trying 1308622848 - 1342177279, speed 28824291 seeds per second seed = 1337331453 Found 2, trying 3254779904 - 3288334335, speed 28811010 seeds per second seed = 3283082581 Found 3, trying 4261412864 - 4294967295, speed 28677071 seeds per second Found 3
爆破出了3個可能的種子,數量很少手動一個一個測試:
<?php mt_srand(735487048);//手工播种 for($i=0;$i<21;$i++){ echo mt_rand()." "; }
輸出:
前20位元跟上面腳本取得的一模一樣,確認種子就是1513334371 。有了種子我們就能計算出任意次數呼叫mt_rand()產生的隨機數了。例如這個腳本我產生了21位,最後一位是 1515656265 如果跑完剛才的腳本之後沒訪問過站點,那麼打開 http://localhost/pid2.php 就能看到相同的 1515656265 。
所以我們得到結論:
php的自動播種發生在php cgi行程中第一次呼叫mt_rand()的時候。跟造訪的頁面無關,只要是同一個行程處理的請求,就會共用同一個原本自動播種的種子。
php_mt_seed
我們已經知道隨機數的產生是依賴特定的函數,上面曾經假設為 rand = seed+(i*10) 。對於這樣一個簡單的函數,我們當然可以直接計算(口算)出一個(組)解來,但 mt_rand() 實際使用的函數可是相當複雜且無法逆運算的。有效的破解方法其實是窮舉所有的種子並根據種子生成隨機數序列再跟已知的隨機數序列做比對來驗證種子是否正確。 php_mt_seed^phpmtseed就是這麼一個工具,它的速度非常快,跑完2^32位元seed也就幾分鐘。它可以根據單次mt_rand()的輸出結果直接爆破出可能的種子(上面有範例),當然也可以爆破類似mt_rand(1,100)這樣限定了MIN MAX輸出的種子(下面實例中有用到)。
安全性問題
說了這麼多,那到底隨機數字怎麼不安全了呢?其實函數本身沒有問題,官方也明確提示了產生的隨機數字不應用於安全加密用途(雖然中文版manual沒寫)。問題在於開發者並沒有意識到這並不是一個 真·隨機數 。我們已經知道,透過已知的隨機數序列可以爆破出種子。也就是說,只要任意頁面中存在輸出隨機數或其衍生值(可逆推隨機值),那麼其他任意頁面的隨機數將不再是「隨機數」。常見的輸出隨機數的例子例如驗證碼,隨機檔案名稱等等。常見的隨機數字用於安全驗證的例如找回密碼校驗值,例如加密key等等。一個理想中的攻擊場景:
夜深人靜,等待apache(nginx)收回所有php進程(確保下次訪問會重新播種),訪問一次驗證碼頁面,根據驗證碼字元逆推出隨機數,再根據隨機數爆破出隨機數種子。接著造訪找回密碼頁面,產生的找回密碼連結是基於隨機數的。我們就可以輕鬆計算出這個連結,找回管理員的密碼………XXOO
實例
PHPCMS MT_RAND SEED CRACK致authkey洩漏雨牛寫的比我好,看他的就夠了
Discuz x3.2 authkey洩漏這個其實也差不多。官方已出補丁,有興趣的可以自己去分析一下。
相關推薦:
#以上是PHP中mt_rand()隨機數的安全實例詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

PHP在電子商務、內容管理系統和API開發中廣泛應用。 1)電子商務:用於購物車功能和支付處理。 2)內容管理系統:用於動態內容生成和用戶管理。 3)API開發:用於RESTfulAPI開發和API安全性。通過性能優化和最佳實踐,PHP應用的效率和可維護性得以提升。

PHP可以輕鬆創建互動網頁內容。 1)通過嵌入HTML動態生成內容,根據用戶輸入或數據庫數據實時展示。 2)處理表單提交並生成動態輸出,確保使用htmlspecialchars防XSS。 3)結合MySQL創建用戶註冊系統,使用password_hash和預處理語句增強安全性。掌握這些技巧將提升Web開發效率。

PHP和Python各有優勢,選擇依據項目需求。 1.PHP適合web開發,尤其快速開發和維護網站。 2.Python適用於數據科學、機器學習和人工智能,語法簡潔,適合初學者。

PHP仍然具有活力,其在現代編程領域中依然佔據重要地位。 1)PHP的簡單易學和強大社區支持使其在Web開發中廣泛應用;2)其靈活性和穩定性使其在處理Web表單、數據庫操作和文件處理等方面表現出色;3)PHP不斷進化和優化,適用於初學者和經驗豐富的開發者。

PHP在現代Web開發中仍然重要,尤其在內容管理和電子商務平台。 1)PHP擁有豐富的生態系統和強大框架支持,如Laravel和Symfony。 2)性能優化可通過OPcache和Nginx實現。 3)PHP8.0引入JIT編譯器,提升性能。 4)雲原生應用通過Docker和Kubernetes部署,提高靈活性和可擴展性。

PHP適合web開發,特別是在快速開發和處理動態內容方面表現出色,但不擅長數據科學和企業級應用。與Python相比,PHP在web開發中更具優勢,但在數據科學領域不如Python;與Java相比,PHP在企業級應用中表現較差,但在web開發中更靈活;與JavaScript相比,PHP在後端開發中更簡潔,但在前端開發中不如JavaScript。

PHP和Python各有優勢,適合不同場景。 1.PHP適用於web開發,提供內置web服務器和豐富函數庫。 2.Python適合數據科學和機器學習,語法簡潔且有強大標準庫。選擇時應根據項目需求決定。

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

SublimeText3 Linux新版
SublimeText3 Linux最新版

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能

PhpStorm Mac 版本
最新(2018.2.1 )專業的PHP整合開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

記事本++7.3.1
好用且免費的程式碼編輯器