提问人:Minding 提问时间:12/21/2019 最后编辑:Minding 更新时间:2/24/2020 访问量:2338
PHP 7.4 和 MySQL:caching_sha2_password 拒绝长 (20c) 密码
PHP 7.4 & MySQL: caching_sha2_password Denying long (20c) passwords
问:
更新:
23.02.2020:该错误已在 PHP 7.4.3 中修复。
23.12.2019:我已发现哪些密码会受到影响。请参阅下面的回答。 对于为什么拒绝长密码的答案仍然不胜感激。
免责声明:我已经尝试了大约 2 小时,只是设置了不同的密码。我绝对相信下面的密码会导致问题。它适用于其他密码。我确实知道如何解决它:使用不同的密码。我想知道为什么它不起作用。因为这种不一致是不可接受的。
我能够在我的系统上重现该问题。
最近切换到 PHP 7.4 和 MySQL 8,它们默认使用 .
在验证它确实受PHP支持后,我无法让它与我随机生成的密码一起使用,所以我再次使用了PHP 7.3。caching_sha2_password
mysql_native_password
现在,我设置了一个新服务器并且它正常工作,所以我试图找出问题所在,以便我可以在我的另一台服务器上使用。caching_sha2_password
MySQL(通过 mysql shell 使用root
)
ALTER USER 'test'@'localhost' IDENTIFIED WITH caching_sha2_password BY '';
FLUSH PRIVILEGES;
QUIT
PHP的
const DB_HOST = '127.0.0.1';
const DB_USERNAME = 'test';
const DB_PASSWORD = '';
const DB_NAME = 'test_db';
$mysqli = new mysqli(DB_HOST, DB_USERNAME, DB_PASSWORD, DB_NAME);
TEST(重现)
php db.php
错误
PHP 警告:mysqli::__construct():(HY000/1045):第 5 行 /db.php 中的用户“test”@“localhost”(使用密码:YES)的访问被拒绝
解决方法:有趣的是,由于某种疯狂的原因,运行它再次修复了它:
mysql -u test -p
# Enter password
QUIT
重新设置密码会再次引入问题。
我注意到它失败了,基于我使用的密码。所以我认为这可能是不支持的字符或粘贴问题。
我将原始密码(40chars)归结为这个(20chars):
此密码会破坏它:l0QDEptp*L6tNo28ey^8
所有较短的组合都可以正常工作:
此密码适用于例如:以及以下密码:l0QDEptp*L6tNo28ey^
0QDEptp*L6tNo28ey^8
重要提示:仅在安全环境中测试此公共密码!
如果您能够重现该问题或对此有任何想法(解决方案/可能的原因),请告诉我。
注意:这个问题实际上发生在我所有随机生成的密码上,这些密码有 40 个字符长,包含特殊字符(例如:%^$!)。我想一些相对常见的组合会触发这个问题。
图片:演示
MySQL版本:mysql Ver 8.0.18-0ubuntu0.19.10.1 for Linux on aarch64 ((Ubuntu)) PHP版本:PHP 7.4.1(cli)(构建时间:Dec 18 2019 14:44:55) (NTS )
PHP错误报告:这里 MySQL错误报告:这里
答:
使用此脚本自动设置随机长度和内容密码,然后重新连接到 mysql 服务器。
$mysqli = new mysqli('localhost', 'username', 'initialpassword', 'dbname');
$i=0;
while (true) {
if($i!=0){
$mysqli = new mysqli('localhost', 'username', $pw, 'dbname');
}
$pw = bin2hex(random_bytes(rand(1, 16)));
$successd = $mysqli->query("ALTER USER 'username'@'localhost' IDENTIFIED WITH caching_sha2_password BY '{$pw}'");
echo "times:{$i} pw:{$pw} {$successd}\n";
$i++;
}
在我的环境中,迭代 100 万次后没有发生任何访问被拒绝错误。
评论
此问题仅发生在具有 19 个以上字符的密码上。可以通过 MySQL Shell () 登录一次来解决它。mysql -u test -p
PHP 测试脚本:
<?php
# Static
const DB_HOST = '127.0.0.1';
const DB_USER = 'test';
const DB_NAME = 'test_db';
const INITIAL_PW = 'Test123+++!!!';
# Variable
const CHARS = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+-!^$?#%';
//const CHARS = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
# At least one special char is required, because of my security configuration.
# Due to this restriction the script may fail randomly - only 'Access Denied' is important.
const REQUIRED_SPECIAL_CHAR = '$';
# Any length below 20 works - 20 and upwards fails.
const PASSWORD_LENGTH = 20;
# Number of iterations
const ITERATIONS = 10;
# Test
$pw = INITIAL_PW;
for($i = 0; $i < ITERATIONS; $i++) {
$mysqli = new mysqli(DB_HOST, DB_USER, $pw, DB_NAME);
if($mysqli->connect_errno !== 0) {
echo('Failed after '.$i.' iterations.'.PHP_EOL);
echo('Password: '.$pw.PHP_EOL);
exit;
}
$pw = getPassword(PASSWORD_LENGTH);
$mysqli->query("ALTER USER 'test'@'localhost' IDENTIFIED WITH caching_sha2_password BY '$pw'") OR DIE('Failed to set password (after '.$i.' iterations): '.$mysqli->error.PHP_EOL);
$mysqli->query('FLUSH PRIVILEGES') OR DIE('Failed to flush: '.$mysqli->error.PHP_EOL);
$mysqli->close() OR DIE('Failed to close: '.$mysqli->error.PHP_EOL);
}
echo('Done.'.PHP_EOL);
# Helper
function getPassword(int $length) {
$pw = '';
for($i = 1; $i < $length; $i++)
$pw .= CHARS[rand(0, strlen(CHARS) - 1)];
$pw .= REQUIRED_SPECIAL_CHAR;
return $pw;
}
?>
为什么长密码会发生这种情况?IDK(也许是缓存限制?
评论
const DB_HOST = 'localhost';