首頁 > php教程 > php手册 > PHP中「==」運算子的安全性問題

PHP中「==」運算子的安全性問題

大家讲道理
發布: 2016-11-12 10:28:27
原創
1168 人瀏覽過
前言

PHP是一種通用的開源腳本語言,它的語法混合了C,Java,以及Perl等優秀語言的語法。除此之外,它還提供了大量的函數庫可供開發人員使用。但是,如果使用不當,PHP也會為應用程式帶來非常大的安全風險。

在這篇文章中,我們將會對PHP應用程式中經常會出現的一些問題進行深入地分析,尤其是當我們使用「==」(比較運算子)來進行字串比較時,可能會出現的一些安全問題。雖然近期有很多文章都圍繞著這一話題進行過一些探討,但我決定從「黑盒測試」的角度出發,討論一下如何利用這個問題來對目標進行滲透和攻擊。首先,我會對引起這個問題的根本原因進行分析,以便我們能夠更加深入地理解其工作機制,這樣才可以保證我們能夠盡可能地避免這種安全問題的發生。

問題的描述

在2011年,PHP官方漏洞追蹤系統發現,當字串與數字在進行比較的時候,程式會出現某些非常奇怪的現象。從安全的角度出發,這個問題其實並不能算是安全問題。比如說,你可以看到下面這段程式碼:

PHP中「==」運算子的安全性問題

實際上,當使用類似「==」這樣的比較運算子進行操作時,就會出現這樣的情況。上面這個例子中出現的問題不能算是漏洞,因為它是PHP所提供的一種名為「型別轉換」的功能。從本質上來分析,當我們使用特定的比較運算子(例如== , !=, )來進行操作時,PHP首先會嘗試去確定參與比較的資料類型。但是這樣的一種類型轉換機制將有可能導致計算結果與我們預期的結果有較大出入,而且也會帶來非常嚴重的安全問題。安全研究專家在該問題的完整披露報告中寫到:這種類型轉化機制將有可能導致權限提升,甚至還會使程序的密碼驗證過程變得不安全。

Gynvael寫過一篇關於這一主題的經典文章,PHP等號運算符“==”所涵蓋的數據類型非常廣泛,我們給大家提供了一個較為完整的比較參考列表,並給出了一些範例,具體內容如下所示:

PHP中「==」運算子的安全性問題

正如你所看到的,當我們使用“==”來比較這些數字字符串時,參與比較的就是字符串中數字的實際大小,從安全的角度出發,這就是一個非常有趣的問題了。在這種情況下,你可以使用科學計數法來表示一個數字,並將其放在一個字串中,PHP將會自動把它作為一個數字類型來處理。我們之所以會得到這樣的輸出類型,是因為PHP使用了一種哈希演算法(通常使用十六進制數值表示)來進行處理。比如說,如果一個數字為0,那麼在進行鬆散比較的過程中,PHP會自動對其類型進行轉換,但其值永遠為0。對於一個給定的雜湊演算法而言,密碼就有可能會變成可以被替換的了。比如說,當密碼的雜湊值被轉換成使用科學計數法來表示的數字時,將有可能正好與其他的密碼雜湊相匹配。這樣一來,即使是一個完全不同的密碼,也有可能可以通過系統的驗證。但有趣的是,當某些採用科學計數法表示的數字在進行比較的時候,結果可能會讓你意想不到:

PHP中「==」運算子的安全性問題

從「黑盒測試」的角度出發來考慮這個問題

從靜態分析的角度來看,這些安全問題就顯得有些普通了。但如果我們從黑盒的角度來看待這些問題,我們能夠得到什麼樣的啟發呢?對於應用程式中的任何用戶帳號而言,如果應用程式使用了當前最為流行的哈希散列演算法(例如SHA1和MD5)來對密碼進行處理,而你在對密碼哈希進行驗證的時候使用了PHP的鬆散比較,那麼此時就有可能出現安全問題。我們現在可以考慮進行一次典型的滲透測試,你可以創建一個普通的帳號,將密碼設置成哈希值類似的其中一個密碼,然後使用其他的密碼進行登錄操作。很明顯,系統的安全性完全取決於你所使用的雜湊演算法。所以,我們假設你沒有在散列演算法中使用「Salt」值,那麼你至少得使用兩種不同的雜湊演算法來對密碼進行處理。

現在,在我們去對這些密碼組合進行研究之前,我們還應該考慮到一點——即密碼的要求。因為我們在對這些密碼和雜湊演算法進行分析之前,首先得確保我們所設定的初始密碼複合了密碼複雜度的要求,否則我們的分析和研究將會沒有任何的意義。因此,我們得確保我們的密碼長度至少為八個字元,密碼中包含有大小寫字母,數字,以及至少一個特殊字元:具體如下所示:
import random
import hashlib
import re
import string
import sys
prof = re.compile("^0+ed*$") # you can also consider: re.compile("^d*e0+$")
prefix = string.lower(sys.argv[1])+'!'+string.upper(sys.argv[1])+"%s"
num=0
while True:
    num+=1
    b = hashlib.sha256(prefix % num).hexdigest()
    if (b[0]=='0' and prof.match(b)):
        print(prefix+str(num),b)
登入後複製
為此,我專門編寫了一個Python腳本,雖然我沒有竭盡全力去優化這個腳本的性能,但是在PyPy編譯器的幫助下,這個精心編寫的腳本可以在我的AMD FX8350所有可用的CPU核心中穩定運行。除此之外,我還使用到了hashlib庫中的散列函數,而且為了避免遇到Python GIL的進程同步問題,我還生成了獨立的進程來對密碼數據進行處理。不僅如此,我還使用了非常複雜的技術來為每一個密碼產生不同的前綴,正如上面這段程式碼所示。
分析結果

在經過了一個多小時的分析之後,我得到了四個密碼的SHA1值。令我感到驚訝的是,拿到四個密碼的MD5值所需的時間竟然更短。

密碼的計算結果十分相似,具體如下所示:

PHP中「==」運算子的安全性問題

你可以隨意選取兩個密碼來進行對比,對比的演示結果如下:

PHP中「==」運算子的安全性問題

如果你無法得到如上圖所示的計算結果,那麼你應該感到幸運。你可以嘗試將使用者名稱和密碼捆綁在一起,然後使用帶有“salt”值的雜湊演算法來進行計算。你只需要修改一小部分程式碼即可實現,點擊「這裡」取得修改後的腳本。
解決方案

PHP給我們提供了一個解決方案,如果你想要對比哈希值,你應該使用password_verify()或hash_equals()這兩個函數。它們會對數據進行嚴格比較,並排除一些其他的干擾因素。但是請你注意,hash_equals()函數也可以用於字串的比較。
分析結論

雖然我們的分析步驟執行起來有些過於復雜,但是從黑盒測試的角度出發,我們所描述的方法也許可以給大家提供一些有價值的資訊。如果某個應用程式中的密碼採用了這樣的一種驗證機制,那麼它所帶來的安全問題將會超出PHP資料型別轉換本身所存在的問題。
問題遠不止於此

這個問題帶給我們的影響遠不止於此。攻擊者可以將這些密碼添加到字典檔案中,然後對應用程式中的所有用戶進行暴力破解攻擊。而且,如果應用程式的密碼恢復機制中存在不安全的因素,攻擊者還有可能對目標帳號進行不限次數的攻擊,直到攻擊成功為止。
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
最新問題
熱門推薦
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板