PHP .crypt() 对于不同的字符串和盐产生相同的结果

PHP .crypt() results identical for different strings and salts

因为我使用的是旧版本的PHP,所以我必须使用.crypt()。我正在测试一些密码验证,服务器正在验证错误的密码是否正确。然后我决定尽可能进行最基本的测试,但我仍然遇到这个问题:

<?php
echo crypt("cryptcryptcrypt","salt");
echo "<br>";
echo crypt("cryptcryptcrypta","salta");
?>

– 结果是:

saRyxun8Pn/K6
saRyxun8Pn/K6

为什么会这样?


出于测试目的,我使用的是 PhpFiddle,因此您在回答问题时可能会发现这很有用...

引用docs

The standard DES-based crypt() returns the salt as the first two characters of the output. It also only uses the first eight characters of str, so longer strings that start with the same eight characters will generate the same result (when the same salt is used).

您提供的盐只有 4 或 5 个字符长,这使得 crypt 使用标准的基于 DES 的算法。因此,只使用密码的前 9 个字符,并且只使用盐的前两个字符。因此你的哈希值是相等的。你真的应该更新你的 PHP 版本,这样你就可以使用现代的 password_hash 功能。如果那不可能,请尝试使用与 PHP 版本 3 及更高版本兼容的 http://www.openwall.com/phpass/。如果那不可能继续阅读...

您需要将正确格式的盐传递给 crypt 函数。来自文档中的示例:

if (CRYPT_BLOWFISH == 1) {
    echo 'Blowfish:     ' . crypt('rasmuslerdorf', 'a$usesomesillystringforsalt$') . "\n";
}

if (CRYPT_SHA256 == 1) {
    echo 'SHA-256:      ' . crypt('rasmuslerdorf', '$rounds=5000$usesomesillystringforsalt$') . "\n";
}

if (CRYPT_SHA512 == 1) {
    echo 'SHA-512:      ' . crypt('rasmuslerdorf', '$rounds=5000$usesomesillystringforsalt$') . "\n";
}

哈希的开头定义了要使用的算法。您还需要确保为每个用户使用随机的唯一盐。