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,默认情况下使用 caching_sha2_password
。
在 它实际上被 PHP 支持之后,我无法使用我随机生成的密码来使用它,所以我再次使用 PHP 7.3 和 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 Warning: mysqli::__construct(): (HY000/1045): Access denied for user 'test'@'localhost' (using password: YES) in /db.php on line 5
解决方法:有趣的是 运行 由于一些疯狂的原因,这再次修复了它:
mysql -u test -p
# Enter password
QUIT
重新设置密码后问题再次出现。
我注意到根据我使用的密码,它失败了。所以我认为这可能是不支持的字符或粘贴问题。
我把我原来的密码(40 个字符)压缩成这个(20 个字符):
这个密码破解了它:l0QDEptp*L6tNo28ey^8
所有较短的组合都可以正常工作:
此密码适用于例如:l0QDEptp*L6tNo28ey^
以及此密码:0QDEptp*L6tNo28ey^8
重要提示:仅在安全环境中测试此 public 密码!
如果您能够重现问题或对此有任何想法(解决方案/可能的原因),请告诉我。
注意:这个问题实际上发生在我所有随机生成的密码上,这些密码长度为 40 个字符并包含特殊字符(例如:%^$!)。我猜是一些相对常见的组合触发了这个问题。
图片: Demo
MySQL 版本: mysql Ver 8.0.18-0ubuntu0.19.10.1 for Linux on aarch64 ((Ubuntu))
PHP 版本: PHP 7.4.1(cli)(内置:2019 年 12 月 18 日 14:44:55)(NTS)
PHP 错误报告: Here
MySQL 错误报告: Here
使用此脚本自动设置随机长度和内容密码,然后重新连接到 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(可能是缓存限制?)
更新:
23.02.2020: 该错误已在 PHP 7.4.3.
中修复23.12.2019: 我发现哪些密码受到了影响。请参阅下面的答案。 仍然非常感谢为什么拒绝长密码的答案。
免责声明:我已经尝试了大约 2 个小时,只是设置了不同的密码。我绝对相信下面的密码会导致问题。它适用于其他密码。我知道如何修复它:使用不同的密码。我想知道为什么它不起作用。因为这种不一致是不能接受的。
我能够在我的系统上重现该问题。
最近切换到 PHP 7.4 和 MySQL 8,默认情况下使用 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 Warning: mysqli::__construct(): (HY000/1045): Access denied for user 'test'@'localhost' (using password: YES) in /db.php on line 5
解决方法:有趣的是 运行 由于一些疯狂的原因,这再次修复了它:
mysql -u test -p
# Enter password
QUIT
重新设置密码后问题再次出现。
我注意到根据我使用的密码,它失败了。所以我认为这可能是不支持的字符或粘贴问题。
我把我原来的密码(40 个字符)压缩成这个(20 个字符):
这个密码破解了它:l0QDEptp*L6tNo28ey^8
所有较短的组合都可以正常工作:
此密码适用于例如:l0QDEptp*L6tNo28ey^
以及此密码:0QDEptp*L6tNo28ey^8
重要提示:仅在安全环境中测试此 public 密码!
如果您能够重现问题或对此有任何想法(解决方案/可能的原因),请告诉我。
注意:这个问题实际上发生在我所有随机生成的密码上,这些密码长度为 40 个字符并包含特殊字符(例如:%^$!)。我猜是一些相对常见的组合触发了这个问题。
图片: Demo
MySQL 版本: mysql Ver 8.0.18-0ubuntu0.19.10.1 for Linux on aarch64 ((Ubuntu))
PHP 版本: PHP 7.4.1(cli)(内置:2019 年 12 月 18 日 14:44:55)(NTS)
PHP 错误报告: Here
MySQL 错误报告: Here
使用此脚本自动设置随机长度和内容密码,然后重新连接到 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(可能是缓存限制?)