From 0eef9260a8b37453a7787d5e63bccdda5d464380 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Tue, 8 Dec 2020 14:00:33 +1100 Subject: [PATCH 1/2] mariadb-10.4+ empty passwords MariaDB-10.4 migrated their authentication to a global_priv table in JSON format. Also locked user accounts where added. By default the mariadb.sys is a locked user without a password and there as the owner of the mysql.user view. As its hazardous for a user to modify this we exclude locked accounts but still search for mysql_native_password plugin without authentication. We use versioned comments to process all other versions. The 5.5+ MySQL version comment is also read by MariaDB (ref: https://mariadb.com/kb/en/comment-syntax/ enabling the processing of plugins on other version that have plugins. While this branch doesn't yet apply to MySQL-8.0 yet, we add support for the locked user accounts in MySQL-8.0+ in a versioned comment (not read by MariaDB). --- mysqltuner.pl | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/mysqltuner.pl b/mysqltuner.pl index 77b8745..1a61558 100644 --- a/mysqltuner.pl +++ b/mysqltuner.pl @@ -1810,13 +1810,17 @@ sub security_recommendations { } # Looking for Empty Password - if ( mysql_version_ge( 5, 5 ) ) { + if ( mysql_version_ge(10, 4) ) { @mysqlstatlist = select_array -"SELECT CONCAT(user, '\@', host) FROM mysql.user WHERE ($PASS_COLUMN_NAME = '' OR $PASS_COLUMN_NAME IS NULL) AND plugin NOT IN ('unix_socket', 'win_socket', 'auth_pam_compat')"; +q{SELECT CONCAT(user, '@', host) FROM mysql.global_priv WHERE + JSON_CONTAINS(Priv, '"mysql_native_password"', '$.plugin') AND JSON_CONTAINS(Priv, '""', '$.authentication_string') + AND NOT JSON_CONTAINS(Priv, 'true', '$.account_locked')}; } else { @mysqlstatlist = select_array -"SELECT CONCAT(user, '\@', host) FROM mysql.user WHERE ($PASS_COLUMN_NAME = '' OR $PASS_COLUMN_NAME IS NULL)"; +"SELECT CONCAT(user, '\@', host) FROM mysql.user WHERE ($PASS_COLUMN_NAME = '' OR $PASS_COLUMN_NAME IS NULL) + /*!50501 AND plugin NOT IN ('unix_socket', 'win_socket', 'auth_pam_compat') */ + /*!80000 AND account_locked = 'N' AND password_expired = 'N' */"; } if (@mysqlstatlist) { foreach my $line ( sort @mysqlstatlist ) { From 79a4403c9c640501d1bf051cb8ef4837d82451d2 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Tue, 8 Dec 2020 14:18:03 +1100 Subject: [PATCH 2/2] MySQL-5.7/8.0+ auth_socket is safe MySQL has auth_socket as its plugin compared to unix_socket on MariaDB so accept that as a valid reason for having no authentication. MySQL [(none)]> show create user dan@localhost; +-----------------------------------------------------------------------------------------------------------------+ | CREATE USER for dan@localhost | +-----------------------------------------------------------------------------------------------------------------+ | CREATE USER 'dan'@'localhost' IDENTIFIED WITH 'auth_socket' REQUIRE NONE PASSWORD EXPIRE DEFAULT ACCOUNT UNLOCK | +-----------------------------------------------------------------------------------------------------------------+ 1 row in set (0.000 sec) MySQL [(none)]> select user,host,plugin from mysql.user; +---------------+-----------+-----------------------+ | user | host | plugin | +---------------+-----------+-----------------------+ | root | localhost | mysql_native_password | | mysql.session | localhost | mysql_native_password | | mysql.sys | localhost | mysql_native_password | | dan | localhost | auth_socket | | expiretest | % | mysql_native_password | | expiretest | localhost | mysql_native_password | +---------------+-----------+-----------------------+ 6 rows in set (0.001 sec) MySQL [(none)]> select version(); +-----------+ | version() | +-----------+ | 5.7.31 | +-----------+ --- mysqltuner.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysqltuner.pl b/mysqltuner.pl index 1a61558..3ee1642 100644 --- a/mysqltuner.pl +++ b/mysqltuner.pl @@ -1819,7 +1819,7 @@ q{SELECT CONCAT(user, '@', host) FROM mysql.global_priv WHERE else { @mysqlstatlist = select_array "SELECT CONCAT(user, '\@', host) FROM mysql.user WHERE ($PASS_COLUMN_NAME = '' OR $PASS_COLUMN_NAME IS NULL) - /*!50501 AND plugin NOT IN ('unix_socket', 'win_socket', 'auth_pam_compat') */ + /*!50501 AND plugin NOT IN ('auth_socket', 'unix_socket', 'win_socket', 'auth_pam_compat') */ /*!80000 AND account_locked = 'N' AND password_expired = 'N' */"; } if (@mysqlstatlist) {