MySQL8 中文参考(二十五)(2)https://developer.aliyun.com/article/1566165
双密码支持
截至 MySQL 8.0.14,用户帐户被允许具有主密码和辅助密码,称为双密码。双密码功能使得在诸如此类场景中无缝执行凭据更改成为可能:
- 一个系统有大量的 MySQL 服务器,可能涉及复制。
- 多个应用程序连接到不同的 MySQL 服务器。
- 必须定期更改用于连接到服务器的应用程序使用的帐户或帐户的凭据。
考虑在前述类型的场景中执行凭据更改时,当一个账户只允许一个密码时。在这种情况下,必须在账户密码更改和在所有服务器上传播时以及所有使用该账户的应用程序更新以使用新密码的时间上进行紧密合作。这个过程可能涉及停机,期间服务器或应用程序不可用。
通过双重密码,可以更轻松地分阶段进行凭据更改,无需紧密合作,也无需停机:
- 对于每个受影响的账户,在服务器上建立一个新的主密码,将当前密码保留为次要密码。这使得服务器可以识别每个账户的主密码或次要密码,而应用程序可以继续使用与以前相同的密码连接到服务器(现在是次要密码)。
- 在密码更改传播到所有服务器后,修改使用任何受影响账户的应用程序,以使用账户主密码连接。
- 在所有应用程序已从次要密码迁移到主密码后,次要密码不再需要,可以丢弃。此更改传播到所有服务器后,每个账户只能使用主密码连接。凭据更改现在已完成。
MySQL 使用保存和丢弃次要密码的语法实现双重密码功能:
RETAIN CURRENT PASSWORD
子句用于ALTER USER
和SET PASSWORD
语句,当您分配新的主密码时,会将账户当前密码保存为其次要密码。DISCARD OLD PASSWORD
子句用于ALTER USER
,丢弃账户次要密码,仅保留主密码。
假设对于先前描述的凭据更改场景,一个名为'appuser1'@'host1.example.com'
的账户被应用程序用于连接服务器,并且要将账户密码从'*
password_a*'
更改为'*
password_b*'
。
要执行凭据更改,请使用以下ALTER USER
:
- 在每个非副本服务器上,建立
'*
password_b*'
作为新的appuser1
主密码,保留当前密码作为次要密码:
ALTER USER 'appuser1'@'host1.example.com' IDENTIFIED BY '*password_b*' RETAIN CURRENT PASSWORD;
- 等待密码更改在整个系统中复制到所有副本。
- 修改使用
appuser1
账户的每个应用程序,使其使用密码'*
password_b*'
而不是'*
password_a*'
连接到服务器。 - 此时,次要密码不再需要。在每个非副本服务器上丢弃次要密码:
ALTER USER 'appuser1'@'host1.example.com' DISCARD OLD PASSWORD;
- 在丢弃密码更改已经复制到所有副本之后,凭据更改完成。
RETAIN CURRENT PASSWORD
和 DISCARD OLD PASSWORD
子句具有以下效果:
RETAIN CURRENT PASSWORD
会保留账户当前密码作为其二级密码,替换任何现有的二级密码。新密码成为主密码,但客户端可以使用主密码或二级密码连接到服务器。 (例外情况:如果由ALTER USER
或SET PASSWORD
语句指定的新密码为空,则即使给出RETAIN CURRENT PASSWORD
,二级密码也会变为空。)- 如果您为具有空主密码的账户指定
RETAIN CURRENT PASSWORD
,则该语句将失败。 - 如果一个账户有二级密码,并且您更改其主密码而不指定
RETAIN CURRENT PASSWORD
,则二级密码保持不变。 - 对于
ALTER USER
,如果更改分配给账户的身份验证插件,则二级密码将被丢弃。 如果更改身份验证插件并且还指定RETAIN CURRENT PASSWORD
,则该语句将失败。 - 对于
ALTER USER
,DISCARD OLD PASSWORD
会丢弃二级密码(如果存在)。账户仅保留其主密码,客户端只能使用主密码连接到服务器。
修改二级密码的语句需要以下权限:
- 要使用
RETAIN CURRENT PASSWORD
或DISCARD OLD PASSWORD
子句来操作您自己的账户的ALTER USER
和SET PASSWORD
语句,需要APPLICATION_PASSWORD_ADMIN
权限。 大多数用户只需要一个密码,因此需要该权限来操作自己的二级密码。 - 如果要允许一个账户为所有账户操作二级密码,则应授予
CREATE USER
权限,而不是APPLICATION_PASSWORD_ADMIN
。
随机密码生成
截至 MySQL 8.0.18 版本,CREATE USER
,ALTER USER
和 SET PASSWORD
语句具有生成用户账户随机密码的功能,作为明文密码的替代选择。有关语法的详细信息,请参阅每个语句的描述。本节描述了生成随机密码的共同特征。
默认情况下,生成的随机密码长度为 20 个字符。这个长度由generated_random_password_length
系统变量控制,范围从 5 到 255。
对于每个语句生成随机密码的账户,该语句将密码存储在mysql.user
系统表中,适当地为账户认证插件进行哈希处理。该语句还会在结果集的一行中返回明文密码,以便用户或应用程序执行该语句。结果集列名为user
,host
,generated password
和auth_factor
,表示标识mysql.user
系统表中受影响行的用户名和主机名值,明文生成的密码,以及显示密码值适用的认证因素。
mysql> CREATE USER 'u1'@'localhost' IDENTIFIED BY RANDOM PASSWORD, 'u2'@'%.example.com' IDENTIFIED BY RANDOM PASSWORD, 'u3'@'%.org' IDENTIFIED BY RANDOM PASSWORD; +------+---------------+----------------------+-------------+ | user | host | generated password | auth_factor | +------+---------------+----------------------+-------------+ | u1 | localhost | iOeqf>Mh9:;XD&qn(Hl} | 1 | | u2 | %.example.com | sXTSAEvw3St-R+_-C3Vb | 1 | | u3 | %.org | nEVe%Ctw/U/*Md)Exc7& | 1 | +------+---------------+----------------------+-------------+ mysql> ALTER USER 'u1'@'localhost' IDENTIFIED BY RANDOM PASSWORD, 'u2'@'%.example.com' IDENTIFIED BY RANDOM PASSWORD; +------+---------------+----------------------+-------------+ | user | host | generated password | auth_factor | +------+---------------+----------------------+-------------+ | u1 | localhost | Seiei:&cw}8]@3OA64vh | 1 | | u2 | %.example.com | j@&diTX80l8}(NiHXSae | 1 | +------+---------------+----------------------+-------------+ mysql> SET PASSWORD FOR 'u3'@'%.org' TO RANDOM; +------+-------+----------------------+-------------+ | user | host | generated password | auth_factor | +------+-------+----------------------+-------------+ | u3 | %.org | n&cz2xF;P3!U)+]Vw52H | 1 | +------+-------+----------------------+-------------+
一个CREATE USER
,ALTER USER
或SET PASSWORD
语句,为一个账户生成一个随机密码,被写入二进制日志作为一个带有IDENTIFIED WITH *
auth_plugin* AS '*
auth_string*
'子句的
CREATE USER或
ALTER USER语句,其中*
auth_plugin*是账户认证插件,
'auth_string
'
是账户哈希密码值。
如果安装了validate_password
组件,则其实施的策略对生成的密码没有影响。(密码验证的目的是帮助人类创建更好的密码。)
登录失败跟踪和临时账户锁定
从 MySQL 8.0.19 开始,管理员可以配置用户账户,使得连续登录失败次数过多会导致临时账户锁定。
在这种情况下,“登录失败”意味着客户端在连接尝试期间未提供正确密码。这不包括由于未知用户或网络问题等原因而无法连接的情况。对于具有双重密码的账户(参见双重密码支持),任一账户密码都算正确。
每个账户的所需登录失败次数和锁定时间可通过CREATE USER
和ALTER USER
语句的FAILED_LOGIN_ATTEMPTS
和PASSWORD_LOCK_TIME
选项进行配置。示例:
CREATE USER 'u1'@'localhost' IDENTIFIED BY '*password*' FAILED_LOGIN_ATTEMPTS 3 PASSWORD_LOCK_TIME 3; ALTER USER 'u2'@'localhost' FAILED_LOGIN_ATTEMPTS 4 PASSWORD_LOCK_TIME UNBOUNDED;
当连续登录失败次数过多时,客户端会收到如下错误消息:
ERROR 3957 (HY000): Access denied for user *user*. Account is blocked for *D* day(s) (*R* day(s) remaining) due to *N* consecutive failed logins.
使用选项如下:
FAILED_LOGIN_ATTEMPTS *
N*
此选项指示是否跟踪指定了不正确密码的账户登录尝试。数字*N
*指定了多少个连续的不正确密码会导致临时账户锁定。PASSWORD_LOCK_TIME {*
N* | UNBOUNDED}
此选项指示在太多连续登录尝试提供错误密码后锁定帐户的时间。该值是一个数字*N
*,用于指定帐户保持锁定状态的天数,或UNBOUNDED
以指定当帐户进入临时锁定状态时,该状态的持续时间是无限的,并且直到帐户被解锁为止。解锁发生的条件将在后面描述。
每个选项的允许值*N
*的范围为 0 到 32767。值为 0 会禁用该选项。
失败登录跟踪和临时帐户锁定具有以下特征:
- 要对帐户进行失败登录跟踪和临时锁定,其
FAILED_LOGIN_ATTEMPTS
和PASSWORD_LOCK_TIME
选项都必须为非零。 - 对于
CREATE USER
,如果未指定FAILED_LOGIN_ATTEMPTS
或PASSWORD_LOCK_TIME
,则其隐式默认值对于语句命名的所有帐户均为 0。这意味着禁用了失败登录跟踪和临时帐户锁定。(这些隐式默认值也适用于在引入失败登录跟踪之前创建的帐户。) - 对于
ALTER USER
,如果未指定FAILED_LOGIN_ATTEMPTS
或PASSWORD_LOCK_TIME
,则其值对于语句命名的所有帐户保持不变。 - 要发生临时帐户锁定,密码失败必须是连续的。在达到失败登录的
FAILED_LOGIN_ATTEMPTS
值之前发生的任何成功登录都会导致失败计数重置。例如,如果FAILED_LOGIN_ATTEMPTS
为 4,并且已发生三次连续密码失败,则需要再次失败一次才能开始锁定。但是,如果下次登录成功,则帐户的失败登录计数将被重置,因此再次需要四次连续失败才能锁定。 - 一旦临时锁定开始,即使使用正确密码也无法进行成功登录,直到锁定持续时间已过或帐户通过以下讨论中列出的帐户重置方法之一被解锁。
当服务器读取授权表时,它会初始化每个帐户的状态信息,包括是否启用了失败登录跟踪,帐户当前是否被临时锁定以及如果是的话锁定何时开始,以及如果帐户未被锁定,则在临时锁定发生之前的失败次数。
帐户的状态信息可以被重置,这意味着失败登录计数被重置,并且如果当前被临时锁定,则帐户被解锁。帐户重置可以是全局的,适用于所有帐户,也可以是每个帐户:
- 所有帐户的全局重置发生在以下任何条件下:
- 服务器重新启动。
- 执行
FLUSH PRIVILEGES
。(使用--skip-grant-tables
选项启动服务器会导致授予权限表不被读取,从而禁用了失败登录跟踪。在这种情况下,第一次执行FLUSH PRIVILEGES
会导致服务器读取授予权限表并启用失败登录跟踪,同时重置所有账户。)
- 对于任何以下条件,每个账户都会发生重置:
- 账户成功登录。
- 锁定持续时间过去。在这种情况下,失败登录计数将在下次登录尝试时重置。
- 对于账户执行设置
FAILED_LOGIN_ATTEMPTS
或PASSWORD_LOCK_TIME
(或两者)任何值(包括当前选项值)的ALTER USER
语句的执行,或对于账户执行ALTER USER ... UNLOCK
语句。
对于账户的其他ALTER USER
语句对其当前的失败登录计数或锁定状态没有影响。
失败登录跟踪与用于检查凭据的登录账户相关联。如果使用用户代理,跟踪将针对代理用户而不是被代理用户进行。也就是说,跟踪与USER()
指示的账户相关联,而不是与CURRENT_USER()
指示的账户相关联。有关代理用户和被代理用户之间区别的信息,请参阅第 8.2.19 节,“代理用户”。
8.2.16 服务器处理过期密码
原文:
dev.mysql.com/doc/refman/8.0/en/expired-password-handling.html
MySQL 提供了密码过期功能,使数据库管理员可以要求用户重置他们的密码。密码可以手动过期,也可以根据自动过期策略(参见第 8.2.15 节,“密码管理”)。
ALTER USER
语句可以启用账户密码过期。例如:
ALTER USER 'myuser'@'localhost' PASSWORD EXPIRE;
对于使用过期密码的账户的每个连接,服务器要么断开客户端连接,要么将客户端限制在“沙盒模式”中,其中服务器只允许客户端执行重置过期密码所需的操作。服务器采取的操作取决于客户端和服务器设置,稍后将讨论。
如果服务器断开客户端连接,它会返回一个ER_MUST_CHANGE_PASSWORD_LOGIN
错误:
$> mysql -u myuser -p Password: ****** ERROR 1862 (HY000): Your password has expired. To log in you must change it using a client that supports expired passwords.
如果服务器将客户端限制在沙盒模式中,客户端会话内允许执行以下操作:
- 客户端可以使用
ALTER USER
或SET PASSWORD
重置账户密码。完成后,服务器将为该会话以及使用该账户的后续连接恢复正常访问。
注意
尽管可以通过将过期密码重置为当前值来“重置”过期密码,但作为良好策略,最好选择一个不同的密码。数据库管理员可以通过建立适当的密码重用策略来强制执行不重复使用。参见密码重用策略。 - 在 MySQL 8.0.27 之前,客户端可以使用
SET
语句。从 MySQL 8.0.27 开始,不再允许此操作。
对于会话中不允许的任何操作,服务器会返回一个ER_MUST_CHANGE_PASSWORD
错误:
mysql> USE performance_schema; ERROR 1820 (HY000): You must reset your password using ALTER USER statement before executing this statement. mysql> SELECT 1; ERROR 1820 (HY000): You must reset your password using ALTER USER statement before executing this statement.
这通常发生在交互式调用mysql客户端时,因为默认情况下这种调用会被放置在沙盒模式中。要恢复正常功能,请选择一个新密码。
对于mysql客户端的非交互式调用(例如,在批处理模式下),如果密码过期,服务器通常会断开客户端的连接。为了允许非交互式的mysql调用保持连接,以便可以更改密码(使用沙盒模式中允许的语句),请在mysql命令中添加--connect-expired-password
选项。
如前所述,服务器是否断开过期密码客户端的连接或将其限制在沙盒模式取决于客户端和服务器设置的组合。以下讨论描述了相关设置及其交互方式。
注意
此讨论仅适用于密码过期的帐户。如果客户端使用未过期的密码连接,则服务器会正常处理客户端。
在客户端端,给定的客户端指示它是否可以处理过期密码的沙盒模式。对于使用 C 客户端库的客户端,有两种方法可以做到这一点:
- 在连接之前向
mysql_options()
传递MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS
标志:
bool arg = 1; mysql_options(mysql, MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS, &arg);
- 这是在mysql客户端中使用的技术,如果以交互方式调用或使用
--connect-expired-password
选项,则启用MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS
。 - 在连接时向
mysql_real_connect()
传递CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS
标志:
MYSQL mysql; mysql_init(&mysql); if (!mysql_real_connect(&mysql, host, user, password, db, port, unix_socket, CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS)) { ... handle error ... }
其他 MySQL 连接器有其自己的约定,用于指示准备处理沙盒模式。请参阅您感兴趣的连接器的文档。
在服务器端,如果客户端指示它可以处理过期密码,服务器会将其置于沙盒模式。
如果客户端没有指示它可以处理过期密码(或者使用无法指示的较旧版本的客户端库),则服务器的操作取决于disconnect_on_expired_password
系统变量的值:
- 如果
disconnect_on_expired_password
已启用(默认情况下),服务器将以ER_MUST_CHANGE_PASSWORD_LOGIN
错误断开客户端的连接。 - 如果
disconnect_on_expired_password
已禁用,则服务器将客户端置于沙盒模式。
8.2.17 可插拔认证
原文:
dev.mysql.com/doc/refman/8.0/en/pluggable-authentication.html
当客户端连接到 MySQL 服务器时,服务器使用客户端提供的用户名和客户端主机来从mysql.user
系统表中选择适当的账户行。然后服务器对客户端进行认证,从账户行确定适用于客户端的认证插件:
- 如果服务器找不到插件,则会发生错误并拒绝连接尝试。
- 否则,服务器会调用该插件来对用户进行认证,插件会向服务器返回一个状态,指示用户是否提供了正确的密码并被允许连接。
可插拔认证使得以下重要功能成为可能:
- 认证方法的选择。 可插拔的认证使得数据库管理员可以轻松选择和更改用于各个 MySQL 账户的认证方法。
- 外部认证。 可插拔认证使得客户端可以使用适合于在
mysql.user
系统表之外存储凭据的认证方法进行连接到 MySQL 服务器。例如,可以创建插件来使用外部认证方法,如 PAM、Windows 登录 ID、LDAP 或 Kerberos。 - 代理用户: 如果用户被允许连接,认证插件可以向服务器返回一个与连接用户名称不同的用户名,以指示连接用户是另一个用户(被代理用户)的代理。在连接持续期间,代理用户在访问控制方面被视为具有被代理用户的权限。实际上,一个用户冒充另一个用户。更多信息,请参见第 8.2.19 节,“代理用户”。
注意
如果使用--skip-grant-tables
选项启动服务器,则即使加载了认证插件,也不会使用认证插件,因为服务器不执行客户端认证并允许任何客户端连接。由于这是不安全的,如果使用--skip-grant-tables
选项启动服务器,则还会通过启用skip_networking
来禁用远程连接。
- 可用认证插件
- 默认认证插件
- 认证插件使用
- 认证插件客户端/服务器兼容性
- 认证插件连接器编写注意事项
- 可插拔认证的限制
可用的认证插件
MySQL 8.0 提供了这些认证插件:
- 一个执行本地认证的插件;即,在 MySQL 引入可插拔认证之前使用的基于密码哈希方法的认证。
mysql_native_password
插件实现了基于此本地密码哈希方法的认证。参见 Section 8.4.1.1,“本地可插拔认证”。
注意
截至 MySQL 8.0.34,mysql_native_password
认证插件已被弃用,并可能在将来的 MySQL 版本中被移除。 - 使用 SHA-256 密码哈希进行认证的插件。这比本地认证提供的加密更强大。参见 Section 8.4.1.2,“缓存 SHA-2 可插拔认证”,以及 Section 8.4.1.3,“SHA-256 可插拔认证”。
- 一个客户端插件,将密码以明文形式发送到服务器,不经过哈希或加密。此插件与需要以客户端用户提供的密码完全一致的服务器端插件一起使用。参见 Section 8.4.1.4,“客户端明文插件认证”。
- 一个使用 PAM(可插拔认证模块)执行外部认证的插件,使 MySQL 服务器能够使用 PAM 对 MySQL 用户进行认证。此插件还支持代理用户。参见 Section 8.4.1.5,“PAM 可插拔认证”。
- 一个在 Windows 上执行外部认证的插件,使 MySQL 服务器能够使用本地 Windows 服务对客户端连接进行认证。已登录到 Windows 的用户可以根据其环境中的信息从 MySQL 客户端程序连接到服务器,而无需指定额外的密码。此插件还支持代理用户。参见 Section 8.4.1.6,“Windows 可插拔认证”。
- 使用 LDAP(轻量级目录访问协议)进行认证的插件,通过访问诸如 X.500 之类的目录服务来认证 MySQL 用户。这些插件还支持代理用户。参见第 8.4.1.7 节,“LDAP 可插拔认证”。
- 一个使用 Kerberos 进行认证的插件,用于认证与 Kerberos 主体对应的 MySQL 用户。参见第 8.4.1.8 节,“Kerberos 可插拔认证”。
- 一个阻止所有使用它的帐户的客户端连接的插件。此插件的用例包括永远不允许直接登录但仅通过代理帐户访问的代理帐户和必须能够以提升的权限执行存储程序和视图而不向普通用户公开这些权限的帐户。参见第 8.4.1.9 节,“无登录可插拔认证”。
- 一个插件,用于验证通过 Unix 套接字文件从本地主机连接的客户端。参见第 8.4.1.10 节,“套接字对等凭证可插拔认证”。
- 一个通过 FIDO 认证将用户认证到 MySQL 服务器的插件。参见第 8.4.1.11 节,“FIDO 可插拔认证”。
注意
截至 MySQL 8.0.35 版本,authentication_fido
和authentication_fido_client
认证插件已被弃用,并可能在将来的 MySQL 版本中被移除。 - 一个测试插件,检查帐户凭据并将成功或失败记录到服务器错误日志中。此插件旨在用于测试和开发目的,并作为编写认证插件的示例。参见第 8.4.1.12 节,“测试可插拔认证”。
注意
有关当前对可插拔认证使用的限制的信息,包括哪些连接器支持哪些插件,请参阅可插拔认证限制。
第三方连接器开发人员应阅读该部分,以确定连接器可以利用可插拔认证功能的程度,以及成为更加符合规范的步骤。
如果您有兴趣编写自己的认证插件,请参阅编写认证插件。
MySQL8 中文参考(二十五)(4)https://developer.aliyun.com/article/1566167