1、安全開發-原生PHP-弱類型脆弱
2、安全開發-原生PHP-函數&數據類型
3、安全開發-原生PHP-代碼審計案例
1、== 和 ===
兩個等號==是弱比較,使用==進行對比的時候,php解析器就會做隱式類型轉換,如果兩個值的類型不相等就會把兩個值的類型轉為同一類型進行對比。
==:弱比較運算符,進行比較時,PHP會嘗試將兩個值的類型進行隱式轉換為相同的類型。
===:強比較運算符,要求類型和值都相等,不進行任何隱式轉換。
在弱比較下,某些值之間可能因為隱式類型轉換導致不符合預期的結果。例如:
if ("123abc" == 123) {echo "True"; // 輸出 "True",因為 "123abc" 被轉換為數字 123 進行比較
}
建議與修復:
總是優先使用 === 進行比較,避免隱式類型轉換。
如果必須使用弱比較,明確了解隱式轉換規則,并確保輸入類型符合預期。
if ("123abc" === 123) {echo "True"; // 不會輸出任何結果
}
2、MD5對比缺陷
進行hash加密出來的字符串如存在0e開頭進行弱比較的話會直接判定為true
QNKCDZO與0e830400451993494058024219903391
md5(QNKCDZO,32) = 0e830400451993494058024219903391
240610708與0e462097431906509019562988736854
md5(240610708,32) = 0e462097431906509019562988736854
s878926199a與0e545993274517709034328855841020
md5(s878926199a,32) = 0e545993274517709034328855841020
MD5 哈希值以 0e
開頭時,PHP 的弱比較會將其解釋為科學計數法的數字 0
。例如:
if (md5('QNKCDZO') == md5('240610708')) {echo "True"; // 輸出 "True",因為兩個哈希值都以 `0e` 開頭,被解析為 0
}
安全隱患:這種比較方式會導致哈希碰撞,攻擊者可以利用特定輸入生成以 0e
開頭的 MD5 值,從而繞過驗證。
建議與修復:
不要使用弱比較 (==) 進行哈希值驗證,應使用強比較 (===)。
使用更安全的哈希算法,如 hash_hmac 或 password_hash。
if (md5('QNKCDZO') === md5('240610708')) {echo "True"; // 不會輸出任何結果
}
3 函數strcmp類型比較缺陷
低版本的strcmp比較的是字符串類型,如果強行傳入其他類型參數,會出錯,出錯后返回值0,正是利用這點進行繞過。
在 PHP 的低版本中,strcmp()
函數只能用于比較字符串。如果傳入非字符串參數,會返回 0
,因為出錯后 PHP 內部會返回相等的結果。
if (strcmp([], "string") == 0) {echo "True"; // 輸出 "True",因為出錯后返回 0
}
安全隱患:攻擊者可以通過傳入特殊類型的參數(如數組、對象)繞過邏輯判斷。
建議與修復:
確保傳入參數的類型始終是字符串。
使用顯式類型檢查或類型強制轉換:
if (is_string($param1) && is_string($param2) && strcmp($param1, $param2) === 0) {echo "Strings are equal.";
}
4、函數Bool類型比較缺陷
在使用 json_decode() 函數或 unserialize() 函數時,部分結構被解釋成 bool 類型,也會造成缺陷,運行結果超出研發人員的預期
使用 json_decode()
解析 JSON 字符串或 unserialize()
反序列化數據時,如果數據的結構意外被解析為布爾值,可能會引發邏輯錯誤。例如:
$json = 'false';
if (json_decode($json)) {echo "True"; // 不輸出任何結果,但邏輯可能被繞過
}
安全隱患:攻擊者可以構造特定的 JSON 數據或序列化數據,導致解析結果超出預期。
建議與修復:
顯式檢查解析結果的類型和結構:
$data = json_decode($json, true);
if (is_array($data) && isset($data['key'])) {// 進一步邏輯處理
}
5、函數switch 類型比較缺陷
當在switch中使用case判斷數字時,switch會將參數轉換為int類型計算
switch
語句中,PHP 會將 case
參數轉換為整數類型進行比較。如果傳入字符串類型的參數,可能會意外被轉換為數字:
switch ("123abc") {case 123:echo "Matched"; // 輸出 "Matched",因為 "123abc" 被轉換為 123break;
}
安全隱患:攻擊者可以通過構造特定輸入繞過邏輯判斷。
建議與修復:
避免在 switch 中混用不同類型的數據。
使用 === 替代 switch 語句中的隱式比較
$value = "123abc";
if ($value === 123) {echo "Matched";
}
6、函數in_array數組比較缺陷
當使用in_array()或array_search()函數時,如果第三個參數沒有設置為true,則in_array()或array_search()將使用松散比較來判斷
in_array()
和 array_search()
默認使用弱比較(==
)。如果未設置第三個參數為 true
,可能會導致意外的比較結果:
$array = ["123", 123];
if (in_array("123abc", $array)) {echo "True"; // 輸出 "True",因為 "123abc" 被轉換為數字 123
}
安全隱患:攻擊者可以構造與數組中已有值相等的不同類型數據,繞過驗證。
建議與修復:
始終設置第三個參數為 true,啟用嚴格比較:
if (in_array("123abc", $array, true)) {echo "True"; // 不會輸出任何結果
}
7、===數組比較缺陷
注意此時遇到的是 “===” ,不過也不是代表無從下手。在md5()函數傳入數組時會報錯返回NULL,當變量都導致報錯返回NULL時就能使使得條件成立。
在 PHP 中,md5()
函數不支持數組作為參數,會拋出錯誤并返回 NULL
。如果多個變量導致函數返回 NULL
,可能使條件成立:
$a = md5([]);
$b = md5([]);
if ($a === $b) {echo "True"; // 輸出 "True",因為兩次調用均返回 NULL
}
安全隱患:攻擊者可以利用此特性通過錯誤處理來繞過邏輯。
建議與修復:
確保函數參數的類型符合預期:
if (is_string($input) && md5($input) === $knownHash) {echo "Valid";
}
使用顯式類型驗證,避免直接比較可能返回錯誤的結果。
案例:
CTF題目:
矛盾 - Bugku CTF平臺
MD5 - Bugku CTF平臺
代碼審CMS:
某Info CMS代碼審計