扩展 MySQL 8.0  / 第 4 章 MySQL 插件 API  / 4.4 编写插件  / 4.4.9 编写认证插件  /  6.4.1.3 从 4.1 之前的密码散列和 mysql_old_password 插件迁移

6.4.1.3 从 4.1 之前的密码散列和 mysql_old_password 插件迁移

mysql.userMySQL 服务器使用列中命名的身份验证插件 对系统表中列出的每个帐户的连接尝试进行身份验证plugin。如果该 plugin列为空,服务器将按如下方式验证帐户:

  • 在 MySQL 5.7 之前,服务器隐式使用 mysql_native_passwordor mysql_old_password插件,具体取决于 Password列中密码哈希的格式。如果该 Password值为空或 4.1 密码哈希(41 个字符),则服务器使用 mysql_native_password. 如果密码值是 pre-4.1 密码哈希(16 个字符),则服务器使用mysql_old_password. (有关这些哈希格式的其他信息,请参阅 第 6.1.2.4 节,“MySQL 中的密码哈希”。)

  • 从 MySQL 5.7 开始,服务器要求该 plugin列为非空并禁用具有空plugin值的帐户。

4.1 之前的密码哈希和 mysql_old_password插件在 MySQL 5.6 中被弃用,在 MySQL 5.7 中删除了对它们的支持。它们提供的安全级别低于 4.1 密码哈希和 mysql_native_password插件提供的级别。

鉴于 MySQL 5.7 要求该 plugin列必须为非空,加上取消了mysql_old_password支持,建议 DBA 升级帐户如下:

  • mysql_native_password将隐式使用的 帐户升级 为显式使用

  • mysql_old_password升级使用(隐式或显式)mysql_native_password 显 式使用的 帐户

本节中的说明描述了如何执行这些升级。结果是没有帐户具有空 plugin值,也没有帐户使用 pre-4.1 密码哈希或mysql_old_password 插件。

作为这些说明的变体,DBA 可能会为用户提供升级到sha256_password 插件的选择,该插件使用 SHA-256 密码哈希进行身份验证。有关此插件的信息,请参阅 第 6.4.1.5 节,“SHA-256 可插入身份验证”

下表列出了 mysql.user本次讨论中考虑的帐户类型。

plugin柱子 Password柱子 认证结果 升级动作
空的 空的 隐式使用mysql_native_password 分配插件
空的 4.1 哈希 隐式使用mysql_native_password 分配插件
空的 4.1 之前的哈希 隐式使用mysql_old_password 分配插件,重新哈希密码
mysql_native_password 空的 明确使用mysql_native_password 没有任何
mysql_native_password 4.1 哈希 明确使用mysql_native_password 没有任何
mysql_old_password 空的 明确使用mysql_old_password 升级插件
mysql_old_password 4.1 之前的哈希 明确使用mysql_old_password 升级插件,重新哈希密码

与插件行对应的帐户 mysql_native_password不需要升级操作(因为不需要更改插件或哈希格式)。对于与密码为空的行对应的帐户,考虑要求帐户所有者选择一个密码(或通过使用ALTER USER使空帐户密码过期来要求它)。

将帐户从隐式升级为显式 mysql_native_password 使用

具有空插件和 4.1 密码哈希的帐户 mysql_native_password隐式使用。要升级这些帐户以mysql_native_password 明确使用,请执行以下语句:

UPDATE mysql.user SET plugin = 'mysql_native_password'
WHERE plugin = '' AND (Password = '' OR LENGTH(Password) = 41);
FLUSH PRIVILEGES;

在 MySQL 5.7 之前,您可以执行这些语句来主动升级帐户。从 MySQL 5.7 开始,您可以运行 mysql_upgrade,它在升级操作中执行相同的操作。

笔记:

  • 刚刚描述的升级操作在任何时候都可以安全地执行,因为它使 mysql_native_password插件只对已经隐式使用它的帐户显式。

  • 此操作不需要更改密码,因此可以在不影响用户或不需要他们参与升级过程的情况下执行。

将帐户从 mysql_old_password 升级到 mysql_native_password

使用(隐式或显式)的帐户mysql_old_password应升级为 mysql_native_password显式使用。这需要更改插件并将密码从 pre-4.1 更改为 4.1 哈希格式。

对于必须升级的此步骤中涵盖的帐户,以下条件之一为真:

  • 该帐户mysql_old_password 隐式使用,因为该plugin列为空且密码具有 4.1 之前的哈希格式(16 个字符)。

  • 该帐户mysql_old_password 明确使用。

要识别此类帐户,请使用以下查询:

SELECT User, Host, Password FROM mysql.user
WHERE (plugin = '' AND LENGTH(Password) = 16)
OR plugin = 'mysql_old_password';

以下讨论提供了两种更新该帐户集的方法。它们具有不同的特性,因此请阅读两者并决定哪个最适合给定的 MySQL 安装。

方法一。

这种方法的特点:

  • 它要求服务器和客户端一直运行, secure_auth=0直到所有用户都升级到mysql_native_password. (否则,用户无法使用旧格式的密码哈希连接到服务器以升级到新格式的哈希。)

  • 它适用于 MySQL 5.5 和 5.6。在 5.7 中,它不起作用,因为服务器要求帐户具有非空插件,否则将禁用它们。因此,如果您已经升级到 5.7,请选择稍后介绍的方法 2。

您应该确保服务器正在运行 secure_auth=0.

对于所有明确使用的帐户mysql_old_password ,将它们设置为空插件:

UPDATE mysql.user SET plugin = ''
WHERE plugin = 'mysql_old_password';
FLUSH PRIVILEGES;

要使受影响帐户的密码也过期,请改用以下语句:

UPDATE mysql.user SET plugin = '', password_expired = 'Y'
WHERE plugin = 'mysql_old_password';
FLUSH PRIVILEGES;

现在受影响的用户可以重置密码以使用 4.1 哈希。要求每个现在拥有空插件的用户连接到服务器并执行这些语句:

SET old_passwords = 0;
SET PASSWORD = PASSWORD('user-chosen-password');
笔记

The client-side --secure-auth option is enabled by default, so remind users to disable it; otherwise, they cannot connect:

$> mysql -u user_name -p --secure-auth=0

After an affected user has executed those statements, you can set the corresponding account plugin to mysql_native_password to make the plugin explicit. Or you can periodically run these statements to find and fix any accounts for which affected users have reset their password:

UPDATE mysql.user SET plugin = 'mysql_native_password'
WHERE plugin = '' AND (Password = '' OR LENGTH(Password) = 41);
FLUSH PRIVILEGES;

When there are no more accounts with an empty plugin, this query returns an empty result:

SELECT User, Host, Password FROM mysql.user
WHERE plugin = '' AND LENGTH(Password) = 16;

At that point, all accounts have been migrated away from pre-4.1 password hashing and the server no longer need be run with secure_auth=0.

Method 2.

Characteristics of this method:

  • It assigns each affected account a new password, so you must tell each such user the new password and ask the user to choose a new one. Communication of passwords to users is outside the scope of MySQL, but should be done carefully.

  • It does not require server or clients to be run with secure_auth=0.

  • It works for any version of MySQL 5.5 or later (and for 5.7 has an easier variant).

With this method, you update each account separately due to the need to set passwords individually. Choose a different password for each account.

Suppose that 'user1'@'localhost' is one of the accounts to be upgraded. Modify it as follows:

  • In MySQL 5.7, ALTER USER provides the capability of modifying both the account password and its authentication plugin, so you need not modify the mysql.user system table directly:

    ALTER USER 'user1'@'localhost'
    IDENTIFIED WITH mysql_native_password BY 'DBA-chosen-password';

    To also expire the account password, use this statement instead:

    ALTER USER 'user1'@'localhost'
    IDENTIFIED WITH mysql_native_password BY 'DBA-chosen-password'
    PASSWORD EXPIRE;

    Then tell the user the new password and ask the user to connect to the server with that password and execute this statement to choose a new password:

    ALTER USER USER() IDENTIFIED BY 'user-chosen-password';
  • Before MySQL 5.7, you must modify the mysql.user system table directly using these statements:

    SET old_passwords = 0;
    UPDATE mysql.user SET plugin = 'mysql_native_password',
    Password = PASSWORD('DBA-chosen-password')
    WHERE (User, Host) = ('user1', 'localhost');
    FLUSH PRIVILEGES;

    To also expire the account password, use these statements instead:

    SET old_passwords = 0;
    UPDATE mysql.user SET plugin = 'mysql_native_password',
    Password = PASSWORD('DBA-chosen-password'), password_expired = 'Y'
    WHERE (User, Host) = ('user1', 'localhost');
    FLUSH PRIVILEGES;

    然后告诉用户新密码并要求用户使用该密码连接到服务器并执行以下语句以选择新密码:

    SET old_passwords = 0;
    SET PASSWORD = PASSWORD('user-chosen-password');

对每个要升级的帐户重复此操作。