自 2017 年以來,NIST 建議在雜湊記憶的密碼等機密資訊時使用秘密輸入。透過混入秘密輸入(通常稱為「胡椒」),即使攻擊者擁有雜湊值和鹽,也能防止他們徹底暴力破解密碼雜湊。例如,SQL 注入通常只影響資料庫,不會影響磁碟上的檔案,因此儲存在設定檔中的胡椒仍然超出攻擊者的範圍。胡椒必須隨機產生一次,並且對於所有使用者都可以相同。如果網站擁有者這樣做,許多密碼洩漏事件可能會完全無效。
由於 password_hash 沒有胡椒參數(即使 Argon2 有一個「secret」參數,PHP 也不允許設定它),混入胡椒的正確方法是使用 hash_hmac()。php.net 的「新增註解」規則說我不能連結外部網站,所以我無法用 NIST、維基百科、來自安全堆疊交換網站的解釋理由的文章等連結來支持任何這些說法... 您必須手動驗證。程式碼
// config.conf
pepper=c1isvFdxMDdmjOlvxpecFw
<?php
$pepper = getConfigVariable("pepper");
$pwd = $_POST['password'];
$pwd_peppered = hash_hmac("sha256", $pwd, $pepper);
$pwd_hashed = password_hash($pwd_peppered, PASSWORD_ARGON2ID);
add_user_to_database($username, $pwd_hashed);
?>
<?php
$pepper = getConfigVariable("pepper");
$pwd = $_POST['password'];
$pwd_peppered = hash_hmac("sha256", $pwd, $pepper);
$pwd_hashed = get_pwd_from_db($username);
if (password_verify($pwd_peppered, $pwd_hashed)) {
echo "密碼符合。";
}
else {
echo "密碼不正確。";
}
?>
請注意,此程式碼包含一個洩漏使用者名稱是否存在的時間攻擊。但是我的註解超過了長度限制,所以我不得不刪除這段文字。
另請注意,如果洩漏或可以破解,胡椒是無用的。考慮一下它可能如何暴露,例如將它傳遞給 docker 容器的不同方法。為了防止破解,請使用一個長的隨機產生值(如上面的範例),並在您使用乾淨的使用者資料庫進行新安裝時變更胡椒。變更現有資料庫的胡椒與變更其他雜湊參數相同:您可以將舊值包裝在新值中並分層雜湊(更複雜),您可以在有人登入時計算新的密碼雜湊(使舊使用者處於風險之中,因此這可能沒問題,具體取決於您升級的原因)。
為什麼會這樣?因為攻擊者在竊取資料庫後會執行以下操作
password_verify("a", $stolen_hash)
password_verify("b", $stolen_hash)
...
password_verify("z", $stolen_hash)
password_verify("aa", $stolen_hash)
等等。
(更實際的做法是,他們使用破解字典,但原則上,破解密碼雜湊的方式是猜測。這就是我們使用特殊演算法的原因:它們速度較慢,因此每個 verify() 操作都會較慢,因此他們每小時破解的密碼會少很多。)
現在,如果您使用了胡椒呢?現在他們需要做的是
password_verify(hmac_sha256("a", $secret), $stolen_hash)
沒有那個 $secret(胡椒),他們就無法進行此計算。他們必須做
password_verify(hmac_sha256("a", "a"), $stolen_hash)
password_verify(hmac_sha256("a", "b"), $stolen_hash)
...
等等,直到他們找到正確的胡椒。
如果您的胡椒包含 128 位元的熵,並且只要 hmac-sha256 保持安全(即使 MD5 在 hmac 中使用在技術上是安全的:只有其衝突抗性被破壞,但當然沒有人會使用 MD5,因為發現的缺陷越來越多),這將比太陽輸出的能量還要多。換句話說,目前不可能破解如此強大的胡椒,即使已知密碼和鹽也是如此。