在PHP 中,當我們需要比較兩個字符串是否相等時,常用的方法是strcmp函數。但隨著安全需求的提升,PHP 5.6 引入了一個專門用於安全比較的函數hash_equals 。本文將詳細介紹這兩個函數的區別,並解釋為什麼在某些場景下推薦使用hash_equals 。
strcmp(string $str1, string $str2): int
strcmp用於按字典順序比較兩個字符串。它返回一個整數值:
0 表示兩個字符串完全相同
負數表示第一個字符串小於第二個字符串
正數表示第一個字符串大於第二個字符串
hash_equals(string $known_string, string $user_string): bool
hash_equals專門用於比較兩個字符串是否完全相同,且比較過程是防止計時攻擊(Timing Attack)的安全方式。它返回布爾值:
true表示兩個字符串完全相等
false表示不相等
在某些安全場景下,比如驗證密碼哈希、API 密鑰、簽名等敏感數據時,攻擊者可能通過測量比較函數的執行時間,推斷出字符串中相同部分的長度,進而逐步猜測正確的密鑰。普通的字符串比較函數(如strcmp )在發現第一個不同字符時就會立即返回,導致比較時間與字符串相等的部分長度有關,容易洩漏信息。
hash_equals設計時特別考慮了防止計時攻擊,其比較時間不會隨兩個字符串中相同部分的長度變化而變化,而是固定執行時間,從而降低洩漏信息的風險。
<?php
// 使用 strcmp 比較兩個字符串
$known = 'securetoken123';
$userInput = 'securetoken124';
if (strcmp($known, $userInput) === 0) {
echo "匹配成功(strcmp)";
} else {
echo "匹配失敗(strcmp)";
}
?>
<?php
// 使用 hash_equals 比較兩個字符串
$known = 'securetoken123';
$userInput = 'securetoken124';
if (hash_equals($known, $userInput)) {
echo "匹配成功(hash_equals)";
} else {
echo "匹配失敗(hash_equals)";
}
?>
注意,在上面代碼中的字符串比較, strcmp會在第一個不同字符時立即返回,而hash_equals會執行完整比較。
驗證密碼哈希:雖然大多數密碼驗證都通過password_verify ,但如果自己實現對比哈希時,推薦使用hash_equals 。
比較加密簽名:例如HMAC、JWT 等,避免密鑰被猜測。
比較安全令牌:API 密鑰、訪問令牌、驗證碼等。
簡單來說,任何安全相關的字符串比較,都建議使用hash_equals 。
hash_equals要求傳入的兩個參數類型為字符串,且長度相同,否則會直接返回false 。
在使用hash_equals前,建議確保輸入字符串都為字符串類型且長度一致,避免意外錯誤。
雖然strcmp是常用且功能強大的字符串比較函數,但在安全敏感的場合, hash_equals因其防止計時攻擊的特性,是更合適的選擇。正確使用hash_equals能有效提升應用的安全性,避免潛在的攻擊風險。