PHP安全之道學習筆記2:編碼安全指南
編碼安全指南
程式設計本身就應該是一門藝術,而安全程式設計更是一種在刀尖上舞蹈的藝術,不僅要小心腳下的鋒利寒刃,更要小心來自網路黑客或攻擊者的狂轟亂炸。
- by code artist
- 1.hash比較的缺陷
經過試驗發現,當Hash值以"0e"開頭且後面都為數字,當和數字進行比較的時候總會被判斷和0相等
例如:
var_dump('0e1327544' == 0); // bool(true)
當密碼被md5計算後,可能會以"0e"開頭,下面這個例子可以繞過密碼驗證。
經過我的驗證PHP 7.1.x後沒有這種問題。
<?php $password_from_db = "0e23434"; $password = "2323"; // 隨意的一個密碼。來自$_POST,即表單提交 if ($password_from_db == md5($password)) { echo "login success!"; } else { echo "login fails"; }
更安全的hash比較:
可以使用內建函式hash_equals()來比較hash值。(PHP版本必須是5.6及其以上)
if (hash_equals($password_from_db, md5($password)) {
.....// other logic
}
- 2.bool比較的缺陷
json_decode和unserialize函式可能將部分結構解析成bool值,造成一些比較上的缺陷。
先舉例json_decode的案例:
<?php $str = '{"user":true, "pass": true}'; $data = json_decode($str, true); if ($data['user'] == 'root' && $data['pass'] == 'pass') { echo "login success\r\n"; } else { echo "login fails\r\n"; }
執行結果為:login success
這樣利用bool比較的漏洞就繞過了登入或者授權驗證。
unserialize過程相逆,結果類似,也會出現安全問題。
正確的做法還是使用"==="來進行比較,這不光是php,包括一些其他指令碼語言或者靜態語言,都請嚴謹地使用全等於符號進行比較。
- 3.數值比較
PHP雖然是弱型別語言,但是資料型別也有數值範圍。對於整型而言,最大值為PHP_INT_MAX(即9223372036854775807)
攻擊者可以利用最大值越界,繞過一些驗證,如登入、賬號充值等等。
舉例:
$a = 9223372036854775807; $b = 9223372036854775827; var_dump($a === $b); // bool(true) var_dump($a % 100); // int(0)
由此,可見全等號(===)也不是萬能的,具體場景下要更小心。經驗證,PHP7.1.x後不會出現該問題,5.x的可能出現。
在實際業務邏輯裡面一定要注意判斷最大值問題,避免越界帶來的問題。
當使用超長浮點數變數的時候,PHP也會出錯。
<?php
$uid = 0.999999999999999999;
if ($uid == "1") {
echo "search uid is 1 for data\r\n"; // 這裡PHP將$uid約等於1了,進入該判斷條件裡的邏輯
}
同理,2.999999999999也會被當成3,這就是超越浮點數精度造成的偏差。
解決辦法有很多,最簡單的就是用is_int()函式進行判斷,如果不是整型,則報錯或做錯誤處理。
- 4.switch缺陷
當用case判斷數字的時候,switch會把引數轉換成int型別進行計算,程式碼如下:
<?php
$num = "1FreePHP";
switch ($num) {
case 0: echo "nothing";
break;
case 1: echo "1 hacker here!";
break;
case 2: echo "2 hackers here";
break;
default:
echo "confused";
}
最後輸出:1 hacker here!
所以,請使用is_numeric()函式進行判斷,保證資料型別如預期的一致。
- 5.陣列缺陷。
in_array()和array_search()函式在沒有使用嚴格模式的情況下會用鬆散比較,可能造成一些錯誤。
例如:
<?php
$arr = [0, 2, 3, "4"];
var_dump(in_array('freephp', $arr)); // true
var_dump(array_search('freephp', $arr)); // 0: 下標
var_dump(in_array('2freephp', $arr)); // true
var_dump(array_search('3freephp', $arr)); // 2: 下標
總的來說,PHP工程師對於這種弱型別語言的使用上要更加小心,雖然平時寫起業務來“短平快”,但安全程式設計也不要忘記,能用上hint的高版本PHP就進行標註清楚入參、出參,讓PHP程式碼更加健壯。