扩展 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.4 节,“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');
笔记

客户端--secure-auth 选项默认开启,提醒用户关闭,否则无法连接:

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

在受影响的用户执行了这些语句后,您可以将相应的帐户插件设置 mysql_native_password为显式插件。或者您可以定期运行这些语句来查找和修复受影响用户已为其重置密码的任何帐户:

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

当没有更多帐户具有空插件时,此查询将返回空结果:

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

那时,所有帐户都已从 4.1 之前的密码散列中迁移出来,服务器不再需要使用 secure_auth=0.

方法二。

这种方法的特点:

  • 它为每个受影响的帐户分配一个新密码,因此您必须告诉每个这样的用户新密码并要求用户选择一个新密码。向用户传达密码不在 MySQL 的范围内,但应谨慎进行。

  • 它不需要服务器或客户端与 secure_auth=0.

  • 它适用于任何版本的 MySQL 5.5 或更高版本(并且 5.7 有一个更简单的变体)。

使用这种方法,由于需要单独设置密码,您可以单独更新每个帐户。为每个帐户选择不同的密码。

假设这'user1'@'localhost'是要升级的帐户之一。修改如下:

  • 在MySQL 5.7中,ALTER USER提供了同时修改账号密码和认证插件的能力,不需要 mysql.user直接修改系统表:

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

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

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

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

    ALTER USER USER() IDENTIFIED BY 'user-chosen-password';
  • 在 MySQL 5.7 之前,您必须 mysql.user使用这些语句直接修改系统表:

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

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

    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');

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