第6章安全性

目录

6.1一般安全问题
6.1.1安全指南
6.1.2保持密码安全
6.1.3使MySQL安全抵御攻击者
6.1.4与安全相关的mysqld选项和变量
6.1.5如何以普通用户身份运行MySQL
6.1.6 LOAD DATA LOCAL的安全问题
6.1.7客户端编程安全指南
6.2访问控制和帐户管理
6.2.1帐户用户名和密码
6.2.2 MySQL提供的权限
6.2.3拨款表
6.2.4指定帐户名称
6.2.5指定角色名称
6.2.6访问控制,阶段1:连接验证
6.2.7访问控制,第2阶段:请求验证
6.2.8添加帐户,分配权限和删除帐户
6.2.9预留账户
6.2.10使用角色
6.2.11帐户类别
6.2.12使用部分撤销权限的权限限制
6.2.13权限更改生效时
6.2.14分配帐户密码
6.2.15密码管理
6.2.16过期密码的服务器处理
6.2.17可插拔认证
6.2.18代理用户
6.2.19账户锁定
6.2.20设置帐户资源限制
6.2.21连接MySQL的问题疑难解答
6.2.22基于SQL的帐户活动审计
6.3使用加密连接
6.3.1配置MySQL使用加密连接
6.3.2加密连接的命令选项
6.3.3创建SSL和RSA证书和密钥
6.3.4 SSL库相关功能
6.3.5构建支持加密连接的MySQL
6.3.6加密连接协议和密码
6.3.7使用SSH从Windows远程连接到MySQL
6.4安全组件和插件
6.4.1认证插件
6.4.2连接控制插件
6.4.3密码验证组件
6.4.4 MySQL密钥环
6.4.5 MySQL企业审计
6.4.6审计消息组件
6.4.7 MySQL企业防火墙
6.4.8 MySQL企业数据屏蔽和去标识
6.5 FIPS支持

在考虑MySQL安装中的安全性时,您应该考虑各种可能的主题以及它们如何影响MySQL服务器和相关应用程序的安全性:

6.1一般安全问题

本节介绍了要注意的一般安全问题,以及如何使MySQL安装更安全,防止攻击或滥用。 有关MySQL用于设置用户帐户和检查数据库访问权限的访问控制系统的信息,请参见 第2.10节“安装后设置和测试”

有关经常被问及有关MySQL服务器安全性问题的一些问题的答案,请参见 第A.9节“MySQL 8.0 FAQ:安全性”

6.1.1安全指南

在连接到Internet的计算机上使用MySQL的任何人都应该阅读本节以避免最常见的安全错误。

在讨论安全性时,有必要考虑完全保护整个服务器主机(不仅仅是MySQL服务器)免受所有类型的适用攻击:窃听,更改,回放和拒绝服务。 我们没有涵盖可用性和容错的所有方面。

MySQL使用基于访问控制列表(ACL)的安全性来处理用户可以尝试执行的所有连接,查询和其他操作。 MySQL客户端和服务器之间也支持SSL加密连接。 这里讨论的许多概念都不是特定于MySQL的; 相同的一般想法适用于几乎所有应用程序。

运行MySQL时,请遵循以下准则:

  • 不要让任何人(MySQL root 帐户 除外 )访问 系统数据库中 user mysql 这很关键。

  • 了解MySQL访问权限系统的工作原理(请参见 第6.2节“访问控制和帐户管理” )。 使用 GRANT REVOKE 语句来控制对MySQL的访问。 不要授予超出必要的权限。 永远不会授予所有主机权限。

    清单:

    • 试试 mysql -u root 如果您能够在不被要求输入密码的情况下成功连接到服务器,则任何人都可以以 root 具有完全权限 的MySQL 用户 身份连接到MySQL服务器 查看MySQL安装说明,特别注意有关设置 root 密码 的信息 请参见 第2.10.4节“保护初始MySQL帐户”

    • 使用该 SHOW GRANTS 语句检查哪些帐户可以访问哪些帐户。 然后使用该 REVOKE 语句删除那些不必要的权限。

  • 不要在数据库中存储明文密码。 如果您的计算机遭到入侵,入侵者可以获取完整的密码列表并使用它们。 相反,使用 SHA2() 或一些其他单向散列函数并存储散列值。

    要防止使用彩虹表恢复密码,请不要在普通密码上使用这些功能; 相反,选择一些字符串用作salt,并使用hash(hash(密码)+ salt)值。

  • 不要从词典中选择密码。 存在破坏密码的特殊程序。 甚至像 xfish98 这样的密码 都非常糟糕。 更好的是 duag98 ,它包含相同的单词 fish ”, 但在标准的QWERTY键盘上键入了左键。 另一种方法是使用从句子中每个单词的第一个字符中获取的密码(例如, 四分和七年前 导致密码为 Fsasya )。 密码易于记忆和输入,但对于不知道该句子的人来说很难猜到。 在这种情况下,你可以另外用数字代替数字来获得短语 4分和7年前 ,产生密码 4sa7ya ,这更难以猜测。

  • 投资防火墙。 这可以保护您免受任何软件中至少50%的漏洞攻击。 将MySQL放在防火墙后面或非军事区(DMZ)。

    清单:

    • 尝试使用诸如此类的工具从Internet扫描您的端口 nmap MySQL默认使用端口3306。 不应从不受信任的主机访问此端口。 作为检查MySQL端口是否打开的简单方法,请从某个远程计算机尝试以下命令,其中 server_host 运行MySQL服务器的主机的主机名或IP地址:

      外壳> telnet server_host 3306
      

      如果 telnet 挂起或连接被拒绝,则端口被阻塞,这就是你想要的。 如果你得到一个连接和一些垃圾字符,端口是打开的,应该在防火墙或路由器上关闭,除非你真的有充分的理由保持它打开。

  • 访问MySQL的应用程序不应信任用户输入的任何数据,应使用适当的防御性编程技术编写。 请参见 第6.1.7节“客户端编程安全指南”

  • 不要通过Internet传输普通(未加密)数据。 每个有时间和能力拦截并将其用于自己目的的人都可以访问此信息。 而是使用加密协议,如SSL或SSH。 MySQL支持内部SSL连接。 另一种技术是使用SSH端口转发为通信创建加密(和压缩)隧道。

  • 学习使用 tcpdump 字符串 实用程序。 在大多数情况下,您可以通过发出如下命令来检查MySQL数据流是否未加密:

    外壳> tcpdump -l -i eth0 -w - src or dst port 3306 | strings
    

    这适用于Linux,并且应该在其他系统下进行小的修改。

    警告

    如果您没有看到明文数据,这并不总是意味着信息实际上是加密的。 如果您需要高安全性,请咨询安全专家。

6.1.2保持密码安全

密码出现在MySQL中的几个上下文中。 以下各节提供了一些指导原则,使最终用户和管理员能够确保这些密码的安全并避免泄露这些密码。 此外,该 validate_password 插件可用于对可接受的密码实施策略。 请参见 第6.4.3节“密码验证组件”

6.1.2.1密码安全最终用户指南

MySQL用户应使用以下准则来保证密码安全。

当您运行客户端程序以连接到MySQL服务器时,不建议以将其公开给其他用户发现的方式指定您的密码。 此处列出了运行客户端程序时可用于指定密码的方法,以及每种方法的风险评估。 简而言之,最安全的方法是让客户端程序提示输入密码或在受适当保护的选项文件中指定密码。

  • 使用 mysql_config_editor 实用程序,该实用程序使您可以将身份验证凭据存储在名为的加密登录路径文件中 .mylogin.cnf MySQL客户端程序稍后可以读取该文件以获取用于连接到MySQL服务器的身份验证凭据。 请参见 第4.6.7节“ mysql_config_editor - MySQL配置实用程序”

  • 在命令行上 使用 选项。 例如: -pyour_pass --password=your_pass

    外壳> mysql -u francis -pfrank db_name
    
    警告

    这很方便 但不安全 在某些系统上,您的密码对系统状态程序(例如 ps) 可见 ,其他用户可以调用它来显示命令行。 MySQL客户端通常在初始化序列期间用零覆盖命令行密码参数。 但是,仍然存在一个短暂的间隔,在该间隔期间值是可见的。 此外,在某些系统上,此覆盖策略无效,并且 ps 仍然可以看到密码 (SystemV Unix系统和其他人可能遇到这个问题。)

    如果您的操作环境设置为在终端窗口的标题栏中显示当前命令,则只要命令正在运行,密码仍然可见,即使该命令已在窗口内容区域中滚动出视图。

  • 在命令行上 使用 -p --password 选项,但未指定密码值。 在这种情况下,客户端程序以交互方式请求密码:

    外壳> mysql -u francis -p db_name
    输入密码: ********
    

    * 字符显示在您输入密码。 输入密码时不会显示密码。

    以这种方式输入密码比在命令行中指定密码更安全,因为其他用户看不到密码。 但是,这种输入密码的方法仅适用于以交互方式运行的程序。 如果要从非交互式运行的脚本调用客户端,则无法从键盘输入密码。 在某些系统上,您甚至可能会发现脚本的第一行被读取并被解释(错误地)作为您的密码。

  • 将密码存储在选项文件中。 例如,在Unix上,您可以 在主目录 [client] 中的 .my.cnf 文件 部分 列出您的密码

    [客户]
    密码= your_pass的
    

    为了确保密码安全,除了您自己之外,任何人都无法访问该文件。 要确保这一点,请将文件访问模式设置为 400 600 例如:

    外壳> chmod 600 .my.cnf
    

    要从命令行命名包含密码的特定选项文件,请使用 选项,其中 是文件的完整路径名。 例如: --defaults-file=file_name file_name

    外壳> mysql --defaults-file=/home/francis/mysql-opts
    

    第4.2.2.2节“使用选项文件” 更详细地讨论了选项文件。

  • 将密码存储在 MYSQL_PWD 环境变量中。 请参见 第4.9节“MySQL程序环境变量”

    这种指定MySQL密码的方法必须被认为是 非常不安全的 ,不应该使用。 某些版本的 ps 包含显示正在运行的进程环境的选项。 在某些系统上,如果设置 MYSQL_PWD ,则密码将暴露给运行 ps的 任何其他用户 即使在没有这种版本的 ps的系统上 ,假设用户没有其他方法可以检查过程环境也是不明智的。

在Unix上, mysql 客户端将执行语句的记录写入历史文件(参见 第4.5.1.3节“mysql客户端日志记录” )。 默认情况下,此文件已命名 .mysql_history 并在主目录中创建。 密码可以在诸如 CREATE USER 和的 SQL语句中以纯文本形式写入 ALTER USER ,因此如果使用这些语句,它们将记录在历史文件中。 要保证此文件的安全,请使用限制访问模式,方法与前面对 .my.cnf 文件 所述的方式相同

如果命令解释程序配置为维护历史记录,则保存命令的任何文件都将包含在命令行中输入的MySQL密码。 例如, bash 使用 ~/.bash_history 任何此类文件都应具有限制性访问模式。

6.1.2.2密码安全管理员指南

数据库管理员应使用以下准则来确保密码安全。

MySQL在 mysql.user 系统表中 存储用户帐户的密码 永远不应该向任何非管理帐户授予对此表的访问权限。

帐户密码可以过期,以便用户必须重置它们。 请参见 第6.2.15节“密码管理” 第6.2.16节“过期密码的服务器处理”

validate_password 插件可用于对可接受的密码强制实施策略。 请参见 第6.4.3节“密码验证组件”

有权修改插件目录( plugin_dir 系统变量 的值 )或 my.cnf 指定插件目录位置 文件的用户可以替换插件并修改插件提供的功能,包括身份验证插件。

应该保护可能写入密码的日志文件等文件。 请参见 第6.1.2.3节“密码和日志记录”

6.1.2.3密码和日志记录

口令可以写在SQL语句,如纯文本 CREATE USER GRANT SET PASSWORD 如果MySQL服务器将此类语句记录为已写入,则访问日志的任何人都可以看到其中的密码。

语句记录避免将密码写为以下语句的明文:

创建用户...通过...识别
ALTER USER ...由......识别
设置密码 ...
从头开始......密码= ......
创建服务器...选项(...密码...)
ALTER SERVER ...选项(...密码...)

这些语句中的密码被重写为不会出现在写入常规查询日志,慢查询日志和二进制日志的语句文本中。 重写不适用于其他声明。 具体而言, INSERT UPDATE 对语句 mysql.user 引用文字密码系统表中记录为是,那么你应该避免这样的语句。 (无论如何,不​​鼓励直接修改授权表。)

对于常规查询日志,可以通过使用该 --log-raw 选项 启动服务器来抑制密码重写 出于安全原因,建议不要将此选项用于生产用途。 出于诊断目的,查看服务器收到的语句的确切文本可能很有用。

默认情况下,审计日志插件生成的审计日志文件的内容未加密,可能包含敏感信息,例如SQL语句的文本。 出于安全原因,审计日志文件应写入只能由MySQL服务器访问的目录以及具有查看日志的合法理由的用户。 请参见 第6.4.5.3节“MySQL Enterprise Audit安全注意事项”

如果安装了查询重写插件,则可以重写服务器收到的语句(请参阅 查询重写插件 )。 在这种情况下,该 --log-raw 选项会影响语句记录,如下所示:

  • 如果没有 --log-raw ,服务器会记录查询重写插件返回的语句。 这可能与收到的声明不同。

  • 使用时 --log-raw ,服务器将原始语句记录为已接收。

密码重写的含义是无法解析的语句(例如,由于语法错误)不会写入通用查询日志,因为无法知道它们是无密码的。 需要记录所有语句(包括有错误的语句)的用例应使用该 --log-raw 选项,请记住这也会绕过密码重写。

只有在需要纯文本密码时才会进行密码重写。 对于具有期望密码哈希值的语法的语句,不会发生重写。 如果为此类语法错误地提供了纯文本密码,则会将密码记录为给定,而不进行重写。

要保护日志文件免受不必要的暴露,请将它们放在限制访问服务器和数据库管理员的目录中。 如果服务器记录到 mysql 数据库中的表,则仅将这些表的访问权限授予数据库管理员。

复制从属服务器将复制主服务器的密码存储在主信息存储库中,默认情况下,该信息存储库是 mysql 名为数据库 的表 slave_master_info 现在不推荐在主数据存储库的数据目录中使用文件,但仍然可以使用(请参见 第17.2.4节“复制中继和状态日志” )。 确保只能由数据库管理员访问主信息存储库。 将密码存储在主信息存储库中的替代方法是使用该 START SLAVE 语句指定用于连接到主服务器的凭据。

使用受限访问模式来保护包含日志表或包含密码的日志文件的数据库备份。

6.1.3使MySQL安全抵御攻击者

连接到MySQL服务器时,应使用密码。 密码不会通过连接以明文形式传输。

所有其他信息都以文本形式传输,任何能够观看连接的人都可以阅读。 如果客户端和服务器之间的连接通过不受信任的网络,并且您担心这一点,则可以使用压缩协议使流量更难以解密。 您还可以使用MySQL的内部SSL支持来使连接更加安全。 请参见 第6.3节“使用加密连接” 或者,使用SSH在MySQL服务器和MySQL客户端之间获得加密的TCP / IP连接。 您可以在 http://www.openssh.org/ 找到一个开源SSH客户端 ,并 在那里 比较开源和商业SSH客户端 http://en.wikipedia.org/wiki/Comparison_of_SSH_clients

要使MySQL系统安全,您应该强烈考虑以下建议:

  • 要求所有MySQL帐户都有密码。 客户端程序不一定知道运行它的人的身份。 客户端/服务器应用程序通常可以为客户端程序指定任何用户名。 例如,任何人都可以使用 MySQL的 程序为任何其他人简单地调用它作为连接 ,如果 没有密码。 如果所有帐户都有密码,则使用其他用户的帐户进行连接会变得更加困难。 mysql -u other_user db_name other_user

    有关设置密码的方法的讨论,请参见 第6.2.14节“分配帐户密码”

  • 确保在数据库目录中具有读或写权限的唯一Unix用户帐户是用于运行 mysqld 的帐户

  • 永远不要以Unix root 用户 身份运行MySQL服务器 这是非常危险的,因为具有该 FILE 权限的 任何用户 都能够使服务器创建文件 root (例如, ~root/.bashrc )。 为了防止这种情况, 除非使用该 选项 明确指定 否则 mysqld 拒绝运行 root --user=root

    mysqld 可以(而且应该)作为普通的非特权用户运行。 您可以创建一个单独的Unix帐户,以 mysql 使一切更加安全。 仅将此帐户用于管理MySQL。 以不同的Unix用户身份 启动 mysqld ,请添加一个 user 选项, [mysqld] my.cnf 选项指定用于指定服务器选项 选项文件 组中的 用户名 例如:

    的[mysqld]
    用户= MySQL的
    

    这会导致服务器以指定用户身份启动,无论是手动启动还是使用 mysqld_safe mysql.server 启动它 有关更多详细信息,请参见 第6.1.5节“如何以普通用户身份运行MySQL”

    mysqld 作为Unix用户 运行 root 并不意味着您需要更改 表中 root 用户名 user MySQL帐户的用户名与Unix帐户的用户名无关

  • 不要将 FILE 权限 授予 非管理用户。 具有此权限的任何用户都可以使用 mysqld 守护程序 的权限在文件系统中的任何位置编写文件 这包括服务器的数据目录,其中包含实现权限表的文件。 为了使 FILE -privilege操作更安全一些,生成的文件 SELECT ... INTO OUTFILE 不会覆盖现有文件,并且每个人都可以写入。

    FILE 特权还可用于读取服务器运行的Unix用户可以访问或访问的任何文件。 使用此权限,您可以将任何文件读入数据库表。 这可能会被滥用,例如,通过使用 LOAD DATA 加载 /etc/passwd 到表中,然后可以显示 SELECT

    要限制可以读取和写入文件的位置,请将 secure_file_priv 系统设置为特定目录。 请参见 第5.1.8节“服务器系统变量”

  • 加密二进制日志文件和中继日志文件。 加密有助于保护这些文件及其中包含的潜在敏感数据免受外部攻击者的滥用,以及存储它们的操作系统用户的未授权查看。 通过将 binlog_encryption 系统变量 设置为,可以在MySQL服务器上启用加密 ON 有关更多信息,请参见 第17.3.10节“加密二进制日志文件和中继日志文件”

  • 不要 向非管理用户 授予 PROCESS SUPER 特权。 mysqladmin processlist 的输出 SHOW PROCESSLIST 显示当前正在执行的任何语句的文本,因此任何被允许查看服务器进程列表的用户都可以看到其他用户发出的语句。

    mysqld 为拥有 CONNECTION_ADMIN SUPER 特权的 用户保留额外的连接 ,这样 root 即使所有正常连接都在使用 ,MySQL 用户也可以登录并检查服务器活动。

    SUPER 权限可用于终止客户端连接,通过更改系统变量的值来更改服务器操作,以及控制复制服务器。

  • 不允许对表使用符号链接。 (此功能可通过禁用 --skip-symbolic-links 选项。)如果您运行,这一点尤其重要 的mysqld root ,因为有写访问到服务器的数据目录,然后任何人都可以在系统中删除任何文件! 请参见 第8.12.2.2节“在Unix上使用MyISAM表的符号链接”

  • 应使用 第24.6节“存储对象访问控制”中 讨论的安全准则编写存储的程序和视图

  • 如果您不信任您的DNS,则应在授权表中使用IP地址而不是主机名。 在任何情况下,您都应该非常小心地使用包含通配符的主机名值创建授权表条目。

  • 如果要限制允许连接到单个帐户的连接数,可以通过 max_user_connections mysqld中 设置 变量来实现 CREATE USER ALTER USER 语句也支持资源控制选项来限制允许帐户服务器使用的程度。 请参见 第13.7.1.3节“创建用户语法” 第13.7.1.1节“更改用户语法”

  • 如果服务器可以写入插件目录,则用户可以使用可执行代码将可执行代码写入目录中的文件 SELECT ... INTO DUMPFILE 这可以通过 plugin_dir 对服务器 进行 只读或通过设置 --secure-file-priv SELECT 可以安全地 进行 写入 的目录 来防止

6.1.4与安全相关的mysqld选项和变量

下表显示 了影响安全性的 mysqld 选项和系统变量。 有关其中每个的说明,请参见 第5.1.7节“服务器命令选项” 第5.1.8节“服务器系统变量”

表6.1安全选项和变量摘要

名称 CMD线 选项文件 系统变量 状态变量 Var范围 动态
允许可疑-UDF的
automatic_sp_privileges 全球
chroot环境
DES密钥文件
local_infile 全球
old_passwords
安全用户创建
安全-AUTH 全球
- 变量 secure_auth 全球
安全文件私法 全球 没有
- 变量 secure_file_priv 全球 没有
跳过赠款表
跳过名称解析 全球 没有
- 变量 skip_name_resolve 全球 没有
跳过网络 全球 没有
- 变量 skip_networking 全球 没有
跳过出现数据库 全球 没有
- 变量 skip_show_database 全球 没有

6.1.5如何以普通用户身份运行MySQL

在Windows上,您可以使用普通用户帐户将服务器作为Windows服务运行。

在Linux上,对于使用MySQL存储库或RPM软件包执行的安装,MySQL服务器 mysqld 应由本地 mysql 操作系统用户启动。 从另一个操作系统用户开始,作为MySQL存储库的一部分包含的init脚本不支持该用户。

在Unix(或用于使用 tar.gz 软件包 执行的安装的Linux )上,MySQL服务器 mysqld 可以由任何用户启动和运行。 但是, root 出于安全原因 ,应避免以Unix 用户 身份运行服务器 要将 mysqld 更改 为以普通的非特权Unix用户身份运行 user_name ,您必须执行以下操作:

  1. 如果服务器正在运行,请停止服务器(使用 mysqladmin shutdown )。

  2. 更改数据库目录和文件,以便 user_name 具有读取和写入文件的权限(您可能需要以Unix root 用户 身份执行此 操作):

    外壳> chown -R user_name /path/to/mysql/datadir
    

    如果不这样做,服务器在运行时将无法访问数据库或表 user_name

    如果MySQL数据目录中的目录或文件是符号链接,则 chown -R 可能不会跟随符号链接。 如果没有,您还需要关注这些链接并更改它们指向的目录和文件。

  3. 以用户身份启动服务器 user_name 另一种方法是启动 mysqld 作为Unix root 用户并使用该 选项。 mysqld 启动,然后 在接受任何连接之前 切换为以Unix用户身份运行 --user=user_name user_name

  4. 要在系统启动时自动以给定用户身份启动服务器,请通过向 选项文件 服务器数据目录 中的 选项文件 添加 user 选项来 指定用户名 例如: [mysqld] /etc/my.cnf my.cnf

    的[mysqld]
    用户=user_name
    

如果你的Unix机器本身不安全,你应该 root 在授权表中 为MySQL 帐户 分配密码 否则,在该计算机上具有登录帐户的任何用户都可以 使用 选项 运行 mysql 客户端 --user=root 并执行任何操作。 (在任何情况下,最好将密码分配给MySQL帐户,但在服务器主机上存在其他登录帐户时尤其如此。)请参见 第2.10.4节“保护初始MySQL帐户”

6.1.6 LOAD DATA LOCAL的安全问题

LOAD DATA 语句可以加载位于服务器主机上的文件,或者,如果 LOCAL 指定 关键字 ,则加载 在客户端主机上。

有与两个潜在的安全问题 LOCAL 的版本 LOAD DATA

  • 从客户端主机到服务器主机的文件传输由MySQL服务器启动。 理论上,可以构建修补的服务器,该服务器将告诉客户端程序传输服务器选择的文件而不是 LOAD DATA 语句中 客户端指定的文件 这样的服务器可以访问客户端用户具有读访问权限的客户端主机上的任何文件。 (补丁服务器实际上可以回复任何语句的文件传输请求,而不仅仅是 LOAD DATA LOCAL ,因此更基本的问题是客户端不应该连接到不受信任的服务器。)

  • 在客户端从Web服务器连接的Web环境中,用户可以使用 LOAD DATA LOCAL 读取Web服务器进程具有读访问权限的任何文件(假设用户可以对SQL服务器运行任何语句)。 在此环境中,与MySQL服务器相关的客户端实际上是Web服务器,而不是由连接到Web服务器的用户运行的远程程序。

为避免出现 LOAD DATA 问题,客户应避免使用 LOCAL 为避免连接到不受信任的服务器,客户端可以通过使用 --ssl-mode=VERIFY_IDENTITY 选项和相应的CA证书 进行连接来建立安全连接并验证服务器标识

要使管理员和应用程序能够管理本地数据加载功能, LOCAL 配置的工作方式如下:

  • 在服务器端:

    • 所述 local_infile 系统变量控制服务器端 LOCAL 的能力。 根据 local_infile 设置,服务器拒绝或允许客户端 LOCAL 启用的客户端 加载本地数据 默认情况下, local_infile 已禁用。

    • 要显式地使服务器拒绝或允许 LOAD DATA LOCAL 语句(无论在构建时或运行时如何配置客户端程序和库) ,分别启用 具有 禁用或启用的 mysqld local_infile local_infile 也可以在运行时设置。

  • 在客户端:

    • CMake的 选项控制编译默认 的MySQL客户端库的能力。 因此,没有明确安排的客户端会 根据 MySQL构建时指定 设置 禁用或启用功能 ENABLED_LOCAL_INFILE LOCAL LOCAL ENABLED_LOCAL_INFILE

      默认情况下,MySQL二进制发行版中的客户端库是使用 ENABLED_LOCAL_INFILE disabled 编译的 如果从源代码编译MySQL,则 ENABLED_LOCAL_INFILE 根据未进行显式排列的客户端是否应 LOCAL 分别禁用或启用功能,将其配置为禁用或启用。

    • 使用C API的客户端程序可以通过调用 mysql_options() 禁用或启用该 MYSQL_OPT_LOCAL_INFILE 选项 显式控制加载数据加载 请参见 第28.7.7.50节“mysql_options()”

    • 对于 mysql 客户端,默认情况下禁用本地数据加载。 要显式禁用或启用它,请使用 --local-infile=0 --local-infile[=1] 选项。

    • 对于 mysqlimport 客户端,默认情况下禁用本地数据加载。 要显式禁用或启用它,请使用 --local=0 --local[=1] 选项。

    • 如果您 LOAD DATA LOCAL 在Perl脚本或 [client] 从选项文件 中读取 组的 其他程序中使用,则可以向该 组添加 local-infile 选项设置。 要防止不理解此选项的程序出现问题,请使用 loose- 前缀 指定它

      [客户]
      松和本地的infile = 0
      

      要么:

      [客户]
      松和本地的infile = 1
      
    • 在所有情况下, LOCAL 客户端 成功使用 加载操作也需要服务器允许它。

如果 LOCAL 禁用功能,则在服务器或客户端上,尝试发出 LOAD DATA LOCAL 语句 的客户端会 收到以下错误消息:

错误1148:此MySQL版本不允许使用used命令

6.1.7客户端编程安全指南

访问MySQL的应用程序不应该信任用户输入的任何数据,用户可以通过在Web表单,URL或您构建的任何应用程序中输入特殊或转义的字符序列来欺骗您的代码。 如果用户输入类似内容,请确保您的应用程序保持安全 ; DROP DATABASE mysql; 这是一个极端的例子,但是如果你没有为它们做准备,黑客可能会使用类似的技术来发生大量的安全漏洞和数据丢失。

常见的错误是仅保护字符串数据值。 记得也要检查数字数据。 如果应用程序生成查询(例如, SELECT * FROM table WHERE ID=234 当用户输入值时) 234 ,则用户可以输入该值 234 OR 1=1 以使应用程序生成查询 SELECT * FROM table WHERE ID=234 OR 1=1 结果,服务器检索表中的每一行。 这会暴露每一行并导致过多的服务器负载。 防止此类攻击的最简单方法是在数字常量周围使用单引号: SELECT * FROM table WHERE ID='234' 如果用户输入额外信息,则它们都成为字符串的一部分。 在数字上下文中,MySQL会自动将此字符串转换为数字,并从中删除任何尾随的非数字字符。

有时人们会认为,如果数据库只包含公开可用的数据,则无需受到保护。 这是不正确的。 即使允许在数据库中显示任何行,您仍应该防止拒绝服务攻击(例如,那些基于前一段中导致服务器浪费资源的技术的攻击)。 否则,您的服务器将无法响应合法用户。

清单:

  • 启用严格SQL模式以告知服务器对其接受的数据值有更多限制。 请参见 第5.1.11节“服务器SQL模式”

  • 尝试 在所有Web表单中 输入单引号和双引号( ' " )。 如果您遇到任何类型的MySQL错误,请立即调查此问题。

  • 尝试通过向它们添加 %22 " ), %23 # )和 %27 ' )来 修改动态URL

  • 尝试使用前面示例中显示的字符将动态URL中的数据类型从数字类型修改为字符类型。 您的应用程序应该可以安全抵御这些和类似的攻击

  • 尝试输入字符,空格和特殊符号,而不是数字字段中的数字。 您的应用程序应该在将它们传递给MySQL之前删除它们,否则会生成错误。 将未经检查的值传递给MySQL非常危险!

  • 在将数据传递给MySQL之前检查数据的大小。

  • 使用与用于管理目的的用户名不同的用户名将应用程序连接到数据库。 不要为您的应用程序提供他们不需要的任何访问权限。

许多应用程序编程接口提供了一种在数据值中转义特殊字符的方法。 正确使用,这可以防止应用程序用户输入导致应用程序生成具有与您想要的效果不同的语句的值:

  • MySQL C API:使用 mysql_real_escape_string_quote() API调用。

  • MySQL ++: 对查询流 使用 escape quote 修饰符。

  • PHP:使用 mysqli pdo_mysql 扩展名,而不是旧的 ext/mysql 扩展名。 首选API支持改进的MySQL身份验证协议和密码,以及带有占位符的预处理语句。 另请参阅 选择API

    如果 ext/mysql 必须使用 较旧的 扩展名,那么为了转义使用该 mysql_real_escape_string_quote() 函数而不是 mysql_escape_string() addslashes() 因为只有 mysql_real_escape_string_quote() 字符集感知; 使用(无效)多字节字符集时, 可以 绕过 其他功能

  • Perl DBI:使用占位符或 quote() 方法。

  • Ruby DBI:使用占位符或 quote() 方法。

  • Java JDBC:使用 PreparedStatement 对象和占位符。

其他编程接口可能具有类似的功能。

6.2访问控制和帐户管理

MySQL允许创建允许客户端用户连接到服务器并访问服务器管理的数据的帐户。 MySQL权限系统的主要功能是验证谁从给定主机连接用户,并与特权用户数据库如联想 SELECT INSERT UPDATE ,和 DELETE 其他功能包括为管理操作授予权限的功能。

要控制哪些用户可以连接,可以为每个帐户分配身份验证凭据,例如密码。 用户界面MySQL账户由SQL语句如 CREATE USER GRANT REVOKE 请参见 第13.7.1节“帐户管理语句”

MySQL权限系统确保所有用户只能执行允许的操作。 作为用户,当您连接到MySQL服务器时,您的身份由 您连接的主机 您指定的用户名决定 在连接后发出请求时,系统会根据您的身份和 您要执行的操作 授予权限

MySQL会同时识别您的主机名和用户名,因为没有理由认为给定的用户名属于所有主机上的同一个人。 例如, joe 连接 的用户 office.example.com 不必是与 joe 连接 的用户相同的人 home.example.com MySQL的,使您能够区分上碰巧有相同的名称不同的主机用户来处理它:你可以通过授予一组的连接权限 joe office.example.com ,并通过连接一组不同的权限 joe home.example.com 要查看给定帐户具有的权限,请使用该 SHOW GRANTS 语句。 例如:

为'joe'@'office.example.com'显示资助';
为'joe'@'home.example.com'显示资助';

在内部,服务器将特权信息存储在 mysql 系统数据库 的授权表中 MySQL服务器在启动时将这些表的内容读入内存,并根据授权表的内存中副本建立访问控制决策。

当您运行连接到服务器的客户端程序时,MySQL访问控制涉及两个阶段:

阶段1: 服务器根据您的身份接受或拒绝连接,以及您是否可以通过提供正确的密码来验证您的身份。

阶段2: 假设您可以连接,服务器会检查您发出的每个语句,以确定您是否具有足够的权限来执行它。 例如,如果尝试从数据库中的表中选择行或从数据库中删除表,则服务器会验证您是否具有 SELECT 该表的 DROP 权限 数据库 权限。

有关每个阶段所发生情况的更详细说明,请参见 第6.2.6节“访问控制,第1阶段:连接验证” 第6.2.7节“访问控制,第2阶段:请求验证” 有关诊断与权限相关的问题的帮助,请参见 第6.2.21节“连接到MySQL的问题疑难解答”

如果在连接时更改了您的权限(由您自己或其他人),则这些更改不一定会立即生效,以用于您发出的下一个语句。 有关服务器重新加载授权表的条件的详细信息,请参见 第6.2.13节“特权更改生效时”

有些事情你不能用MySQL特权系统做:

  • 您无法明确指定应拒绝给定用户访问。 也就是说,您无法明确匹配用户,然后拒绝连接。

  • 您不能指定用户具有在数据库中创建或删除表的权限,但不能指定创建或删除数据库本身的权限。

  • 密码全局适用于帐户。 您无法将密码与特定对象(如数据库,表或例程)相关联。

6.2.1帐户用户名和密码

MySQL将帐户存储在 系统数据库 user 表中 mysql 帐户是根据用户名和用户可以从中连接到服务器的客户端主机定义的。 有关 user 表中 帐户表示的信息 ,请参见 第6.2.3节“授予表”

帐户还可能具有身份验证凭据,例如密码。 凭据由帐户身份验证插件处理。 MySQL支持多种身份验证插件。 其中一些使用内置身份验证方法,而其他人则使用外部身份验证方法启用身份验证。 请参见 第6.2.17节“可插入验证”

MySQL和您的操作系统使用用户名和密码的方式有几点不同:

  • MySQL用于身份验证的用户名与Windows或Unix使用的用户名(登录名)无关。 在Unix上,大多数MySQL客户端默认尝试使用当前的Unix用户名作为MySQL用户名登录,但这只是为了方便起见。 可以轻松覆盖默认值,因为客户端程序允许使用 -u --user 选项 指定任何用户名 这意味着任何人都可以尝试使用任何用户名连接到服务器,因此除非所有MySQL帐户都有密码,否则无法以任何方式使数据库安全。 为没有密码的帐户指定用户名的任何人都可以成功连接到服务器。

  • MySQL用户名最长为32个字符。 操作系统用户名可能具有不同的最大长度。

    警告

    MySQL用户名长度限制在MySQL服务器和客户端中是硬编码的,并且试图通过修改 mysql 数据库 中表的定义来绕过它是 行不通的

    mysql 除非通过 第2.11节“升级MySQL”中 描述的过程,否则 不应 以任何方式 更改 数据库 中表的结构 尝试以任何其他方式重新定义MySQL的系统表会导致未定义和不受支持的行为。 服务器可以自由忽略由于此类修改而变得格式错误的行。

  • 要对使用内置身份验证方法的帐户的客户端连接进行身份验证,服务器将使用存储在 user 表中的 密码 这些密码与登录操作系统的密码不同。 用于登录Windows或Unix计算机 外部 密码与用于访问该计算机上的MySQL服务器的密码 之间没有必要的连接

    如果服务器使用其他插件对客户端进行身份验证,则插件实现的身份验证方法可能会也可能不会使用存储在 user 表中 的密码 在这种情况下,外部密码也可能用于向MySQL服务器进行身份验证。

  • 存储在 user 表中的密码使用特定 插件的算法进行加密。

  • 如果用户名和密码仅包含ASCII字符,则无论字符集设置如何,都可以连接到服务器。 要在用户名或密码包含非ASCII字符时启用连接,客户端应用程序应 mysql_options() 使用 MYSQL_SET_CHARSET_NAME 选项和相应的字符集名称作为参数 调用 C API函数 这会导致使用指定的字符集进行身份验证。 否则,除非服务器默认字符集与身份验证默认值中的编码相同,否则身份验证将失败。

    标准MySQL客户端程序支持一个 --default-character-set 导致如上所述 mysql_options() 调用 选项 此外,还支持字符集自动检测,如 第10.4节“连接字符集和排序”中所述 对于使用不基于C API的连接器的程序,连接器可以提供与 mysql_options() 可以使用 的连接器等效的连接器 检查连接器文档。

    前面的注释不适用于 ucs2 utf16 utf32 ,不允许作为客户端字符集。

MySQL安装过程使用初始 root 帐户 填充授权表 ,如 第2.10.4节“保护初始MySQL帐户”中所述 ,其中还讨论了如何为其分配密码。 此后,你通常建立,修改和删除MySQL账户使用语句,例如 CREATE USER DROP USER GRANT ,和 REVOKE 请参见 第6.2.8节“添加帐户,分配权限和删除帐户” 第13.7.1节“帐户管理语句”

要使用命令行客户端连接到MySQL服务器,请根据需要为要使用的帐户指定用户名和密码选项:

外壳> mysql --user=finley --password db_name

如果您更喜欢短选项,则命令如下所示:

外壳> mysql -u finley -p db_name

如果省略 命令行上 --password -p 选项 后面的密码值 (如刚才所示),则客户端会提示 输入密码值 或者,可以在命令行上指定密码:

shell> 
shell>mysql --user=finley --password=password db_namemysql -u finley -ppassword db_name

如果使用该 -p 选项,则 密码值和以下密码值 之间 必须 没有空格 -p

在命令行上指定密码应该被认为是不安全的。 请参见 第6.1.2.1节“密码安全的最终用户指南” 要避免在命令行上输入密码,请使用选项文件或登录路径文件。 请参见 第4.2.2.2节“使用选项文件” 第4.6.7节“ mysql_config_editor - MySQL配置实用程序”

有关指定用户名,密码和其他连接参数的其他信息,请参见 第4.2.3节“连接到MySQL服务器”

6.2.2 MySQL提供的权限

授予MySQL帐户的权限决定了帐户可以执行的操作。 MySQL权限在它们适用的上下文和不同操作级别上有所不同:

  • 管理权限使用户能够管理MySQL服务器的操作。 这些权限是全局的,因为它们不是特定于特定数据库的。

  • 数据库权限适用于数据库及其中的所有对象。 可以为特定数据库或全局授予这些权限,以便它们适用于所有数据库。

  • 可以为数据库中的特定对象,数据库中给定类型的所有对象(例如,数据库中的所有表)或全局的所有对象授予数据库对象(如表,索引,视图和存储例程)的权限。所有数据库中给定类型的对象。

权限在静态(内置到服务器)或动态(在运行时定义)方面也有所不同。 权限是静态还是动态会影响其授予用户帐户和角色的可用性。 有关静态和动态权限之间差异的信息,请参阅 静态与动态权限 。)

有关帐户权限的信息存储在 mysql 系统数据库 的授权表中 有关这些表的结构和内容的说明,请参见 第6.2.3节“授权表” MySQL服务器在启动时将内容读取到内存中,并在 第6.2.13节“权限更改生效时”中 指示的情况下重新加载它们 服务器基于授权表的内存中副本建立访问控制决策。

重要

一些MySQL版本引入了对授权表的更改以添加新的特权或功能。 要确保您可以利用任何新功能,请在升级MySQL时将授权表更新为当前结构。 请参见 第2.11节“升级MySQL”

以下部分总结了可用权限,提供了有关每个权限的更详细说明以及提供使用指南。

可用权限摘要

下表显示了 GRANT REVOKE 语句中 使用的静态特权名称 ,以及与授权表中的每个特权关联的列名以及特权适用的上下文。

表6.2 GRANT和REVOKE的允许静态权限

特权 授予表格列 上下文
ALL [PRIVILEGES] all privileges ”的 同义词 服务器管理
ALTER Alter_priv
ALTER ROUTINE Alter_routine_priv 存储例程
CREATE Create_priv 数据库,表或索引
CREATE ROLE Create_role_priv 服务器管理
CREATE ROUTINE Create_routine_priv 存储例程
CREATE TABLESPACE Create_tablespace_priv 服务器管理
CREATE TEMPORARY TABLES Create_tmp_table_priv
CREATE USER Create_user_priv 服务器管理
CREATE VIEW Create_view_priv 查看
DELETE Delete_priv
DROP Drop_priv 数据库,表或视图
DROP ROLE Drop_role_priv 服务器管理
EVENT Event_priv 数据库
EXECUTE Execute_priv 存储例程
FILE File_priv 服务器主机上的文件访问
GRANT OPTION Grant_priv 数据库,表或存储例程
INDEX Index_priv
INSERT Insert_priv 表或列
LOCK TABLES Lock_tables_priv 数据库
PROCESS Process_priv 服务器管理
PROXY 请参阅 proxies_priv 服务器管理
REFERENCES References_priv 数据库或表
RELOAD Reload_priv 服务器管理
REPLICATION CLIENT Repl_client_priv 服务器管理
REPLICATION SLAVE Repl_slave_priv 服务器管理
SELECT Select_priv 表或列
SHOW DATABASES Show_db_priv 服务器管理
SHOW VIEW Show_view_priv 查看
SHUTDOWN Shutdown_priv 服务器管理
SUPER Super_priv 服务器管理
TRIGGER Trigger_priv
UPDATE Update_priv 表或列
USAGE no privileges ”的 同义词 服务器管理

下表显示了 GRANT REVOKE 语句中 使用的动态权限名称 ,以及权限适用的上下文。

表6.3 GRANT和REVOKE的允许动态权限

特权 上下文
APPLICATION_PASSWORD_ADMIN 双密码管理
AUDIT_ADMIN 审核日志管理
BACKUP_ADMIN 备份管理
BINLOG_ADMIN 备份和复制管理
BINLOG_ENCRYPTION_ADMIN 备份和复制管理
CONNECTION_ADMIN 服务器管理
ENCRYPTION_KEY_ADMIN 服务器管理
FIREWALL_ADMIN 防火墙管理
FIREWALL_USER 防火墙管理
GROUP_REPLICATION_ADMIN 复制管理
PERSIST_RO_VARIABLES_ADMIN 服务器管理
REPLICATION_SLAVE_ADMIN 复制管理
RESOURCE_GROUP_ADMIN 资源组管理
RESOURCE_GROUP_USER 资源组管理
ROLE_ADMIN 服务器管理
SESSION_VARIABLES_ADMIN 服务器管理
SET_USER_ID 服务器管理
SYSTEM_USER 服务器管理
SYSTEM_VARIABLES_ADMIN 服务器管理
TABLE_ENCRYPTION_ADMIN 服务器管理
VERSION_TOKEN_ADMIN 服务器管理
XA_RECOVER_ADMIN 服务器管理

静态权限描述

与在运行时定义的动态权限相比,静态权限内置于服务器中。 以下列表描述了MySQL中可用的每个静态特权。

特定的SQL语句可能具有比此处指示的更具体的权限要求。 如果是,则有关语句的描述提供了详细信息。

动态权限说明

动态特权是在运行时定义的,与内置于服务器的静态特权形成对比。 以下列表描述了MySQL中可用的每个动态权限。

大多数动态权限在服务器启动时定义。 其他由特定服务器组件或插件定义,如权限说明中所示。 在这种情况下,除非启用了定义它的组件或插件,否则该特权不可用。

特定的SQL语句可能具有比此处指示的更具体的权限要求。 如果是,则有关语句的描述提供了详细信息。

特权授予指南

最好只向帐户授予它所需的权限。 在授予 FILE 和管理权限 时应特别小心

  • FILE 可以滥用MySQL服务器可以在服务器主机上读取的任何文件来读入数据库表。 这包括服务器数据目录中的所有世界可读文件和文件。 然后可以使用该表 SELECT 将其内容传输到客户端主机 来访问该表

  • GRANT OPTION 使用户能够将其权限授予其他用户。 具有不同权限和权限的两个用户 GRANT OPTION 可以组合权限。

  • ALTER 可用于通过重命名表来破坏权限系统。

  • SHUTDOWN 可以滥用通过终止服务器完全拒绝向其他用户提供服务。

  • PROCESS 可用于查看当前正在执行的语句的纯文本,包括设置或更改密码的语句。

  • SUPER 可用于终止其他会话或更改服务器的运行方式。

  • mysql 系统数据库本身 授予的权限 可用于更改密码和其他访问权限信息:

    • 密码以加密方式存储,因此恶意用户无法简单地读取密码以了解明文密码。 但是,对 mysql.user 系统表 authentication_string 具有写访问权限的用户 可以更改帐户的密码,然后使用该帐户连接到MySQL服务器。

    • INSERT UPDATE 授予 mysql 系统数据库使用户能够分别添加权限或修改现有权限。

    • DROP 对于 mysql 系统数据库,用户可以使用远程权限表,甚至是数据库本身。

静态与动态权限

MySQL支持静态和动态权限:

  • 静态特权内置于服务器中。 它们始终可以授予用户帐户,并且无法取消注册。

  • 动态特权可以在运行时注册和取消注册。 这会影响其可用性:无法授予尚未注册的动态权限。

例如, SELECT INSERT 权限是静态的并且始终可用,而动态权限仅在已启用实现它的服务器组件时才可用。

本节的其余部分将介绍动态权限在MySQL中的工作原理。 讨论使用术语 组件 ”, 但同样适用于插件。

注意

服务器管理员应该知道哪些服务器组件定义了动态权限。 对于MySQL发行版,定义动态权限的组件文档描述了这些权限。

第三方组件也可以定义动态权限; 管理员应该了解这些权限,而不是安装可能与服务器操作冲突或危害的组件。 例如,如果两个组件都定义了具有相同名称的权限,则一个组件与另一个组件冲突。 组件开发人员可以通过选择具有基于组件名称的前缀的权限名称来降低发生这种情况的可能性。

服务器在内存中维护已注册的动态权限集。 服务器关闭时发生取消注册。

通常,定义动态权限的服务器组件在其初始化序列期间在安装时注册它们。 卸载时,服务器组件不会取消注册其已注册的动态权限。 (这是当前的做法,而不是要求。也就是说,组件可以,但不能在任何时候取消注册它们注册的权限。)

尝试注册已注册的动态权限时不会出现警告或错误。 请考虑以下语句序列:

安装组件'my_component';
UNINSTALL COMPONENT'my_component';
安装组件'my_component';

第一个 INSTALL COMPONENT 语句注册服务器组件定义的任何权限 my_component ,但 UNINSTALL COMPONENT 不注销它们。 对于第二个 INSTALL COMPONENT 语句,发现已注册的组件权限已经注册,但不会发生警告或错误。

动态权限仅适用于全局级别。 服务器将有关当前动态权限分配的信息存储到 mysql.global_grants 系统表 中的用户帐户

  • 服务器自动注册 global_grants 在服务器启动期间 命名的权限 (除非 --skip-grant-tables 给出选项)。

  • GRANT REVOKE 语句修改的内容 global_grants

  • 列出的动态权限分配 global_grants 是持久的。 服务器关闭时不会删除它们。

示例:以下语句向用户授予 u1 控制从属服务器上的复制(包括组复制)以及修改系统变量所需的权限:

GRANT REPLICATION_SLAVE_ADMIN,GROUP_REPLICATION_ADMIN,BINLOG_ADMIN
ON *。* TO'u1'@'localhost';

授权动态特权出现在 SHOW GRANTS 语句和 INFORMATION_SCHEMA USER_PRIVILEGES 的输出 中。

对于 GRANT REVOKE 在全球范围内,静态是针对当前的一组登记的动态权限检查,如果发现不授予任何公认的命名特权。 否则,将发生错误以指示未知的权限标识符。

对于 GRANT REVOKE 意义 ALL [PRIVILEGES] 在全球范围包括所有静态全局权限,以及所有目前已登记的动态权限:

  • GRANT ALL 在全局级别授予所有静态全局特权和所有当前注册的动态特权。 在执行该 GRANT 语句 之后注册的动态权限 不会追溯授予任何帐户。

  • REVOKE ALL 在全局级别撤消所有授予的静态全局特权和所有授予的动态特权。

FLUSH PRIVILEGES 语句读取 global_grants 表以获取动态权限分配,并注册在那里找到的任何未注册权限。

有关MySQL发行版中包含的MySQL服务器和服务器组件提供的动态权限的说明,请参见 第6.2.2节“MySQL提供的权限”

将帐户从SUPER迁移到动态权限

在MySQL 8.0中,许多以前需要该 SUPER 权限的操作也与更有限范围的动态权限相关联。 (有关这些权限的说明,请参见 第6.2.2节“MySQL提供的权限” 。)通过授予关联的动态权限而不是,可以允许每个此类操作进入帐户 SUPER 此更改通过使DBA能够避免 SUPER 准确地授予 和定制用户权限 来提高安全性 SUPER 现已弃用,将在未来版本的MySQL中删除。

SUPER 发生 删除 时, SUPER 除非已授予 SUPER 帐户 迁移到适当的动态权限, 否则 以前需要的操作 将失败 使用以下说明完成该目标,以便在 SUPER 删除 之前准备好帐户

  1. 执行此查询以标识已授予的帐户 SUPER

    从INFORMATION_SCHEMA.USER_PRIVILEGES中选择GRANTEE
    WHERE PRIVILEGE_TYPE ='超级';
    
  2. 对于前面的查询标识的每个帐户,确定它需要的操作 SUPER 然后授予与这些操作对应的动态权限,并撤消 SUPER

    例如,如果 'u1'@'localhost' 需要 SUPER 二进制日志清除和系统变量修改,则这些语句会对帐户进行必要的更改:

    GRANT BINLOG_ADMIN,SYSTEM_VARIABLES_ADMIN ON *。* TO'u1'@'localhost';
    REVOKE SUPER ON *。* FROM'u1'@'localhost';
    

    修改完所有适用的帐户后, INFORMATION_SCHEMA 第一步中 查询应生成一个空结果集。

6.2.3拨款表

mysql 系统数据库包括包含关于用户帐户和他们持有的特权信息的几个授权表。 本节介绍这些表。 有关系统数据库中其他表的信息,请参见 第5.3节“mysql系统模式”

此处的讨论描述了授权表的基础结构以及服务器在与客户端交互时如何使用其内容。 但是,通常不直接修改授权表。 当您使用帐户管理语句(例如 CREATE USER GRANT )和 REVOKE 设置帐户并控制每个帐户可用的权限 时,间接会发生修改 请参见 第13.7.1节“帐户管理语句” 当您使用此类语句执行帐户操作时,服务器会代表您修改授权表。

注意

使用诸如 ,或者 不鼓励的 语句直接修改授权表 INSERT 并且风险自负。 服务器可以自由忽略由于此类修改而变得格式错误的行。 UPDATE DELETE

对于修改授权表的任何操作,服务器检查该表是否具有预期结构,否则生成错误。 要将表更新为预期结构,请执行MySQL升级过程。 请参见 第2.11节“升级MySQL”

授权表概述

这些 mysql 数据库表包含授权信息:

有关静态和动态全局权限之间差异的信息,请参阅 静态与动态权限 。)

在MySQL 8.0中,授权表使用 InnoDB 存储引擎并且是事务性的。 在MySQL 8.0之前,授权表使用了 MyISAM 存储引擎并且是非事务性的。 授权表存储引擎的这种更改使得对帐户管理语句(例如 CREATE USER 或) 的行为的伴随更改成为 可能 GRANT 以前,为多个用户命名的帐户管理语句可能会对某些用户成功,而对其他用户则失败。 现在,每个语句都是事务性的,并且对所有命名用户都成功或回滚,如果发生任何错误则无效。

每个授权表都包含范围列和特权列:

  • 范围列确定表中每行​​的范围; 也就是说,行适用的上下文。 例如,一个 user 表行,其中包含 Host User 值, 'h1.example.net' 并且 'bob' 适用于 h1.example.net 由指定用户名的客户端 从主机对服务器进行的身份验证的连接 bob 类似地, db 表行包含 Host User Db 列值 'h1.example.net' 'bob' 'reports' bob 从主机连接 h1.example.net 到访问 reports 数据库时应用。 tables_priv columns_priv 表包含范围列,指示每行适用的表或表/列组合。 procs_priv 范围列表示存储程序到各行适用。

  • 权限列指示表行授予的权限; 也就是说,它允许执行哪些操作。 服务器将各种授权表中的信息组合在一起,形成用户权限的完整描述。 第6.2.7节“访问控制,第2阶段:请求验证” ,描述了相关规则。

此外,授权表可能包含用于范围或特权评估之外的目的的列。

服务器以下列方式使用授权表:

  • user 表范围列确定是否拒绝或允许传入连接。 对于允许的连接, user 表中 授予的任何权限都 表示用户的静态全局权限。 此表中授予的任何权限 适用于 服务器上的 所有 数据库。

    警告

    因为任何静态全局特权被认为是所有数据库的特权,任何静态全局特权使用户能够看到所有的数据库名称 SHOW DATABASES 或通过检查 SCHEMATA INFORMATION_SCHEMA ,除了已经在通过局部撤销数据库级别被限制的数据库。

  • global_grants 表列出了当前对用户帐户的动态全局权限的分配。 对于每一行,作用域列确定哪个用户具有在权限列中指定的权限。

  • db 表范围列决定哪些用户可以访问哪些数据库从哪个主机。 权限列确定允许的操作。 在数据库级别授予的权限适用于数据库和数据库中的所有对象,例如表和存储的程序。

  • tables_priv columns_priv 表类似于 db 表,但是更精致:他们在申请表和列级应用而非在数据库级。 表级别授予的权限适用于表及其所有列。 在列级别授予的权限仅适用于特定列。

  • procs_priv 表适用于存储的例程(存储过程和函数)。 在例程级别授予的权限仅适用于单个过程或函数。

  • proxies_priv 表指示哪些用户可以充当其他用户的代理以及用户是否可以将该 PROXY 特权 授予 其他用户。

  • default_roles role_edges 表包含角色关系的信息。

  • password_history 表保留以前选择的密码以启用密码重用限制。 请参见 第6.2.15节“密码管理”

服务器在启动时将授权表的内容读入内存。 您可以通过发出 FLUSH PRIVILEGES 语句或执行 mysqladmin flush-privileges 来告诉它重新加载表 mysqladmin reload 命令 对授权表的更改将在 第6.2.13节“特权更改 生效时”中指示生效

修改帐户时,最好验证您的更改是否具有预期效果。 要检查给定帐户的权限,请使用该 SHOW GRANTS 语句。 例如,要确定与用户名和主机名值授予一个帐户的权限 bob pc84.example.com 使用下面的语句:

为'bob'@'pc84.example.com'展示奖学金;

要显示帐户的非特权属性,请使用 SHOW CREATE USER

SHOW CREATE USER'bob'@'pc84.example.com';

用户和数据库表

服务器 访问控制的第一和第二阶段 使用 数据库中 user db mysql (请参见 第6.2节“访问控制和帐户管理” )。 这里显示 user db 表中的列。

表6.4 user和db Table列

表名 user db
范围列 Host Host
User Db
User
权限列 Select_priv Select_priv
Insert_priv Insert_priv
Update_priv Update_priv
Delete_priv Delete_priv
Index_priv Index_priv
Alter_priv Alter_priv
Create_priv Create_priv
Drop_priv Drop_priv
Grant_priv Grant_priv
Create_view_priv Create_view_priv
Show_view_priv Show_view_priv
Create_routine_priv Create_routine_priv
Alter_routine_priv Alter_routine_priv
Execute_priv Execute_priv
Trigger_priv Trigger_priv
Event_priv Event_priv
Create_tmp_table_priv Create_tmp_table_priv
Lock_tables_priv Lock_tables_priv
References_priv References_priv
Reload_priv
Shutdown_priv
Process_priv
File_priv
Show_db_priv
Super_priv
Repl_slave_priv
Repl_client_priv
Create_user_priv
Create_tablespace_priv
Create_role_priv
Drop_role_priv
安全专栏 ssl_type
ssl_cipher
x509_issuer
x509_subject
plugin
authentication_string
password_expired
password_last_changed
password_lifetime
account_locked
Password_reuse_history
Password_reuse_time
Password_require_current
User_attributes
资源控制列 max_questions
max_updates
max_connections
max_user_connections

user plugin authentication_string 列存储身份验证插件和证书信息。

服务器使用 plugin 帐户行列中 指定的插件 来验证帐户的连接尝试。

plugin 列必须是非空的。 在启动时,在运行时 FLUSH PRIVILEGES 执行时,服务器会检查 user 表行。 对于具有空 plugin 列的 任何行 ,服务器会向此表单的错误日志写入警告:

[警告]用户输入' user_name'@'host_name '有一个空的插件
值。用户将被忽略,没有人可以使用此用户登录
了。

要将插件分配给缺少一个的帐户,请使用 ALTER USER 语句。

password_expired 列允许DBA使帐户密码到期,并要求用户重置其密码。 默认 password_expired 值为 'N' ,但可以 'Y' 使用 ALTER USER 语句 设置 帐户密码过期后,帐户在后续服务器连接中执行的所有操作都会导致错误,直到用户发出 ALTER USER 声明以建立新帐户密码。

密码过期后可以 通过将密码设置为当前值 重置 密码。 作为一个好的政策问题,最好选择不同的密码。 DBA可以通过建立适当的密码重用策略来强制执行非重用。 请参阅 密码重用策略

password_last_changed 是一个 TIMESTAMP 列,指示上次更改密码的时间。 该值为非 NULL 仅适用于使用MySQL内置的身份验证插件账户( mysql_native_password sha256_password ,或 caching_sha2_password )。 该值适用 NULL 于其他帐户,例如使用外部身份验证系统进行身份验证的帐户。

password_last_changed 通过更新 CREATE USER ALTER USER SET PASSWORD 报表,并通过 GRANT 创造一个帐户或更改帐户密码的语句。

password_lifetime 表示帐户密码生存期,以天为单位。 如果密码超过其生命周期(使用 password_last_changed 评估 ),则服务器会在客户端使用该帐户连接时认为密码已过期。 N 大于零意味着必须每天更改密码 N 值为0将禁用自动密码到期。 如果值为 NULL (缺省值),则应用全局过期策略,如 default_password_lifetime 系统变量 所定义

account_locked 指示帐户是否已锁定(请参见 第6.2.19节“帐户锁定” )。

Password_reuse_history PASSWORD HISTORY 帐户选项 的值 ,或 NULL 默认历史记录的值。

Password_reuse_time PASSWORD REUSE INTERVAL 帐户选项 的值 ,或 NULL 默认间隔的值。

Password_require_current (在MySQL 8.0.13中添加)对应于 PASSWORD REQUIRE 帐户选项 的值, 如下表所示。

表6.5允许的Password_require_current值

Password_require_current值 相应的密码请求选项
'Y' PASSWORD REQUIRE CURRENT
'N' PASSWORD REQUIRE CURRENT OPTIONAL
NULL PASSWORD REQUIRE CURRENT DEFAULT

User_attributes (在MySQL 8.0.14中添加)存储未存储在其他列中的帐户属性:

  • additional_password :辅助密码,如果有的话。 请参阅 双密码支持

  • Restrictions :限制列表,如果有的话。 部分撤销操作会增加限制。 属性值是一个元素数组,每个元素都有 Database Restrictions 键,指示受限数据库的名称及其适用的限制(请参见 第6.2.12节“使用部分撤消的权限限制” )。

如果没有适用的属性,那 User_attributes 就是 NULL

例如:具有二级密码和部分撤销数据库特权拥有帐户 additional_password Restrictions 在该列的值属性:

MySQL的> SELECT User_attributes FROM mysql.User WHERE User = 'u'\G
*************************** 1。排******************** *******
User_attributes:{“限制”:
                   [{“Database”:“mysql”,“Privileges”:[“SELECT”]}],
                  “additional_password”:“ hashed_credentials”}

要确定存在哪些属性,请使用以下 JSON_KEYS() 函数:

SELECT User,Host,JSON_KEYS(User_attributes)
FROM mysql.user WHERE User_attributes IS NOT NULL;

要提取特定属性,例如 Restrictions ,请执行以下操作:

SELECT User,Host,User_attributes  -  >>'$。Restrictions'
FROM mysql.user WHERE User_attributes  -  >>'$。Restrictions'<>'';

tables_priv和columns_priv表

在访问控制的第二阶段,服务器执行请求验证以确保每个客户端对其发出的每个请求具有足够的权限。 除了 user db grant表之外,服务器还可以查询 tables_priv columns_priv 涉及表的请求。 后面的表在表级和列级提供更精细的权限控制。 它们具有下表中显示的列。

表6.6 tables_priv和columns_priv表列

表名 tables_priv columns_priv
范围列 Host Host
Db Db
User User
Table_name Table_name
Column_name
权限列 Table_priv Column_priv
Column_priv
其他专栏 Timestamp Timestamp
Grantor

Timestamp Grantor 列被设置为当前时间戳和 CURRENT_USER 值,分别,但其他未使用的。

procs_priv表

为了验证涉及存储例程的请求,服务器可以查询该 procs_priv 表,该表具有下表中显示的列。

表6.7 procs_priv表列

表名 procs_priv
范围列 Host
Db
User
Routine_name
Routine_type
权限列 Proc_priv
其他专栏 Timestamp
Grantor

Routine_type 列是一个 ENUM 值为 'FUNCTION' 列, 'PROCEDURE' 表示行引用的例程类型。 此列允许为具有相同名称的函数和过程单独授予权限。

Timestamp Grantor 列未使用。

proxies_priv表

proxies_priv 表记录有关代理帐户的信息。 它有以下列:

  • Host User :代理帐户; 也就是说,具有 PROXY 代理帐户权限的帐户。

  • Proxied_host Proxied_user :代理帐户。

  • Grantor Timestamp :未使用。

  • With_grant :代理帐户是否可以将 PROXY 权限 授予 其他帐户。

对于能够将 PROXY 权限 授予 其他帐户的帐户,它必须在 proxies_priv 表中具有 With_grant 设置为1的行, Proxied_host Proxied_user 设置为指示可以为其授予权限的帐户。 例如, 'root'@'localhost' 在MySQL安装期间创建 帐户在 proxies_priv 表中 有一行,该行 允许 为所有用户和所有主机 授予 PROXY 权限 ''@'' 这样可以 root 设置代理用户,以及委托其他帐户设置代理用户的权限。 请参见 第6.2.18节“代理用户”

global_grants表

global_grants 表列出了当前对用户帐户的动态全局权限的分配。 该表包含以下列:

  • USER HOST :授予权限的帐户的用户名和主机名。

  • PRIV :权限名称。

  • WITH_GRANT_OPTION :帐户是否可以将权限授予其他帐户。

default_roles表

default_roles 表列出了默认用户角色。 它有以下列:

  • HOST USER :默认角色适用的帐户或角色。

  • DEFAULT_ROLE_HOST DEFAULT_ROLE_USER :默认角色。

role_edges表

role_edges 表列出了角色子图的边缘。 它有以下列:

  • FROM_HOST FROM_USER :被授予角色的帐户。

  • TO_HOST TO_USER :授予帐户的角色。

  • WITH_ADMIN_OPTION :帐户是否可以通过使用授予角色和从其他帐户撤消角色 WITH ADMIN OPTION

password_history表

password_history 表包含有关密码更改的信息。 它有以下列:

  • Host User :发生密码更改的帐户。

  • Password_timestamp :密码更改发生的时间。

  • Password :新密码哈希值。

password_history 表为每个帐户累积足够数量的非空密码,以使MySQL能够对帐户密码历史记录长度和重用间隔执行检查。 当发生密码更改尝试时,会自动修剪超出两个限制的条目。

注意

空密码不会计入密码历史记录中,并且可以随时重复使用。

如果重命名帐户,则会重命名其条目以匹配。 如果删除帐户或更改其身份验证插件,则会删除其条目。

范围列属性

授权表中的范围列包含字符串。 每个的默认值是空字符串。 下表显示了每列中允许的字符数。

表6.8授权表范围列长度

列名称 允许的最大字符数
Host Proxied_host 255(MySQL 8.0.17之前的60)
User Proxied_user 32
Db 64
Table_name 64
Column_name 64
Routine_name 64

对于访问检查的目的,进行比较 User Proxied_user authentication_string Db ,和 Table_name 的值是大小写敏感的。 的比较 Host Proxied_host Column_name ,和 Routine_name 的值是不区分大小写。

权限列属性

user db 表列出了被声明为一个单独的列每个特权 ENUM('N','Y') DEFAULT 'N' 换句话说,可以禁用或启用每个权限,默认为禁用。

tables_priv columns_priv procs_priv 表申报权限列的 SET 列。 这些列中的值可以包含表控制的权限的任意组合。 仅启用列值中列出的那些权限。

表6.9 Set-Type特权列值

表名 列名称 可能的集合元素
tables_priv Table_priv 'Select', 'Insert', 'Update', 'Delete', 'Create', 'Drop', 'Grant', 'References', 'Index', 'Alter', 'Create View', 'Show view', 'Trigger'
tables_priv Column_priv 'Select', 'Insert', 'Update', 'References'
columns_priv Column_priv 'Select', 'Insert', 'Update', 'References'
procs_priv Proc_priv 'Execute', 'Alter Routine', 'Grant'

只有 user global_grants 表指定管理权限,如 RELOAD SHUTDOWN SYSTEM_VARIABLES_ADMIN 管理操作是服务器本身的操作,并不是特定于数据库的,因此没有理由在其他授权表中列出这些特权。 因此,服务器只需要查询 user global_grants 表来确定用户是否可以执行管理操作。

FILE 权限也仅在 user 表中 指定 它本身不是管理权限,但用户在服务器主机上读取或写入文件的能力与所访问的数据库无关。

6.2.4指定帐户名称

MySQL帐户名由用户名和主机名组成。 这样可以为具有相同名称且可以从不同主机连接的用户创建帐户。 本节介绍如何编写帐户名,包括特殊值和通配符规则。

MySQL角色名称与帐户名称类似,但 第6.2.5节“指定角色名称”中 描述了一些差异

在诸如 ,和 等帐户名的 SQL语句中 CREATE USER 遵循以下规则: GRANT SET PASSWORD

  • 帐户名称语法是 'user_name'@'host_name'

  • 仅包含用户名的帐户名称相当于 例如, 相当于 'user_name'@'%' 'me' 'me'@'%'

  • 如果用户名和主机名是合法的,则不需要引用它们作为不带引号的标识符。 需要引号来指定 user_name 包含特殊字符(如空格或 - )的 host_name 字符串 ,或 包含特殊字符或通配符(例如, . % 字符串 (例如 'test-user'@'%.com' )。

  • 使用反引号( ` ),单引号( ' )或双引号( " 引用用户名和主机名作为标识符或字符串 有关字符串引用和标识符引用指南,请参见 第9.1.1节“字符串文字” 第9.2节“模式对象名称”

  • 如果引用,用户名和主机名部分必须单独引用。 也就是说,写 'me'@'localhost' ,不 'me@localhost' ; 后者实际上相当于 'me@localhost'@'%'

  • CURRENT_USER or CURRENT_USER() 函数的 引用 等同于从字面上指定当前客户端的用户名和主机名。

MySQL mysql 使用单独的用户名和主机名部分列 将帐户名存储在 系统数据库的 授权表中

  • user 表包含每个帐户的一行。 User Host 列存储用户名和主机名。 此表还指示帐户具有哪些全局权限。

  • 其他授权表指示帐户对数据库和数据库中的对象具有的特权。 这些表必须 User Host 存储帐户名称列。 这些表中的每一行与该帐户相关联 user ,具有相同的表 User Host 值。

  • 为了访问检查目的,用户值的比较是区分大小写的。 主机值的比较不区分大小写。

有关授权表的结构更多细节,请参见 第6.2.3节“授权表”

用户名和主机名具有某些特殊值或通配符约定,如下所述。

帐户名的用户名部分是非空白值,与字面上与传入连接尝试的用户名匹配,或者是与任何用户名匹配的空值(空字符串)。 具有空白用户名的帐户是匿名用户。 要在SQL语句中指定匿名用户,请使用带引号的空用户名部分,例如 ''@'localhost'

帐户名称的主机名部分可以采用多种形式,并允许使用通配符:

  • 主机值可以是主机名或IP地址(IPv4或IPv6)。 该名称 'localhost' 表示本地主机。 IP地址 '127.0.0.1' 表示IPv4环回接口。 IP地址 '::1' 表示IPv6环回接口。

  • % _ 通配符允许在主机名或IP地址的值。 这些与操作员执行的模式匹配操作具有相同的含义 LIKE 例如,主机值 '%' 匹配任何主机名,而值 '%.mysql.com' 匹配 mysql.com 域中的 任何主机 '198.51.100.%' 匹配198.51.100 C类网络中的任何主机。

    由于主机值中允许使用IP通配符值(例如, '198.51.100.%' 为了匹配子网上的每个主机),因此有人可能会尝试通过命名主机来利用此功能 198.51.100.somewhere.com 为了阻止这种尝试,MySQL不会对以数字和点开头的主机名执行匹配。 例如,如果命名了主机 1.2.example.com ,则其名称永远不会与帐户名称的主机部分匹配。 IP通配符值只能匹配IP地址,而不能匹配主机名。

  • 对于指定为IPv4地址的主机值,可以给出网络掩码以指示用于网络号的地址位数。 网络掩码表示法不能用于IPv6地址。

    语法是 例如: host_ip/netmask

    创建用户'david'@'198.51.100.0/255.255.255.0';
    

    这使得 david 能够从具有 client_ip 以下条件为真的 IP地址的任何客户端主机进行连接

    client_ipnetmask=host_ip
    

    也就是说,对于 CREATE USER 刚才显示 声明:

    client_ip &255.255.255.0 = 198.51.100.0
    

    满足此条件范围的IP地址 198.51.100.0 198.51.100.255

    网络掩码通常以设置为1的位开头,然后将位设置为0.示例:

    • 198.0.0.0/255.0.0.0 :198 A类网络上的任何主机

    • 198.51.100.0/255.255.0.0 :198.51 B类网络上的任何主机

    • 198.51.100.0/255.255.255.0 :198.51.100 C类网络上的任何主机

    • 198.51.100.1 :仅具有此​​特定IP地址的主机

服务器使用系统DNS解析程序为客户端主机名或IP地址返回的值,针对客户端主机执行帐户名中的主机值匹配。 除了使用网络掩码表示法指定帐户主机值的情况之外,服务器将此比较作为字符串匹配执行,即使对于作为IP地址给出的帐户主机值也是如此。 这意味着您应该使用DNS使用的相同格式指定帐户主机值。 以下是需要注意的问题示例:

  • 假设本地网络上的主机具有完全限定名称 host1.example.com 如果DNS返回此主机的名称查找,请 host1.example.com 在帐户主机值中使用该名称。 如果DNS返回 host1 ,请 host1 改用。

  • 如果DNS返回给定主机的IP地址 198.51.100.2 ,那将匹配帐户主机值 198.51.100.2 但不 匹配 198.051.100.2 同样,它会匹配帐户主机模式, 198.51.100.% 但不 匹配 198.051.100.%

为避免这些问题,建议您检查DNS返回主机名和地址的格式。 在MySQL帐户名中使用相同格式的值。

6.2.5指定角色名称

MySQL角色名称指的是角色,它们被命名为特权集合。 有关角色使用示例,请参见 第6.2.10节“使用角色”

角色名的语法和语义相似的账户名( 第6.2.4节“指定帐户名” )。 角色名称在这些方面与帐户名称不同:

  • 角色名称的用户部分不能为空。 因此,没有 匿名角色 类似于 匿名用户 的概念

  • 作为一个帐户名,省略了在主机部分角色名称结果主机部分 '%' 但是,与 '%' 在一个帐户名,主机部分 '%' 的角色名称没有通配符性能。 例如,对于一个名称 'me'@'%' 用作角色名,主机部分( '%' )仅仅是一个文字值; 它没有 任何主机 匹配属性。

  • 角色名称的主机部分中的网络掩码表示法没有意义。

  • 帐户名称允许 CURRENT_USER() 在多个上下文中。 角色名称不是。

mysql.user 系统表中 的一行 可以同时用作帐户和角色。 在这种情况下,任何特殊用户或主机名匹配属性都不适用于将该名称用作角色名称的上下文。 例如,您不能执行以下语句,期望它将使用具有用户部分 myrole 和任何主机名的 所有角色设置当前会话角色

SET ROLE'myrole'@'%';

相反,该语句将会话的活动角色设置为具有完全名称的角色 'myrole'@'%'

因此,通常仅使用用户名部分指定角色名称,并隐式使用主机名部分 '%' '%' 如果您打算创建一个既可用作角色又可用作允许从给定主机连接的用户帐户的名称,则 指定具有非 主机部件 的角色 非常有用。

6.2.6访问控制,阶段1:连接验证

当您尝试连接到MySQL服务器时,服务器会根据以下条件接受或拒绝连接:

  • 您的身份以及是否可以通过提供正确的密码来验证您的身份

  • 您的帐户是锁定还是解锁

服务器首先检查凭据,然后检查帐户锁定状态。 任一步骤失败都会导致服务器完全拒绝您的访问权限。 否则,服务器接受连接,然后进入阶段2并等待请求。

使用三个执行凭证检查 user 表范围列( Host User ,和 authentication_string )。 锁定状态记录在 user 表格 account_locked 列中。 仅当 某些 表行中 Host User user 与客户端主机名和用户名匹配时, 服务器才接受连接 ,客户端提供该行中指定的密码, account_locked 值为 'N' 允许 Host User 的规则 第6.2.4节“指定帐户名称”中给出 可以使用 ALTER USER 语句 更改帐户锁定

您的身份基于两条信息:

  • 您连接的客户端主机

  • 您的MySQL用户名

如果 User 列值为非空,则传入连接中的用户名必须完全匹配。 如果 User 值为空,则它匹配任何用户名。 如果 user 与传入连接匹配 表行具有空白用户名,则该用户被视为没有名称的匿名用户,而不是具有客户端实际指定名称的用户。 这意味着空白用户名用于连接持续时间内的所有进一步访问检查(即,在阶段2期间)。

authentication_string 列可以为空白。 这不是通配符,并不表示任何密码匹配。 这意味着用户必须在不指定密码的情况下进行连接。 如果服务器使用插件对客户端进行身份验证,则插件实现的身份验证方法可能会也可能不会使用 authentication_string 列中 的密码 在这种情况下,外部密码也可能用于向MySQL服务器进行身份验证。

表中的非 authentication_string user 表示加密密码。 MySQL不会将密码存储为任何人都可以看到的明文。 而是,尝试连接的用户提供的密码是加密的(使用由帐户认证插件实现的密码散列方法)。 然后在检查密码是否正确时,在连接过程中使用加密密码。 这是在没有经过连接的加密密码的情况下完成的。 请参见 第6.2.1节“帐户用户名和密码”

从MySQL的角度来看,加密密码是 真正的 密码,所以你永远不应该让任何人访问它。 特别是, 不要给非管理用户读取对 mysql 系统数据库 中表的访问权限

下表显示了表中各种组合 User Host 如何 user 应用于传入连接。

User Host 允许的连接
'fred' 'h1.example.net' fred ,连接 h1.example.net
'' 'h1.example.net' 任何用户,从中连接 h1.example.net
'fred' '%' fred ,从任何主机连接
'' '%' 任何用户,从任何主机连接
'fred' '%.example.net' fred ,从 example.net 域中的 任何主机连接
'fred' 'x.example.%' fred ,从连接 x.example.net x.example.com x.example.edu ,等; 这可能没用
'fred' '198.51.100.177' fred ,从主机与IP地址连接 198.51.100.177
'fred' '198.51.100.%' fred ,从 198.51.100 C类子网 中的任何主机连接
'fred' '198.51.100.0/255.255.255.0' 与前面的示例相同

传入连接的客户端主机名和用户名可以匹配 user 中的多个行 前述组实例证明这一点:若干条目的匹配示出从连接 h1.example.net fred

当可能存在多个匹配项时,服务器必须确定要使用哪些匹配项。 它解决了这个问题如下:

  • 只要服务器将 user 入内存,它就会对行进行排序。

  • 当客户端尝试连接时,服务器按排序顺序查看行。

  • 服务器使用与客户端主机名和用户名匹配的第一行。

服务器使用排序规则, Host 首先 对具有最具特定 值的 行进行排序 文字主机名和IP地址是最具体的。 (文字IP地址的特异性不受其是否具有网络掩码,因此 198.51.100.13 198.51.100.0/255.255.255.0 被认为是同样特异性的。)该模式 '%' 是指 任何主机 并且是最不特定。 空字符串 '' 也表示 任何主机 ”, 但后面排序 '%' 具有相同 Host 值的 行首先以 最具特定的 User 排序 (空白 User 值表示 任何用户 并且最不具体)。 对于具有相同特定 Host User 值的行,顺序是不确定的。

要查看其工作原理,请假设该 user 表如下所示:

+ ----------- + ---------- +  - 
| 主持人| 用户| ...
+ ----------- + ---------- +  - 
| %| 根| ...
| %| 杰弗里| ...
| localhost | 根| ...
| localhost | | ...
+ ----------- + ---------- +  - 

当服务器将表读入内存时,它使用刚才描述的规则对行进行排序。 排序后的结果如下所示:

+ ----------- + ---------- +  - 
| 主持人| 用户| ...
+ ----------- + ---------- +  - 
| localhost | 根| ...
| localhost | | ...
| %| 杰弗里| ...
| %| 根| ...
+ ----------- + ---------- +  - 

当客户端尝试连接时,服务器会查看已排序的行并使用找到的第一个匹配项。 对于从连接 localhost jeffrey 两个从表匹配的行的:一个具有 Host User 的值 'localhost' '' ,和一个具有值 '%' 'jeffrey' 'localhost' 行首先按排序顺序出现,因此这是服务器使用的行。

这是另一个例子。 假设 user 表格如下所示:

+ ---------------- + ---------- +  - 
| 主持人| 用户| ...
+ ---------------- + ---------- +  - 
| %| 杰弗里| ...
| h1.example.net | | ...
+ ---------------- + ---------- +  - 

排序表如下所示:

+ ---------------- + ---------- +  - 
| 主持人| 用户| ...
+ ---------------- + ---------- +  - 
| h1.example.net | | ...
| %| 杰弗里| ...
+ ---------------- + ---------- +  - 

通过连接 jeffrey h1.example.net 由第一行匹配,而通过连接 jeffrey 来自任何主机通过第二匹配。

注意

认为对于给定的用户名,当服务器尝试查找连接匹配时,首先使用显式命名该用户的所有行,这是一种常见的误解。 这不是真的。 前面的例子中示出了这一点,其中从连接 h1.example.net 通过 jeffrey 首先由包含行匹配不 'jeffrey' 作为 User 列值,而是由没有用户名的行。 因此 jeffrey ,即使他在连接时指定了用户名,也会作为匿名用户进行身份验证。

如果您能够连接到服务器,但您的权限不是您所期望的,那么您可能正在进行其他帐户的身份验证。 要了解服务器用于验证您的帐户,请使用该 CURRENT_USER() 功能。 (请参见 第12.15节“信息函数” 。)它返回一个 格式 ,表示 匹配 表行的 假设 连接并发出以下查询: user_name@host_name User Host user jeffrey

MySQL的> SELECT CURRENT_USER();
+ ---------------- +
| CURRENT_USER()|
+ ---------------- +
| @localhost |
+ ---------------- +

此处显示的结果表明匹配的 user 表行具有空白 User 列值。 换句话说,服务器将被 jeffrey 视为匿名用户。

诊断身份验证问题的另一种方法是打印出 user 表格并手动对其进行排序,以查看第一次匹配的位置。

6.2.7访问控制,第2阶段:请求验证

建立连接后,服务器进入访问控制的第2阶段。 对于通过该连接发出的每个请求,服务器确定您要执行的操作,然后检查您是否具有足够的权限来执行此操作。 这是授权表中的特权列发挥作用的地方。 这些权限可以来自任何的 user global_grants db tables_priv columns_priv ,或 procs_priv 表。 (您可能会发现参考 第6.2.3节“授权表” 很有帮助 ,它列出了每个授权表中的列。)

user global_grants 表授予全局权限。 这些表中给定帐户的行表示无论默认数据库是什么,都在全局范围内应用的帐户权限。 例如,如果 user 表授予您 DELETE 特权,则可以从服务器主机上任何数据库的任何表中删除行。 user 表中的 权限 授予 需要它们的人(例如数据库管理员) 是明智的 对于其他用户,请将 user 表中的 所有权限保留 'N' 并且仅在更具体的级别授予权限(对于特定的数据库,表,列或例程)。 也可以在全局范围内授予数据库权限,但使用部分撤销来限制它们在特定数据库上执行(请参见 第6.2.12节“使用部分撤消的权限限制” )。

db 表授予特定于数据库的权限。 此表的范围列中的值可以采用以下形式:

  • User 值与匿名用户匹配。 非空白值与字面意义相符; 用户名中没有通配符。

  • 通配符 % _ 可以在使用 Host Db 列。 这些与操作员执行的模式匹配操作具有相同的含义 LIKE 如果要在授予权限时按字面意思使用任一字符,则必须使用反斜杠对其进行转义。 例如,要将下划线字符( _ )作为数据库名称的一部分 包括在内 \_ ,请在 GRANT 语句中 指定它

  • A '%' 或空白 Host 值表示 任何主机。

  • 一个 '%' 或空白 Db 值意味着 任何数据库。

服务器将 db 入内存并在读取 user 的同时对其进行排序 服务器排序 db 基于表 Host Db User 范围列。 user 表一样,排序将最具体的值放在最前面,将最不具体的值放在最后,当服务器查找匹配的行时,它使用它找到的第一个匹配。

tables_priv columns_priv procs_priv 表授予特定表,特定列,日常特定权限。 这些表的范围列中的值可以采用以下形式:

  • 通配符 % _ 可在使用 Host 的列。 这些与操作员执行的模式匹配操作具有相同的含义 LIKE

  • A '%' 或空白 Host 值表示 任何主机。

  • Db Table_name Column_name ,和 Routine_name 列不能包含通配符或空白。

服务器排序 tables_priv columns_priv 以及 procs_priv 基于表 Host Db User 列。 这与 db 表排序 类似 ,但更简单,因为只有 Host 列可以包含通配符。

服务器使用已排序的表来验证它收到的每个请求。 对于需要管理权限(例如 SHUTDOWN RELOAD )的 请求, 服务器仅检查 user global_privilege 表,因为这些是唯一指定管理权限的表。 如果这些表中的帐户行允许所请求的操作,则服务器授予访问权限,否则拒绝访问。 例如,如果要执行 mysqladmin shutdown 但是您的 user 表行不授予 SHUTDOWN 您权限,则服务器会在不检查 db 表的 情况下拒绝访问 (后一个表中没有 Shutdown_priv 列,所以没有必要检查它。)

对于与数据库相关的请求( INSERT UPDATE 等等),服务器首先检查用户在 user 表行中 的全局特权 (减少部分撤销所施加的任何特权限制)。 如果该行允许所请求的操作,则授予访问权限。 如果 user 表中 的全局特权 不足,则服务器 表中确定用户的特定于数据库的特权 db

该服务器会在 db 表上的匹配 Host Db 以及 User 列。 Host User 列对应连接用户的主机名和MySQL用户名。 Db 列与用户想要访问的数据库匹配。 如果没有排为 Host User ,访问被拒绝。

确定 db 表行 授予的特定于数据库的权限后 ,服务器会将它们添加到 user 授予的全局权限 中。 如果结果允许所请求的操作,则授予访问权限。 否则,服务器会依次检查用户在 tables_priv columns_priv 表中 的表和列权限 ,将这些权限添加到用户的权限,并根据结果允许或拒绝访问。 对于存储例程操作,服务器使用 procs_priv 表而不是 tables_priv columns_priv

以布尔术语表示,前面关于如何计算用户权限的描述可以总结如下:

全球特权
OR(数据库权限和主机权限)
或表权限
OR列权限
或例行特权

可能不明显的是,如果最初发现全局特权不足以满足所请求的操作,则服务器稍后会将这些特权添加到数据库,表和列特权。 原因是请求可能需要多种类型的权限。 例如,如果执行 INSERT INTO ... SELECT 语句,则需要 INSERT SELECT 权限。 您的权限可能是这样的, user 表行授予一个全局权限和 db table row专门为相关数据库授予另一个。 在这种情况下,您具有执行请求所需的权限,但服务器无法单独使用全局或数据库权限。 它必须根据组合的权限做出访问控制决策。

6.2.8添加帐户,分配权限和删除帐户

要管理MySQL帐户,请使用用于此目的的SQL语句:

帐户管理语句使服务器对基础授权表进行适当的修改,这将在 第6.2.3节“授权表” 中讨论

注意

使用诸如 ,或者 不鼓励的 语句直接修改授权表 INSERT 并且风险自负。 服务器可以自由忽略由于此类修改而变得格式错误的行。 UPDATE DELETE

对于修改授权表的任何操作,服务器检查该表是否具有预期结构,否则生成错误。 要将表更新为预期结构,请执行MySQL升级过程。 请参见 第2.11节“升级MySQL”

创建帐户的另一个选择是使用GUI工具MySQL Workbench。 此外,一些第三方程序提供MySQL帐户管理功能。 phpMyAdmin 是一个这样的计划。

本节讨论以下主题:

有关此处讨论的语句的其他信息,请参见 第13.7.1节“帐户管理语句”

创建帐户和授予权限

以下示例显示如何使用 mysql 客户端程序设置新帐户。 这些示例假定MySQL root 帐户具有 CREATE USER 其授予其他帐户 权限和所有权限。

在命令行,以MySQL root 用户 身份连接到服务器 ,在密码提示符下提供相应的密码:

shell> mysql -u root -p
输入密码:(enter root password here)

连接到服务器后,您可以添加新帐户。 以下示例使用 CREATE USER GRANT 语句设置四个帐户(您可以看到 ,替换适当的密码): 'password'

创建用户'finley'@'localhost'
  识别' password';
全部授予
  上 *。*
  去'finley'@'localhost'
  WITH GRANT OPTION;

创建用户'finley'@'%.example.com'
  识别' password';
全部授予
  上 *。*
  去'finley'@'%.example.com'
  WITH GRANT OPTION;

创建用户'admin'@'localhost'
  识别' password';
GRANT RELOAD,PROCESS
  上 *。*
  TO'admin'@'localhost';

创建用户'dummy'@'localhost';

这些语句创建的帐户具有以下属性:

  • 两个帐户的用户名为 finley 两者都是具有完全全局权限的超级用户帐户,可以执行任 'finley'@'localhost' 只有从本地主机连接时才能使用 帐户。 'finley'@'%.example.com' 帐户 '%' 在主机部分中 使用 通配符,因此可用于从 example.com 域中的 任何主机进行连接

    'finley'@'localhost' 如果有匿名用户帐户,则 帐户是必需的 localhost 如果没有该 'finley'@'localhost' 帐户, finley 则从本地主机连接 时该匿名用户帐户优先 finley 并被视为匿名用户。 这样做的原因是匿名用户帐户具有 Host 'finley'@'%' 帐户 更具体的 列值 ,因此在 user 表格排序顺序中 更早出现 (有关 user 表排序的 信息 ,请参见 第6.2.6节“访问控制,第1阶段:连接验证” 。)

  • 'admin'@'localhost' 帐户只能用于 admin 从本地主机进行连接。 它被授予全局 RELOAD PROCESS 管理权限。 这些特权使 admin 用户能够执行 mysqladmin reload mysqladmin refresh mysqladmin flush- xxx 命令,以及 mysqladmin processlist 没有授予访问任何数据库的权限。 您可以使用 GRANT 语句 添加此类权限

  • 'dummy'@'localhost' 帐户没有密码(这是不安全的,不推荐)。 此帐户只能用于从本地主机进行连接。 没有授予任何权限。 假设您将使用 GRANT 语句 向帐户授予特定权限

前面的示例在全局级别授予权限。 下一个示例创建三个帐户并授予他们较低级别的访问权限; 也就是说,对于数据库中的特定数据库或对象。 每个帐户的用户名都是 custom ,但主机名部分不同:

创建用户'自定义'@'localhost'
  识别' password';
全部授予
  在银行帐户。*
  ''custom'@'localhost';

创建用户'custom'@'host47.example.com'
  识别' password';
GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
  开支。*
  到'custom'@'host47.example.com';

创建用户'custom'@'%.example.com'
  识别' password';
GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
  在customer.addresses上
  去'custom'@'%.example.com';

这三个帐户可以使用如下:

  • 'custom'@'localhost' 帐户具有访问 bankaccount 数据库的 所有数据库级权限 该帐户可用于仅从本地主机连接到服务器。

  • 'custom'@'host47.example.com' 帐户具有访问 expenses 数据库的 特定数据库级权限 该帐户可用于仅从主机连接到服务器 host47.example.com

  • 'custom'@'%.example.com' 帐户具有特定的表级权限,可以 域中的 任何主机 访问 数据库中 addresses 由于 在帐户名称的主机部分中 使用 通配符, 该帐户可用于从域中的所有计算机连接到服务器 customer example.com %

检查帐户权限和属性

要查看帐户的权限,请使用 SHOW GRANTS

MySQL的> SHOW GRANTS FOR 'admin'@'localhost';
+ ------------------------------------------------- ---- +
| admin @ localhost的补助金
+ ------------------------------------------------- ---- +
| GRANT RELOAD,PROCESS ON *。* TO'admin'@'localhost'|
+ ------------------------------------------------- ---- +

要查看帐户的非特权属性,请使用 SHOW CREATE USER

mysql> SET print_identified_with_as_hex = ON;
mysql>SHOW CREATE USER 'admin'@'localhost'\G
*************************** 1。排******************** *******
admin @ localhost的CREATE USER:CREATE USER'admin'@'localhost'
通过'caching_sha2_password'识别
AS 0x24412430303524301D0E17054E2241362B1419313C3E44326F294133734B30792F436E77764270373039612E32445250786D43594F45354532324B6169794F47457852796E32
要求无密码存款违约帐户解锁
密码历史默认
密码重复使用间隔默认值
密码要求当前默认值

启用 print_identified_with_as_hex 系统变量(从MySQL 8.0.17开始提供)会导致 SHOW CREATE USER 显示包含不可打印字符的哈希值作为十六进制字符串而不是常规字符串文字。

撤销帐户权限

要撤消帐户权限,请使用该 REVOKE 语句。 权限可以在不同级别撤销,就像可以在不同级别授予权限一样。

撤销全球特权:

全力以赴
  上 *。*
  来自'finley'@'%.example.com';

REVOKE RELOAD
  上 *。*
  来自'admin'@'localhost';

撤消数据库级权限:

REVOKE CREATE,DROP
  开支。*
  来自'custom'@'host47.example.com';

撤消表级权限:

REVOKE INSERT,UPDATE,DELETE
  在customer.addresses上
  来自'custom'@'%.example.com';

要检查权限撤销的效果,请使用 SHOW GRANTS

MySQL的> SHOW GRANTS FOR 'admin'@'localhost';
+ --------------------------------------------- +
| admin @ localhost的补助金
+ --------------------------------------------- +
| GRANT PROCESS ON *。* TO'admin'@'localhost'|
+ --------------------------------------------- +

丢弃帐户

要删除帐户,请使用该 DROP USER 语句。 例如,要删除之前创建的一些帐户:

DROP USER'finley'@'localhost';
DROP USER'finley'@'%.example.com';
DROP USER'admin'@'localhost';
DROP USER'dummy'@'localhost';

6.2.9预留账户

MySQL安装过程的一部分是数据目录初始化(请参见 第2.10.1节“初始化数据目录” )。 在数据目录初始化期间,MySQL会创建应被视为保留的用户帐户:

  • 'root'@'localhost :用于管理目的。 此帐户具有所有权限,是系统帐户,可以执行任何操作。

    严格地说,此帐户名称不是保留的,因为某些安装会将 root 帐户 重命名为 其他名称,以避免使用众所周知的名称公开具有高权限的帐户。

  • 'mysql.sys'@'localhost' :作为 DEFINER sys 架构对象。 使用该 mysql.sys 帐户可避免DBA重命名或删除 root 帐户时 出现的问题 此帐户已锁定,因此无法用于客户端连接。

  • 'mysql.session'@'localhost' :由插件内部使用以访问服务器。 此帐户已锁定,因此无法用于客户端连接。 该帐户是系统帐户。

  • 'mysql.infoschema'@'localhost' :作为 DEFINER INFORMATION_SCHEMA 意见。 使用该 mysql.infoschema 帐户可避免DBA重命名或删除root帐户时出现的问题。 此帐户已锁定,因此无法用于客户端连接。

6.2.10使用角色

MySQL角色是一组命名的特权。 与用户帐户一样,角色可以拥有授予和撤消的权限。

可以为用户帐户授予角色,该角色向帐户授予与每个角色关联的权限。 这样可以为帐户分配权限集,并为授予个人权限提供了一种方便的替代方法,既可以概念化所需的权限分配,也可以实现它们。

以下列表总结了MySQL提供的角色管理功能:

有关各个角色操作语句(包括使用它们所需的权限)的描述,请参见 第13.7.1节“帐户管理语句” 以下讨论提供了角色使用的示例。 除非另有说明,否则此处显示的SQL语句应使用具有足够管理权限的MySQL帐户执行,例如 root 帐户。

创建角色并授予他们权限

考虑这种情况:

  • 应用程序使用名为的数据库 app_db

  • 与应用程序相关联,可以为创建和维护应用程序的开发人员以及与之交互的用户提供帐户。

  • 开发人员需要对数据库的完全访问权限。 有些用户只需要读访问权限,有些用户需要读/写访问权限。

要避免单独为可能的许多用户帐户授予权限,请将角色创建为所需权限集的名称。 这样,通过授予适当的角色,可以轻松地向用户帐户授予所需的权限。

要创建角色,请使用以下 CREATE ROLE 语句:

CREATE ROLE'app_developer','app_read','app_write';

角色名称与用户帐户名称非常相似,并且由 格式 的用户部分和主机部分组成 主机部分(如果省略)默认为 用户和主机部件可以不加引号,除非它们包含特殊字符,如 与帐户名称不同,角色名称的用户部分不能为空。 有关其他信息,请参见 第6.2.5节“指定角色名称” 'user_name'@'host_name' '%' - %

要为角色​​分配权限,请 GRANT 使用与为用户帐户分配权限相同的语法 执行 语句:

全部授予app_db。* TO'app_developer';
GRANT SELECT ON app_db。* TO'app_read';
GRANT INSERT,UPDATE,DELETE ON app_db。* TO'app_write';

现在假设您最初需要一个开发人员帐户,两个需要只读访问权限的用户帐户,以及一个需要读/写访问权限的用户帐户。 使用 CREATE USER 创建帐户:

创建用户'dev1'@'localhost'IDENTIFIED BY'dev1pass';
CREATE USER'read_user1'@'localhost'IDENTIFIED BY'read_user1pass';
CREATE USER'read_user2'@'localhost'IDENTIFIED BY'read_user2pass';
创建用户'rw_user1'@'localhost'IDENTIFIED BY'rw_user1pass';

要为每个用户帐户分配所需的权限,您可以使用 GRANT 与刚才显示的相同表单的语句,但这需要枚举每个用户的个人权限。 相反,使用 GRANT 允许授予角色而不是特权 的替代 语法:

GRANT'app_developer'TO'dev1'@'localhost';
GRANT'app_read'TO'read_user1'@'localhost','read_user2'@'localhost';
GRANT'app_read','app_write'TO'rw_user1'@'localhost';

帐户 GRANT 语句 rw_user1 授予读取和写入角色,这些角色组合在一起以提供所需的读写权限。

GRANT 授予角色的帐户语法不同的语法授予权限:有一个 ON 分配的特权条款,而没有 ON 子句来分配角色。 由于语法是不同的,因此您不能在同一语句中混合使用赋予权限和角色。 (允许为帐户分配权限和角色,但必须使用单独的 GRANT 语句,每个语句的语法都与要授予的语句相适应。)从MySQL 8.0.16开始,不能将角色授予匿名用户。

创建时的角色已锁定,没有密码,并被分配了默认的身份验证插件。 ALTER USER 具有全局 CREATE USER 权限 的用户 可以稍后使用该 语句 更改这些角色属性 。)

锁定时,不能使用角色对服务器进行身份验证。 如果解锁,则可以使用角色进行身份验证。 这是因为角色和用户都是授权标识符,它们有很多共同之处,很难区分它们。 另请参见 用户和角色互换性

定义强制性角色

通过在 mandatory_roles 系统变量 的值中命名角色,可以将角色指定为必需角色 服务器将强制角色视为授予所有用户,因此不需要将其明确授予任何帐户。

要在服务器启动时指定强制角色,请 mandatory_roles 在服务器 my.cnf 文件中 定义

的[mysqld]
mandatory_roles = '基于role1,基于role2 @本地,R3 @%。example.com'

mandatory_roles 在运行时 设置和保持 ,请使用如下语句:

SET PERSIST mandatory_roles ='role1,role2 @ localhost,r3 @%。example.com';

SET PERSIST 设置正在运行的MySQL实例的值。 它还会保存该值,使其用于后续服务器重新启动。 要更改正在运行的MySQL实例的值而不保存它以便后续重新启动,请使用 GLOBAL 关键字而不是 PERSIST 请参见 第13.7.5.1节“变量赋值的SET语法”

除了 通常设置全局系统变量所需的权限 权限 之外, 设置还 mandatory_roles 需要 ROLE_ADMIN 权限 SYSTEM_VARIABLES_ADMIN SUPER

强制角色(如明确授予的角色)在激活之前不会生效(请参阅 激活角色 )。 在登录时,如果 activate_all_roles_on_login 启用 系统变量,则 对所有授予的角色 进行角色激活,否则对于设置为默认角色的角色进行角色激活。 在运行时, SET ROLE 激活角色。

在值命名的角色 mandatory_roles 不能被撤销 REVOKE 或下降 DROP ROLE DROP USER

要防止会话默认为系统会话,具有该 SYSTEM_USER 权限 的角色 不能列在 mandatory_roles 系统变量 的值中

如果 系统表中 mandatory_roles 不存在 名为in的角色, 则不会 mysql.user 将该角色授予用户。 当服务器尝试为用户激活角色时,它不会将不存在的角色视为必需角色,并会向错误日志写入警告。 如果角色稍后创建并因此变为有效,则 FLUSH PRIVILEGES 可能需要使服务器将其视为必需 角色

SHOW GRANTS 根据 第13.7.6.21节“SHOW GRANTS语法”中 描述的规则显示强制角色

检查角色权限

要验证分配给帐户的权限,请使用 SHOW GRANTS 例如:

MySQL的> SHOW GRANTS FOR 'dev1'@'localhost';
+ ------------------------------------------------- +
| dev1 @ localhost的补助金
+ ------------------------------------------------- +
| 授予*。*给'dev1` @`localhost` |
| GRANT`app_developer` @`%`to`dev1` @`localhost` |
+ ------------------------------------------------- +

但是,这会显示每个已授予的角色,而不 会将其 扩展 为角色所代表的权限。 要显示角色权限,请添加一个 USING 子句,命名要为其显示权限的已授予角色:

MySQL的> SHOW GRANTS FOR 'dev1'@'localhost' USING 'app_developer';
+ ------------------------------------------------- --------- +
| dev1 @ localhost的补助金
+ ------------------------------------------------- --------- +
| 授予*。*给'dev1` @`localhost` |
| 在`app_db`上授予所有特权。*到`dev1` @`localhost` |
| GRANT`app_developer` @`%`to`dev1` @`localhost` |
+ ------------------------------------------------- --------- +

同样验证每个其他类型的用户:

MySQL的> SHOW GRANTS FOR 'read_user1'@'localhost' USING 'app_read';
+ ------------------------------------------------- ------- +
| 资助read_user1 @ localhost |
+ ------------------------------------------------- ------- +
| 授予使用*。*给`read_user1` @`localhost` |
| GRANT SELECT ON`app_db`。* to`read_user1` @`localhost` |
| GRANT`app_read` @`%`to`read_user1` @`localhost` |
+ ------------------------------------------------- ------- +
MySQL的> SHOW GRANTS FOR 'rw_user1'@'localhost' USING 'app_read', 'app_write';
+ ------------------------------------------------- ----------------------------- +
| 为rw_user1 @ localhost |授予补助金
+ ------------------------------------------------- ----------------------------- +
| 授予使用*。*给`rw_user1` @`localhost` |
| GRANT SELECT,INSERT,UPDATE,DELETE ON` app_db`。* to`rw_user1` @`localhost` |
| GRANT`app_read` @`%`,`app_write` @`%`to`rw_user1` @`localhost` |
+ ------------------------------------------------- ----------------------------- +

SHOW GRANTS 根据 第13.7.6.21节“SHOW GRANTS语法”中 描述的规则显示强制角色

激活角色

授予用户帐户的角色可以在帐户会话中处于活动状态或非活动状态。 如果授予的角色在会话中处于活动状态,则其权限适用; 否则,他们没有。 要确定当前会话中哪些角色处于活动状态,请使用该 CURRENT_ROLE() 功能。

默认情况下,向帐户授予角色或在 mandatory_roles 系统变量值中 命名 角色不会自动导致角色在帐户会话中变为活动状态。 例如,因为在前面的讨论中到目前为止 rw_user1 还没有激活 任何 角色,如果您连接到服务器 rw_user1 并调用该 CURRENT_ROLE() 函数,结果是 NONE (没有活动角色):

MySQL的> SELECT CURRENT_ROLE();
+ ---------------- +
| CURRENT_ROLE()|
+ ---------------- +
| 没有|
+ ---------------- +

要指定每次用户连接到服务器并进行身份验证时哪些角色应处于活动状态,请使用 SET DEFAULT ROLE 要将默认设置为先前创建的每个帐户的所有已分配角色,请使用以下语句:

将DEFAULT ROLE ALL设置为
  'DEV1' @ 'localhost' 的,
  'read_user1' @ 'localhost' 的,
  'read_user2' @ 'localhost' 的,
  'rw_user1' @ '本地主机';

现在,如果您连接为 rw_user1 ,则初始值 CURRENT_ROLE() 反映新的默认角色分配:

MySQL的> SELECT CURRENT_ROLE();
+ -------------------------------- +
| CURRENT_ROLE()|
+ -------------------------------- +
| `app_read` @`%`,`app_write` @`%`|
+ -------------------------------- +

要在用户连接到服务器时自动激活所有显式授权和强制角色,请启用 activate_all_roles_on_login 系统变量。 默认情况下,禁用自动角色激活。

在会话中,用户可以执行 SET ROLE 以更改活动角色集。 例如,对于 rw_user1

MySQL的> SET ROLE NONE; SELECT CURRENT_ROLE();
+ ---------------- +
| CURRENT_ROLE()|
+ ---------------- +
| 没有|
+ ---------------- +
MySQL的> SET ROLE ALL EXCEPT 'app_write'; SELECT CURRENT_ROLE();
+ ---------------- +
| CURRENT_ROLE()|
+ ---------------- +
| `app_read` @`%`|
+ ---------------- +
MySQL的> SET ROLE DEFAULT; SELECT CURRENT_ROLE();
+ -------------------------------- +
| CURRENT_ROLE()|
+ -------------------------------- +
| `app_read` @`%`,`app_write` @`%`|
+ -------------------------------- +

第一个 SET ROLE 语句停用所有角色。 第二个 rw_user1 有效地只读。 第三个恢复默认角色。

存储的程序和视图对象的有效用户受到 DEFINER SQL SECURITY 属性的 约束,这些 属性确定执行是在调用者或定义者上下文中发生的(参见 第24.6节“存储对象访问控制” ):

  • 在调用程序上下文中执行的存储程序和视图对象使用当前会话中处于活动状态的角色执行。

  • 在定义上下文中执行的存储程序和视图对象使用其 DEFINER 属性中 命名的用户的默认角色执行 如果 activate_all_roles_on_login 启用,则此类对象将执行授予 DEFINER 用户的 所有角色 ,包括强制角色。 对于存储的程序,如果执行的角色与默认角色不同,则应执行程序体 SET ROLE 以激活所需的角色。

撤消角色或角色权限

正如角色可以授予帐户一样,可以从帐户中撤消它们:

REVOKE roleFROM user;

mandatory_roles 系统变量值中 命名的角色 无法撤消。

REVOKE 也可以应用于角色以修改授予它的权限。 这不仅会影响角色本身,还会影响授予该角色的任何帐户。 假设您要暂时使所有应用程序用户只读。 为此,请使用 REVOKE 以撤消 app_write 角色 的修改权限

REVOKE INSERT,UPDATE,DELETE ON app_db。* FROM'app_write';

实际上,这使得角色完全没有特权,正如可以看到的那样 SHOW GRANTS (这表明该语句可以与角色一起使用,而不仅仅是用户):

MySQL的> SHOW GRANTS FOR 'app_write';
+ --------------------------------------- +
| 为app_write @%|授予补助金
+ --------------------------------------- +
| 使用*。*来'app_write` @`%`|
+ --------------------------------------- +

因为从角色中撤销特权会影响谁被分配了修改角色的任何用户的权限, rw_user1 现在已经没有表修改权限( INSERT UPDATE ,和 DELETE 不再存在):

MySQL的> SHOW GRANTS FOR 'rw_user1'@'localhost'
       USING 'app_read', 'app_write';
+ ------------------------------------------------- --------------- +
| 为rw_user1 @ localhost |授予补助金
+ ------------------------------------------------- --------------- +
| 授予使用*。*给`rw_user1` @`localhost` |
| GRANT SELECT ON`app_db`。* to`rw_user1` @`localhost` |
| GRANT`app_read` @`%`,`app_write` @`%`to`rw_user1` @`localhost` |
+ ------------------------------------------------- --------------- +

实际上, rw_user1 读/写用户已成为只读用户。 对于授予该 app_write 角色的 任何其他帐户也会发生这种情况 ,说明如何使用角色使得不必修改个人帐户的权限。

要恢复角色的修改权限,只需重新授予它们:

GRANT INSERT,UPDATE,DELETE ON app_db。* TO'app_write';

现在 rw_user1 再次具有修改权限,授予该 app_write 角色的 任何其他帐户也是如此

放下角色

要删除角色,请使用 DROP ROLE

DROP ROLE'app_read','app_write';

删除角色会从授予它的每个帐户撤消该角色。

mandatory_roles 无法删除 系统变量值中 命名的角色

用户和角色互换性

正如之前所暗示的那样 SHOW GRANTS ,它显示了用户帐户或角色的授权,帐户和角色可以互换使用。

角色和用户之间的一个区别是 CREATE ROLE 创建默认锁定 CREATE USER 的授权标识符 ,而 创建默认情况下解锁的授权标识符。 但是,区别不是不可变的,因为具有适当权限的用户可以在创建角色或用户后锁定或解锁它们。

如果数据库管理员具有特定授权标识符必须是角色的首选项,则可以使用名称方案来传达此意图。 例如,您可以 r_ 为您打算成为角色的所有授权标识符 使用 前缀 ,而不使用 任何其他内容。

角色和用户之间的另一个区别在于可用于管理它们的权限:

因此, CREATE ROLE DROP ROLE 权限不会像 CREATE USER 只允许创建和删除角色的用户 那样强大 并且可能被授予权限,并且不会执行更一般的帐户操作。

关于用户和角色的权限和可互换性,您可以将用户帐户视为角色,并将该帐户授予其他用户或角色。 其结果是将帐户的权限和角色授予其他用户或角色。

这组语句演示了您可以向用户授予用户权限,向用户授予角色,向角色授予用户权限,或向角色授予角色:

创建用户'u1';
创造角色'r1';
GRANT SELECT ON db1。* TO'u1';
GRANT SELECT ON db2。* TO'r1';
创建用户'u2';
创造角色'r2';
GRANT'u1','r1'到'u2';
GRANT'u1','r1'到'r2';

每种情况下的结果是向被授予者对象授予与授予对象相关联的特权。 执行这些语句之后,每个 u2 r2 已经从用户(授予的权限 u1 )和一个角色( r1 ):

MySQL的> SHOW GRANTS FOR 'u2' USING 'u1', 'r1';
+ ------------------------------- +
| u2 @%|的补助金
+ ------------------------------- +
| 使用*。*给'u2` @`%`|
| GRANT SELECT ON`db1`。* TO`u2` @`%`|
| GRANT选择`db2`。* TO`u2` @`%`|
| GRANT`u1` @`%`,`r1` @`%`to`u2` @`%`|
+ ------------------------------- +
MySQL的> SHOW GRANTS FOR 'r2' USING 'u1', 'r1';
+ ------------------------------- +
| r2 @%|的补助金
+ ------------------------------- +
| 授予使用*。*至`r2` @`%`|
| GRANT选择`db1`。* TO`r2` @`%`|
| GRANT选择`db2`。* to`r2` @`%`|
| GRANT`u1` @`%`,`r1` @`%`to`r2` @`%`|
+ ------------------------------- +

前面的示例仅是说明性的,但用户帐户和角色的可互换性具有实际应用,例如在以下情况中:假设遗留应用程序开发项目在MySQL中的角色出现之前开始,因此与项目关联的所有用户帐户都是直接授予权限(而不是通过授予角色授予权限)。 其中一个帐户是最初被授予特权的开发人员帐户,如下所示:

创建用户'old_app_dev'@'localhost'识别'old_app_devpass';
在old_app上全部授予。*''old_app_dev'@'localhost';

如果此开发人员离开项目,则必须将权限分配给另一个用户,或者如果开发活动已扩展,则可能将多个用户分配。 以下是处理该问题的一些方法:

  • 不使用角色:更改帐户密码,以便原始开发人员无法使用它,并让新开发人员使用该帐户:

    ALTER USER'old_app_dev'@'localhost'ENFENTIFIED BY' new_password';
    
  • 使用角色:锁定帐户以防止任何人使用它来连接到服务器:

    ALTER USER'old_app_dev'@'localhost'ACCOUNT LOCK;
    

    然后将该帐户视为一个角色。 对于项目的每个新开发人员,创建一个新帐户并向其授予原始开发人员帐户:

    CREATE USER'new_app_dev1'@'localhost'ENFENTIFIED BY' new_password';
    GRANT'old_app_dev'@'localhost'TO'new_app_dev1'@'localhost';
    

    效果是将原始开发者帐户权限分配给新帐户。

6.2.11帐户类别

从MySQL 8.0.16开始,MySQL基于 SYSTEM_USER 特权 结合了用户帐户类别的概念

系统和常规账户

MySQL结合了用户帐户类别的概念,系统和常规用户根据他们是否拥有 SYSTEM_USER 权限进行 区分

  • 具有该 SYSTEM_USER 权限的用户是系统用户。

  • 没有 SYSTEM_USER 权限的用户是普通用户。

SYSTEM_USER 权限对给定用户可以应用其他权限的帐户有影响,以及用户是否受到其他帐户的保护:

  • 系统用户可以修改系统和常规帐户。 也就是说,拥有对常规帐户执行给定操作的适当权限的用户通过拥有 SYSTEM_USER 也可以对系统帐户执行操作来 启用 系统帐户只能由具有适当权限的系统用户修改,而不能由常规用户修改。

  • 具有适当权限的常规用户可以修改常规帐户,但不能修改系统帐户。 具有适当权限的系统和常规用户都可以修改常规帐户。

如果用户具有在常规帐户上执行给定操作的适当权限,则 SYSTEM_USER 允许用户还对系统帐户执行操作。 SYSTEM_USER 并不意味着任何其他特权,因此执行给定帐户操作的能力仍然取决于拥有任何其他所需特权。 例如,如果用户可以授予 常规帐户 SELECT UPDATE 权限,那么 SYSTEM_USER 用户也可以授予 SELECT UPDATE 系统帐户。

通过保护具有 SYSTEM_USER 来自 没有该 权限的帐户 权限的帐户, 系统和常规帐户之间的区别可以更好地控制某些帐户管理问题 例如,该 CREATE USER 权限不仅可以创建新帐户,还可以修改和删除现有帐户。 如果没有系统用户概念,拥有该 CREATE USER 权限 的用户 可以修改或删除任何现有帐户,包括该 root 帐户。 系统用户的概念允许限制对 root 帐户(本身是系统帐户)的 修改, 因此它们只能由系统用户进行。 定期用户 CREATE USER 权限仍然可以修改或删除现有帐户,但只能修改或删除常规帐户。

受SYSTEM_USER权限影响的操作

SYSTEM_USER 权限会影响这些操作:

  • 帐户操纵。

    帐户操作包括创建和删除帐户,授予和撤消权限,更改帐户身份验证特征(如凭据或身份验证插件)以及更改其他帐户特征(如密码到期策略)。

    SYSTEM_USER 使用帐户管理语句(例如 CREATE USER 和) 操纵系统帐户需要 权限 GRANT 要防止帐户以这种方式修改系统帐户,请将其设为常规帐户,而不是授予其 SYSTEM_USER 权限。 (但是,要完全保护系统帐户不受常规帐户的影响,您还必须保留对常规帐户 mysql 系统架构的 修改权限 。请参阅 保护系统帐户 免受常规帐户 操作 。)

  • 杀死当前会话和在其中执行的语句。

    要杀死使用该 SYSTEM_USER 权限 执行的会话或语句, SYSTEM_USER 除了任何其他所需权限外 ,您自己的会话还必须具有该 权限( CONNECTION_ADMIN SUPER

    在MySQL 8.0.16之前, CONNECTION_ADMIN 或者 SUPER 足以杀死任何会话或语句。

  • 设置 DEFINER 存储的对象。

    要将 DEFINER 存储对象 属性 设置 为具有该 SYSTEM_USER 权限 的帐户, SYSTEM_USER 除了任何其他所需权限之外 ,您还必须具有该 权限( SET_USER_ID 或者 SUPER

    在MySQL 8.0.16之前, SET_USER_ID 或者 SUPER 足以 DEFINER 为存储对象 指定任何 值。

  • 指定强制角色。

    具有该 SYSTEM_USER 权限的 角色 不能列在该值中 mandatory_roles 系统变量

    在MySQL 8.0.16之前,可以列出任何角色 mandatory_roles

系统和常规会话

在服务器内执行的会话被区分为系统或常规会话,类似于系统和常规用户之间的区别:

  • 拥有该 SYSTEM_USER 权限的会话是系统会话。

  • 不具有 SYSTEM_USER 权限的会话是常规会话。

常规会话只能执行常规用户允许的操作。 系统会话还能够执行仅允许系统用户执行的操作。

会话拥有的权限是直接授予其基础帐户的权限,以及授予会话中当前活动的所有角色的权限。 因此,会话可能是系统会话,因为其帐户已被 SYSTEM_USER 直接 授予 权限,或者因为会话已激活具有 以下 权限的角色 SYSTEM_USER 特权 授予会话中未激活的帐户的角色不会影响会话权限。

由于激活和停用角色可以更改会话拥有的权限,因此会话可以从常规会话更改为系统会话,反之亦然。 如果会话激活或停用具有该 SYSTEM_USER 权限 的角色, 则会立即在该会话中立即进行常规会话和系统会话之间的适当更改:

  • 如果常规会话使用该 SYSTEM_USER 权限 激活角色 ,则会话将成为系统会话。

  • 如果系统会话取消激活具有该 SYSTEM_USER 权限 的角色 ,则会话将成为常规会话,除非具有该 SYSTEM_USER 权限的 其他某个角色 保持活动状态。

这些操作对现有会话没有影响:

  • 如果 SYSTEM_USER 从帐户授予或撤消权限,则帐户的现有会话在常规会话和系统会话之间不会更改。 授予或撤消操作仅影响帐户后续连接的会话。

  • 由会话中调用的存储对象执行的语句以系统或父会话的常规状态执行,即使对象 DEFINER 属性命名系统帐户也是如此。

由于角色激活仅影响会话而非影响帐户,因此授予具有 SYSTEM_USER 常规帐户权限 的角色 不会保护该帐户免受常规用户的影响。 该角色仅保护已激活角色的帐户的会话,并仅保护会话,防止被常规会话杀死。

保护系统帐户免受普通帐户的操纵

帐户操作包括创建和删除帐户,授予和撤消权限,更改帐户身份验证特征(如凭据或身份验证插件)以及更改其他帐户特征(如密码到期策略)。

帐户操作可以通过两种方式完成:

  • 通过使用账户管理语句,例如 CREATE USER GRANT 这是首选方法。

  • 通过使用 INSERT 等语句直接授予表修改 UPDATE 不鼓励使用此方法,但对于 mysql 包含授权表 系统架构 具有适当权限的用户可以使用此方法

要完全保护系统帐户不被给定帐户修改,请将其设为常规帐户,并且不授予其对 mysql 架构的 修改权限

  • SYSTEM_USER 使用帐户管理语句操作系统帐户需要 权限。 要防止帐户以这种方式修改系统帐户,请通过不授予帐户使其成为常规帐户 SYSTEM_USER 这包括不授予 SYSTEM_USER 授予该帐户的任何角色。

  • mysql 即使修改帐户是常规帐户 模式的 权限也可以 通过直接修改授权表来操作系统帐户。 要限制通过常规帐户对系统帐户进行​​未经授权的直接修改,请不要将 mysql 架构的 修改权限授予 帐户(或授予该帐户的任何角色)。 如果常规帐户必须具有适用于所有模式的全局特权, mysql 则可以使用部分撤消强加的特权限制来防止模式修改。 请参见 第6.2.12节“使用部分撤消的权限限制”

注意

与扣除 SYSTEM_USER 权限(防止帐户修改系统帐户而非常规帐户)不同,隐藏 mysql 模式权限会阻止帐户修改系统帐户以及常规帐户。 这应该不是问题,因为如上所述,不鼓励直接授权表修改。

假设您要创建一个 u1 对所有模式具有所有权限 的用户 ,除了 u1 应该是普通用户而无法修改系统帐户。 假设 partial_revokes 启用 系统变量,请 u1 按如下方式 配置

创建用户u1标识' password';

全部授予*。*至u1 with GRANT OPTION;
-  GRANT ALL包括SYSTEM_USER,所以此时
-  u1可以操纵系统或常规帐户

REVOKE SYSTEM_USER ON *。* FROM u1;
- 撤销SYSTEM_USER使u1成为普通用户;
- 现在u1可以使用帐户管理语句
- 仅操纵常规帐户

REVOKE ALL ON mysql。* FROM u1;
- 这种部分撤销直接阻止了u1
- 修改授权表以操纵帐户

要阻止 mysql 帐户进行 所有 系统架构访问,请撤消对 mysql 架构的 所有权限 ,如刚才所示。 还可以允许部分 mysql 模式访问,例如只读访问。 下面的示例创建具有一个帐户 SELECT INSERT UPDATE ,和 DELETE 特权全球范围内为所有的模式,但只 SELECT mysql 模式:

创建用户u2标识' password';
GRANT SELECT,INSERT,UPDATE,DELETE ON *。* TO u2;
REVOKE INSERT,UPDATE,DELETE ON mysql。* FROM u2;

另一种可能性是撤消所有 mysql 模式权限,但授予对特定 mysql 表或列的 访问权限 即使部分撤销,也可以这样做 mysql 以下语句启用 u1 mysql 模式 内的 只读访问权限 ,但仅对 db 表的表 Host User 列进行 user

创建用户u3标识' password';
全部授予*。*至u3;
REVOKE ALL ON mysql。* FROM u3;
GRANT SELECT on mysql.db TO u3;
GRANT SELECT(主机,用户)ON mysql.user TO u3;

6.2.12使用部分撤销权限的权限限制

在MySQL 8.0.16之前,除了某些模式之外,不可能授予全局适用的权限。 从MySQL 8.0.16开始,如果 partial_revokes 启用 系统变量 ,则可以 实现。 具体而言,对于具有全局级别权限的用户, partial_revokes 可以撤消特定模式的权限,同时为其他模式保留特权。 这样强加的权限限制可能对管理具有全局权限但不允许访问某些模式的帐户有用。 例如,可以允许帐户修改除 mysql 系统架构 中的表之外的任何表

注意

为简洁起见, CREATE USER 此处显示的语句不包括密码。 对于生产用途,请始终指定帐户密码。

使用部分撤消

partial_revokes 系统变量控制权限限制是否可以放在账户。 默认情况下, partial_revokes 禁用并尝试部分撤消全局权限会产生错误:

mysql> CREATE USER u1;
mysql> GRANT SELECT, INSERT ON *.* TO u1;
mysql>REVOKE INSERT ON world.* FROM u1;
ERROR 1141(42000):在主机'%'上没有为用户'u1'定义此类授权

要允许 REVOKE 操作,请启用 partial_revokes

SET PERSIST partial_revokes = ON;

SET PERSIST 设置正在运行的MySQL实例的值。 它还会保存该值,使其用于后续服务器重新启动。 要更改正在运行的MySQL实例的值而不保存它以便后续重新启动,请使用 GLOBAL 关键字而不是 PERSIST 请参见 第13.7.5.1节“变量赋值的SET语法”

partial_revokes 启用,部分撤销成功:

mysql> REVOKE INSERT ON world.* FROM u1;
mysql>SHOW GRANTS FOR u1;
+ ------------------------------------------ +
| 为u1 @%|拨款
+ ------------------------------------------ +
| GRANT SELECT,INSERT ON *。* to`u1` @`%`|
| REVOKE INSERT ON`world`。* FROM`u1` @`%`|
+ ------------------------------------------ +

SHOW GRANTS 列出部分撤销作为 REVOKE 其输出中的语句。 结果表明 u1 具有全局 SELECT INSERT 特权,除了 INSERT 不能对 world 模式中的 表执行 也就是说, u1 world 表的 访问 是只读的。

服务器记录通过 mysql.user 系统表 中的部分撤销实现的权限限制 如果帐户已部分撤消,则其 User_attributes 列值具有以下 Restrictions 属性:

MySQL的> SELECT User, Host, User_attributes->>'$.Restrictions'
       FROM mysql.user WHERE User_attributes->>'$.Restrictions' <> '';
+ ------ + ------ + ----------------------------------- ------------------- +
| 用户| 主持人| User_attributes  -  >>'$。限制'|
+ ------ + ------ + ----------------------------------- ------------------- +
| u1 | %| [{“数据库”:“世界”,“特权”:[“INSERT”]}] |
+ ------ + ------ + ----------------------------------- ------------------- +
注意

虽然可以对任何模式进行部分撤销 mysql ,但特别是 系统模式的 特权限制 可用作防止常规帐户修改系统帐户的策略的一部分。 请参阅 通过常规帐户保护系统帐户免受操纵

部分撤销操作受以下条件限制:

  • 部分撤销必须按字面意思命名模式。 不允许 包含 % _ SQL通配符的 模式名称 (例如 myschema% )。

  • 可以使用部分撤销对不存在的模式进行限制,但前提是全局授予撤销的特权。 如果未全局授予权限,则为不存在的模式撤消该权限会产生错误。

  • 部分撤销仅适用于架构级别。 对于仅全局(例如 FILE BINLOG_ADMIN )或表,列或例程特权 应用的特权,不能使用部分撤消

如前所述,模式级特权的部分撤销在 SHOW GRANTS 输出中 显示 REVOKE 语句。 这与 SHOW GRANTS 表示 普通 架构级特权的方式不同:

  • 授予时,模式级特权由 GRANT 输出中 的自己的 语句 表示

    mysql> CREATE USER u1;
    mysql> GRANT UPDATE ON mysql.* TO u1;
    mysql> GRANT DELETE ON world.* TO u1;
    mysql>SHOW GRANTS FOR u1;
    + --------------------------------------- +
    | 为u1 @%|拨款
    + --------------------------------------- +
    | 授予使用*。*给'u1` @`%`|
    | 授予更新`mysql`。* to`u1` @`%`|
    | GRANT DELETE ON`world`。* to`u1` @`%`|
    + --------------------------------------- +
    
  • 撤消时,架构级特权会从输出中消失。 它们不作为 REVOKE 陈述 出现

    mysql> REVOKE UPDATE ON mysql.* FROM u1;
    mysql> REVOKE DELETE ON world.* FROM u1;
    mysql>SHOW GRANTS FOR u1;
    + -------------------------------- +
    | 为u1 @%|拨款
    + -------------------------------- +
    | 授予使用*。*给'u1` @`%`|
    + -------------------------------- +
    

当用户授予权限时,授予者对该权限的任何限制都由被授权者继承,除非被授权者已经拥有没有该限制的权限。 考虑以下两个用户,其中一个用户具有全局 SELECT 权限:

创建用户u1,u2;
GRANT SELECT ON *。* TO u2;

假设管理用户 admin 具有全局但部分撤销的 SELECT 权限:

mysql> CREATE USER admin;
mysql> GRANT SELECT ON *.* TO admin WITH GRANT OPTION;
mysql> REVOKE SELECT ON mysql.* FROM admin;
mysql>SHOW GRANTS FOR admin;
+ ------------------------------------------------- ----- +
| 管理员@%|的拨款
+ ------------------------------------------------- ----- +
| GRANT SELECT ON *。* TO`admin` @`%`WITH GRANT OPTION |
| REVOKE SELECT on`mysql`。* FROM`admin` @`%`|
+ ------------------------------------------------- ----- +

如果 admin 补助 SELECT 全球范围内 u1 u2 ,其结果相差为每个用户:

  • 如果 全局 admin 授予( 权限开始),则 继承 权限限制: SELECT u1 SELECT u1 admin

    mysql> GRANT SELECT ON *.* TO u1;
    mysql>SHOW GRANTS FOR u1;
    + ------------------------------------------ +
    | 为u1 @%|拨款
    + ------------------------------------------ +
    | GRANT SELECT ON *。* TO`u1` @`%`|
    | REVOKE SELECT on`mysql`。* FROM`u1` @`%`|
    + ------------------------------------------ +
    
  • 另一方面, u2 已经拥有一个 SELECT 没有限制 的全球 特权。 GRANT 只能添加到受让人现有的特权,而不是减少他们,所以如果 admin 授予 SELECT 在全球范围内 u2 u2 不继承的 admin 限制:

    mysql> GRANT SELECT ON *.* TO u2;
    mysql>SHOW GRANTS FOR u2;
    + --------------------------------- +
    | u2 @%|的补助金
    + --------------------------------- +
    | GRANT SELECT ON *。* TO`u2` @`%`|
    + --------------------------------- +
    

如果 GRANT 语句包含 子句,则应用的权限限制是由子句指定的用户/角色组合上的权限,而不是执行该语句的用户的权限限制。 有关该 子句的 信息 ,请参见 第13.7.1.6节“GRANT语法” AS user AS

授予帐户的新权限的限制将添加到该帐户的任何现有限制中:

mysql> CREATE USER u1;
mysql> GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO u1;
mysql> REVOKE INSERT ON mysql.* FROM u1;
mysql>SHOW GRANTS FOR u1;
+ ------------------------------------------------- -------- +
| 为u1 @%|拨款
+ ------------------------------------------------- -------- +
| GRANT SELECT,INSERT,UPDATE,DELETE ON *。* TO`u1` @`%`|
| REVOKE INSERT ON`mysql`。* FROM`u1` @`%`|
+ ------------------------------------------------- -------- +
mysql> REVOKE DELETE, UPDATE ON db2.* FROM u1;
mysql>SHOW GRANTS FOR u1;
+ ------------------------------------------------- -------- +
| 为u1 @%|拨款
+ ------------------------------------------------- -------- +
| GRANT SELECT,INSERT,UPDATE,DELETE ON *。* TO`u1` @`%`|
| REVOKE UPDATE,删除`db2`。* FROM`u1` @`%`|
| REVOKE INSERT ON`mysql`。* FROM`u1` @`%`|
+ ------------------------------------------------- -------- +

特权限制聚合既适用于显式部分撤销特权(如刚才所示),也适用于从执行语句的用户或 子句中 提到的用户隐式继承限制的情况 AS user

如果帐户对架构具有权限限制:

  • 该帐户无法向其他帐户授予对受限架构或其中任何对象的特权。

  • 另一个没有限制的帐户可以为受限制的帐户或其中的对象授予受限帐户的权限。 假设一个不受限制的用户执行这些语句:

    创建用户u1;
    GRANT SELECT,INSERT,UPDATE ON *。* TO u1;
    REVOKE SELECT,INSERT,UPDATE on mysql。* FROM u1;
    GRANT SELECT ON mysql.user TO u1;  -  grant table特权
    GRANT SELECT(主机,用户)ON mysql.db TO u1;  - 授予列权限
    

    生成的帐户具有这些权限,能够在受限模式中执行有限的操作:

    MySQL的> SHOW GRANTS FOR u1;
    + ------------------------------------------------- ---------- +
    | 为u1 @%|拨款
    + ------------------------------------------------- ---------- +
    | GRANT SELECT,INSERT,UPDATE ON *。* to`u1` @`%`|
    | REVOKE SELECT,INSERT,UPDATE on`mysql`。* FROM`u1` @`%`|
    | GRANT SELECT(`Host`,`User`)on`mysql` .db` to`u1` @`%`|
    | GRANT SELECT on`mysql` .user` TO`u1` @`%`|
    + ------------------------------------------------- ---------- +
    

如果帐户对全局权限有限制,则通过以下任何操作都会删除该限制:

  • 通过对权限没有限制的帐户向帐户全局授予权限。

  • 在架构级别授予权限。

  • 全球撤销特权。

考虑一个 u1 全局拥有多个权限但受到限制的用户 INSERT UPDATE 并且 DELETE

mysql> CREATE USER u1;
mysql> GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO u1;
mysql> REVOKE INSERT, UPDATE, DELETE ON mysql.* FROM u1;
mysql>SHOW GRANTS FOR u1;
+ ------------------------------------------------- --------- +
| 为u1 @%|拨款
+ ------------------------------------------------- --------- +
| GRANT SELECT,INSERT,UPDATE,DELETE ON *。* TO`u1` @`%`|
| REVOKE INSERT,UPDATE,DELETE ON`mysql`。* FROM`u1` @`%`|
+ ------------------------------------------------- --------- +

u1 从没有限制的帐户 全局授予权限 会删除权限限制。 例如,要删除 INSERT 限制:

mysql> GRANT INSERT ON *.* TO u1;
mysql>SHOW GRANTS FOR u1;
+ ------------------------------------------------- -------- +
| 为u1 @%|拨款
+ ------------------------------------------------- -------- +
| GRANT SELECT,INSERT,UPDATE,DELETE ON *。* TO`u1` @`%`|
| REVOKE UPDATE,删除`mysql`。* FROM`u1` @`%`|
+ ------------------------------------------------- -------- +

在架构级别授予权限以 u1 删除权限限制。 例如,要删除 UPDATE 限制:

mysql> GRANT UPDATE ON mysql.* TO u1;
mysql>SHOW GRANTS FOR u1;
+ ------------------------------------------------- -------- +
| 为u1 @%|拨款
+ ------------------------------------------------- -------- +
| GRANT SELECT,INSERT,UPDATE,DELETE ON *。* TO`u1` @`%`|
| REVOKE DELETE ON`mysql`。* FROM`u1` @`%`|
+ ------------------------------------------------- -------- +

撤消全局权限会删除该权限,包括对其的任何限制。 例如,要删除 DELETE 限制(以删除所有 DELETE 访问权 为代价 ):

mysql> REVOKE DELETE ON *.* FROM u1;
mysql>SHOW GRANTS FOR u1;
+ ------------------------------------------------- +
| 为u1 @%|拨款
+ ------------------------------------------------- +
| GRANT SELECT,INSERT,UPDATE ON *。* to`u1` @`%`|
+ ------------------------------------------------- +

如果帐户在全局级别和架构级别都具有权限,则必须在架构级别将其撤消两次以实现部分撤消。 假设 u1 具有这些权限, INSERT 全局和 world 模式 都保存在 哪里

mysql> CREATE USER u1;
mysql> GRANT SELECT, INSERT ON *.* TO u1;
mysql> GRANT INSERT ON world.* TO u1;
mysql>SHOW GRANTS FOR u1;
+ ----------------------------------------- +
| 为u1 @%|拨款
+ ----------------------------------------- +
| GRANT SELECT,INSERT ON *。* to`u1` @`%`|
| GRANT INSERT ON`world`。* to`u1` @`%`|
+ ----------------------------------------- +

撤销 INSERT world 会撤销模式级特权( SHOW GRANTS 不再显示模式级 GRANT 语句):

mysql> REVOKE INSERT ON world.* FROM u1;
mysql>SHOW GRANTS FOR u1;
+ ----------------------------------------- +
| 为u1 @%|拨款
+ ----------------------------------------- +
| GRANT SELECT,INSERT ON *。* to`u1` @`%`|
+ ----------------------------------------- +

撤销 INSERT world 再次执行全局权限(的部分撤销 SHOW GRANTS ,现在包括模式级 REVOKE 语句):

mysql> REVOKE INSERT ON world.* FROM u1;
mysql>SHOW GRANTS FOR u1;
+ ------------------------------------------ +
| 为u1 @%|拨款
+ ------------------------------------------ +
| GRANT SELECT,INSERT ON *。* to`u1` @`%`|
| REVOKE INSERT ON`world`。* FROM`u1` @`%`|
+ ------------------------------------------ +

部分撤销与显式模式授权

为了提供对某些模式而非其他模式的帐户的访问,部分撤销提供了在不授予全局特权的情况下显式授予模式级访问权的方法的替代方法。 这两种方法有不同的优点和缺点。

授予模式级特权而不是全局特权:

  • 添加新架构:默认情况下,现有帐户无法访问架构。 对于应该可以访问架构的任何帐户,DBA必须授予架构级访问权限。

  • 添加新帐户:DBA必须为帐户应有权访问的每个模式授予模式级访问权限。

与部分撤销一起授予全局权限:

  • 添加新架构:具有全局特权的现有帐户可以访问架构。 对于架构应该无法访问的任何此类帐户,DBA必须添加部分撤销。

  • 添加新帐户:DBA必须授予全局权限,并且必须对每个受限制的模式进行部分撤销。

对于访问仅限于少数模式的帐户,使用显式模式级别授权的方法更方便。 对于除了少数几个以外的所有模式具有广泛访问权限的帐户,使用部分撤销的方法更方便。

禁用部分撤消

启用后, partial_revokes 如果任何帐户具有权限限制 则无法禁用。 如果存在任何此类帐户,则禁用 partial_revokes 失败:

partial_revokes 在存在限制时 禁用 ,必须首先删除限制:

  1. 确定哪些帐户有部分撤销:

    SELECT User,Host,User_attributes  -  >>'$。Restrictions'
    FROM mysql.user WHERE User_attributes  -  >>'$。Restrictions'<>'';
    
  2. 对于每个此类帐户,请删除其权限限制。 假设上一步显示帐户 u1 有这些限制:

    [{“数据库”:“世界”,“权限”:[“INSERT”,“DELETE”]
    

    可以通过多种方式删除限制:

    • 全局授予权限,没有任何限制:

      GRANT INSERT,DELETE ON *。* TO u1;
      
    • 在架构级别授予权限:

      GRANT INSERT,DELETE ON world。* TO u1;
      
    • 全局撤销权限(假设不再需要它们):

      REVOKE INSERT,DELETE ON *。* FROM u1;
      
    • 删除帐户本身(假设不再需要):

      DROP USER u1;
      

删除所有权限限制后,可以禁用部分撤消:

SET PERSIST partial_revokes = OFF;

部分撤销和复制

在复制方案中,如果 partial_revokes 在任何主机上启用,则必须在所有主机上启用它。 否则, REVOKE 部分撤销全局特权的语句对发生复制的所有主机的影响不同,可能导致复制不一致或错误。

6.2.13权限更改生效时

如果 没有 选项 启动 mysqld 服务器 --skip-grant-tables ,它会在启动序列期间将所有授权表内容读入内存。 内存表在此时对访问控制有效。

如果使用帐户管理语句间接修改授权表,服务器会注意到这些更改并立即再次将授权表加载到内存中。 帐户管理声明在 第13.7.1节“帐户管理声明”中描述 实例包括 GRANT REVOKE SET PASSWORD ,和 RENAME USER

如果你修改授权表直接使用的语句,例如 INSERT UPDATE DELETE (不推荐),该变化对特权的效果检查,直到你要么告诉服务器重新加载表或重新启动它。 因此,如果直接更改授权表但忘记重新加载它们,则在 重新启动服务器之前 ,更改 不会生效 这可能会让您想知道为什么您的更改似乎没有任何区别!

要告诉服务器重新加载授权表,请执行flush-privileges操作。 这可以通过发出 FLUSH PRIVILEGES 语句或执行 mysqladmin flush-privileges mysqladmin reload 命令来完成。

授权表重新加载会影响每个现有客户端会话的权限,如下所示:

  • 表和列权限更改将随客户端的下一个请求生效。

  • 数据库权限更改将在客户端下次执行 语句 时生效 USE db_name

    注意

    客户端应用程序可以缓存数据库名称 因此,如果不实际更改为不同的数据库,这些效果可能对他们不可见。

  • 对于已连接的客户端,全局权限和密码不受影响。 这些更改仅在后续连接的会话中生效。

对会话中的活动角色集的更改将立即生效,仅适用于该会话。 SET ROLE 语句执行会话角色激活和取消激活(请参见 第13.7.1.11节“SET ROLE语法” )。

如果使用该 --skip-grant-tables 选项 启动服务器 ,则它不会读取授权表或实现任何访问​​控制。 任何用户都可以连接并执行任何操作, 这是不安全的。 为了使服务器因此开始读取表并启用访问检查,请刷新权限。

6.2.14分配帐户密码

连接到MySQL服务器的客户端所需的凭据可以包含密码。 本节介绍如何为MySQL帐户分配密码。

MySQL将凭证存储在 系统数据库 user 表中 mysql 分配或修改密码的操作仅允许具有该 CREATE USER 特权的 用户 ,或者 mysql 数据库的 INSERT 特权(创建新帐户的 UPDATE 特权,修改现有帐户的特权)。 如果 read_only 启用 系统变量,则使用帐户修改语句,例如 CREATE USER ALTER USER 另外需要 CONNECTION_ADMIN SUPER 特权。

此处的讨论仅总结了最常见的密码赋值语句的语法。 有关其他可能性的完整详细信息,请参见 第13.7.1.3节“创建用户语法” 第13.7.1.1节“ALTER USER语法” 第13.7.1.10节“SET PASSWORD语法”

MySQL使用插件来执行客户端身份验证; 请参见 第6.2.17节“可插入的身份验证” 在密码分配语句中,与帐户关联的身份验证插件执行指定的明文密码所需的任何散列。 这使MySQL能够在将密码存储在 mysql.user 系统表 之前对其进行模糊处理 对于此处描述的语句,MySQL会自动散列指定的密码。 还有语法的 CREATE USER ALTER USER 从字面上指定许可证哈希值。 有关详细信息,请参阅这些语句的说明。

要在创建新帐户时指定密码,请使用 CREATE USER 并包含 IDENTIFIED BY 子句:

创建用户'jeffrey'@'localhost'标识' password';

CREATE USER 还支持指定帐户身份验证插件的语法。 请参见 第13.7.1.3节“创建用户语法”

要为现有帐户分配或更改密码,请使用 ALTER USER 带有 IDENTIFIED BY 子句 语句

ALTER USER'jeffrey'@'localhost'ENFENTIFIED BY' password';

如果您未以匿名用户身份进行连接,则可以更改自己的密码,而无需按字面指定自己的帐户:

ALTER USER USER()通过' password' 标识;

要从命令行更改帐户密码,请使用 mysqladmin 命令:

mysqladmin -u user_name-h host_name密码“ password

此命令设置密码的帐户是 mysql.user 系统表中与 匹配 user_name User 行以及 Host 列中 连接 的客户端主机

警告

使用 mysqladmin 设置密码 应该被认为是 不安全的 在某些系统上,您的密码对系统状态程序(例如 ps) 可见 ,其他用户可以调用它来显示命令行。 MySQL客户端通常在初始化序列期间用零覆盖命令行密码参数。 但是,仍然存在一个短暂的间隔,在该间隔期间值是可见的。 此外,在某些系统上,此覆盖策略无效,并且 ps 仍然可以看到密码 (SystemV Unix系统和其他人可能遇到这个问题。)

如果您使用的是MySQL Replication,请注意,目前,复制从属设备使用的密码作为 CHANGE MASTER TO 语句的 一部分 实际上限制为32个字符; 如果密码较长,则会截断任何多余的字符。 这不是由于MySQL服务器通常施加的任何限制,而是MySQL Replication特有的问题。 (有关更多信息,请参阅Bug#43439。)

6.2.15密码管理

MySQL支持这些密码管理功能:

  • 密码过期,要求定期更改密码。

  • 密码重用限制,以防止再次选择旧密码。

  • 密码验证,要求密码更改还指定要替换的当前密码。

  • 双密码,使客户端可以使用主密码或二级密码进行连接。

  • 密码强度评估,要求强密码。

以下部分介绍了这些功能,密码强度评估除外,它使用 validate_password 插件 实现, 并在 第6.4.3节“密码验证组件”中进行了介绍

重要

MySQL使用 mysql 系统数据库中的 表实现密码管理功能 如果从早期版本升级MySQL,则系统表可能不是最新的。 在这种情况下,服务器会在启动过程中将与此类似的消息写入错误日志(具体数字可能会有所不同):

[错误] mysql.user的列数错误。预期
49,发现47.该表可能已损坏
[警告] ACL表mysql.password_history缺失。
某些操作可能会失败。

要解决此问题,请执行MySQL升级过程。 请参见 第2.11节“升级MySQL” 在此之前, 无法更改密码。

注意

这里所描述的密码管理功能仅适用于内部存储凭据的账户 mysql.user 系统表( mysql_native_password sha256_password ,或 caching_sha2_password )。 对于使用对外部凭据系统执行身份验证的插件的帐户,还必须在该系统外部处理密码管理。

密码过期策略

MySQL使数据库管理员可以手动使帐户密码过期,并建立自动密码过期的策略。 可以在全局建立到期策略,并且可以将个人帐户设置为遵循全局策略或使用特定的每帐户行为覆盖全局策略。

要手动过期帐户密码,请使用以下 ALTER USER 语句:

ALTER USER'jeffrey'@'localhost'PASSWORD EXPIRE;

此操作将密码在 mysql.user 系统表 的相应行中标记为已过期

根据策略的密码到期是自动的,并且基于密码年龄,对于给定帐户,密码年龄根据其最近密码更改的日期和时间进行评估。 mysql.user 系统表显示为每个帐户时,其上次更改口令,服务器自动将作为客户端连接的过期时间,如果它的年龄比它允许生存更大的口令。 这适用于没有明确的手动密码到期。

要全局建立自动密码到期策略,请使用 default_password_lifetime 系统变量。 其默认值为0,禁用自动密码到期。 如果值为 default_password_lifetime 正整数 N ,则表示允许的密码生存期,因此必须每天更改密码 N

例子:

  • 要建立密码具有大约六个月生命周期的全局策略,请在服务器 my.cnf 文件中 使用以下行启动服务器

    的[mysqld]
    default_password_lifetime = 180
    
  • 要建立密码永不过期的全局策略,请设置 default_password_lifetime 为0:

    的[mysqld]
    default_password_lifetime = 0
    
  • default_password_lifetime 也可以在运行时设置和持久化:

    SET PERSIST default_password_lifetime = 180;
    SET PERSIST default_password_lifetime = 0;
    

    SET PERSIST 设置正在运行的MySQL实例的值。 它还保存了用于后续服务器重启的值; 请参见 第13.7.5.1节“变量赋值的SET语法” 要更改正在运行的MySQL实例的值而不保存它以便后续重新启动,请使用 GLOBAL 关键字而不是 PERSIST

全局密码到期策略适用于尚未设置为覆盖它的所有帐户。 要为个人帐户建立策略,请使用 语句 PASSWORD EXPIRE 选项 请参见 第13.7.1.3节“创建用户语法” 第13.7.1.1节“更改用户语法” CREATE USER ALTER USER

特定于帐户的语句示例:

  • 要求密码每90天更改一次:

    创建用户'jeffrey'@'localhost'密码EXPIRE INTERVAL 90天;
    ALTER USER'jeffrey'@'localhost'PASSWORD EXPIRE INTERVAL 90天;
    

    此到期选项会覆盖该语句指定的所有帐户的全局策略。

  • 禁用密码到期:

    创建用户'jeffrey'@'localhost'密码永远不会出现;
    ALTER USER'jeffrey'@'localhost'PASSWORD EXPIRE NEVER;
    

    此到期选项会覆盖该语句指定的所有帐户的全局策略。

  • 遵循该语句指定的所有帐户的全局过期策略:

    创建用户'jeffrey'@'localhost'PASSWORD EXPIRE DEFAULT;
    ALTER USER'jeffrey'@'localhost'PASSWORD EXPIRE DEFAULT;
    

当客户端成功连接时,服务器会确定帐户密码是否已过期:

  • 服务器检查密码是否已手动过期。

  • 否则,服务器根据自动密码过期策略检查密码年龄是否大于其允许的生存期。 如果是,则服务器认为密码已过期。

如果密码已过期(无论是手动还是自动),服务器将断开客户端连接或限制允许的操作(请参见 第6.2.16节“过期密码的服务器处理” )。 受限客户端执行的操作会导致错误,直到用户建立新的帐户密码:

MySQL的> SELECT 1;
ERROR 1820(HY000):您必须使用ALTER USER重置密码
执行此语句之前的语句。

MySQL的> ALTER USER USER() IDENTIFIED BY 'password';
查询OK,0行受影响(0.01秒)

MySQL的> SELECT 1;
+ --- +
| 1 |
+ --- +
| 1 |
+ --- +
1排(0.00秒)

客户端重置密码后,服务器将恢复会话的正常访问,以及后续使用该帐户的连接。 管理用户也可以重置帐户密码,但该帐户的任何现有受限会话仍然受到限制。 使用该帐户的客户端必须断开连接并重新连接才能成功执行语句。

注意

可以 通过将密码设置为其当前值 重置 密码。 作为一个好的政策问题,最好选择不同的密码。 DBA可以通过建立适当的密码重用策略来强制执行非重用。 请参阅 密码重用策略

密码重用政策

MySQL允许对重用以前的密码进行限制。 可以根据密码更改次数,已用时间或两者来确定重用限制。 可以在全球范围内建立重用策略,并且可以将个人帐户设置为遵循全局策略或使用特定的每帐户行为覆盖全局策略。

帐户的密码历史记录包含过去分配的密码。 MySQL可以限制从此历史记录中选择新密码:

  • 如果根据密码更改次数限制帐户,则无法从指定数量的最新密码中选择新密码。 例如,如果密码更改的最小数量设置为3,则新密码不能与任何最近的3个密码相同。

  • 如果根据已用时间限制帐户,则无法从历史记录中比指定天数更新的密码中选择新密码。 例如,如果密码重用间隔设置为60,则新密码不得超过先前在过去60天内选择的密码。

注意

空密码不会计入密码历史记录中,并且可以随时重复使用。

要全局建立密码重用策略,请使用 password_history password_reuse_interval 系统变量。

例子:

  • 要禁止重复使用365天以外的最后6个密码或密码,请将这些行放在服务器 my.cnf 文件中:

    的[mysqld]
    PASSWORD_HISTORY = 6
    password_reuse_interval = 365
    
  • 要在运行时设置和持久化变量,请使用如下语句:

    SET PERSIST password_history = 6;
    SET PERSIST password_reuse_interval = 365;
    

    SET PERSIST 设置正在运行的MySQL实例的值。 它还保存了用于后续服务器重启的值; 请参见 第13.7.5.1节“变量赋值的SET语法” 要更改正在运行的MySQL实例的值而不保存它以便后续重新启动,请使用 GLOBAL 关键字而不是 PERSIST

全局密码重用策略适用于尚未设置为覆盖它的所有帐户。 要为个人帐户建立策略,请使用 语句 PASSWORD HISTORY PASSWORD REUSE INTERVAL 选项 请参见 第13.7.1.3节“创建用户语法” 第13.7.1.1节“更改用户语法” CREATE USER ALTER USER

特定于帐户的语句示例:

  • 在允许重用之前,至少需要更改5个密码:

    创建用户'jeffrey'@'localhost'密码历史5;
    ALTER USER'jeffrey'@'localhost'PASSWORD HISTORY 5;
    

    此历史记录长度选项会覆盖该语句指定的所有帐户的全局策略。

  • 在允许重用之前至少需要365天:

    创建用户'jeffrey'@'localhost'密码重新使用INTERVAL 365天;
    ALTER USER'jeffrey'@'localhost'PASSWORD REUSE INTERVAL 365天;
    

    此time-elapsed选项会覆盖该语句指定的所有帐户的全局策略。

  • 要结合这两种类型的重用限制,使用 PASSWORD HISTORY PASSWORD REUSE INTERVAL 在一起:

    创建用户'jeffrey'@'localhost'
      密码历史5
      密码重复间隔365天;
    更改用户'jeffrey'@'localhost'
      密码历史5
      密码重复间隔365天;
    

    这些选项会覆盖语句指定的所有帐户的全局策略重用限制。

  • 遵循两种类型的重用限制的全局策略:

    创建用户'jeffrey'@'localhost'
      密码历史默认
      密码重复使用间隔默认值;
    更改用户'jeffrey'@'localhost'
      密码历史默认
      密码重复使用间隔默认值;
    

密码验证 - 必需的策略

从MySQL 8.0.13开始,可以要求通过指定要替换的当前密码来验证更改帐户密码的尝试。 这使DBA能够阻止用户更改密码,而无需证明他们知道当前密码。 否则可能发生这样的改变,例如,如果一个用户暂时离开终端会话而没有退出,并且恶意用户使用该会话来改变原始用户的MySQL密码。 这可能会产生不幸的后果:

  • 在管理员重置帐户密码之前,原始用户无法访问MySQL。

  • 在密码重置发生之前,恶意用户可以使用良性用户更改的凭据访问MySQL。

可以在全球范围内建立密码验证策略,并且可以将个人帐户设置为遵循全局策略或使用特定的每帐户行为覆盖全局策略。

对于每个帐户,其 mysql.user 行指示是否存在特定于帐户的设置,需要验证密码更改尝试的当前密码。 该设置由 语句 PASSWORD REQUIRE 选项 建立 CREATE USER ALTER USER

  • 如果帐户设置是 PASSWORD REQUIRE CURRENT ,密码更改必须指定当前密码。

  • 如果帐户设置是 PASSWORD REQUIRE CURRENT OPTIONAL ,密码更改可能但不需要指定当前密码。

  • 如果帐户设置为 PASSWORD REQUIRE CURRENT DEFAULT ,则 password_require_current 系统变量确定帐户所需的验证策略:

换句话说,如果帐户设置不是 PASSWORD REQUIRE CURRENT DEFAULT ,则帐户设置优先于 password_require_current 系统变量 建立的全局策略 否则,帐户将按照 password_require_current 设置进行操作。

默认情况下,密码验证是可选的: password_require_current 已禁用,并且创建的帐户没有 PASSWORD REQUIRE 默认选项 PASSWORD REQUIRE CURRENT DEFAULT

下表显示了每个帐户设置如何与 password_require_current 系统变量值 交互 以确定帐户密码验证所需的策略。

表6.10密码验证策略

每帐户设置 password_require_current系统变量 密码更改需要当前密码?
PASSWORD REQUIRE CURRENT OFF
PASSWORD REQUIRE CURRENT ON
PASSWORD REQUIRE CURRENT OPTIONAL OFF 没有
PASSWORD REQUIRE CURRENT OPTIONAL ON 没有
PASSWORD REQUIRE CURRENT DEFAULT OFF 没有
PASSWORD REQUIRE CURRENT DEFAULT ON

注意

无论是否需要验证策略,特权用户都可以更改任何帐户密码而无需指定当前密码。 特权用户是一个谁拥有全球的 CREATE USER 特权或 UPDATE 为特权 mysql 系统数据库。

要全局建立密码验证策略,请使用 password_require_current 系统变量。 其默认值为 OFF ,因此不需要帐户密码更改指定当前密码。

例子:

  • 要建立密码更改必须指定当前密码的全局策略,请在服务器 my.cnf 文件中 使用以下行启动服务器

    的[mysqld]
    password_require_current = ON
    
  • password_require_current 在运行时 设置和持久化 ,请使用以下语句之一:

    SET PERSIST password_require_current = ON;
    SET PERSIST password_require_current = OFF;
    

    SET PERSIST 设置正在运行的MySQL实例的值。 它还保存了用于后续服务器重启的值; 请参见 第13.7.5.1节“变量赋值的SET语法” 要更改正在运行的MySQL实例的值而不保存它以便后续重新启动,请使用 GLOBAL 关键字而不是 PERSIST

全局密码验证所需策略适用于尚未设置为覆盖它的所有帐户。 要为个人帐户建立策略,请使用 语句 PASSWORD REQUIRE 选项 请参见 第13.7.1.3节“创建用户语法” 第13.7.1.1节“更改用户语法” CREATE USER ALTER USER

特定于帐户的语句示例:

  • 要求密码更改指定当前密码:

    创建用户'jeffrey'@'localhost'密码请求当前;
    更改用户'jeffrey'@'localhost'密码请求当前;
    

    此验证选项会覆盖该语句指定的所有帐户的全局策略。

  • 不要求密码更改指定当前密码(可以但不需要给出当前密码):

    创建用户'jeffrey'@'localhost'密码请求当前可选;
    更改用户'jeffrey'@'localhost'密码要求当前可选;
    

    此验证选项会覆盖该语句指定的所有帐户的全局策略。

  • 遵循该语句指定的所有帐户的全局密码验证所需策略:

    创建用户'jeffrey'@'localhost'密码请求当前默认值;
    更改用户'jeffrey'@'localhost'密码请求当前默认值;
    

当用户使用 ALTER USER or SET PASSWORD 语句 更改密码时,验证当前密码 使用的示例 ALTER USER 优先 SET PASSWORD 于此,但此处描述的原则对于两个语句都是相同的。

在password-change语句中, REPLACE 子句指定要替换的当前密码。 例子:

  • 更改当前用户的密码:

    ALTER USER USER()通过' auth_string'REPLACE' current_auth_string' 识别;
    
  • 更改指定用户的密码:

    更改用户'jeffrey'@'localhost'
      由' auth_string' 识别
      替换' current_auth_string';
    
  • 更改命名用户的身份验证插件和密码:

    更改用户'jeffrey'@'localhost'
      使用caching_sha2_password BY' auth_string' 识别
      替换' current_auth_string';
    

REPLACE 条款的作用如下:

  • REPLACE 如果需要对帐户进行密码更改以指定当前密码,则必须给出,因为验证尝试进行更改的用户实际上知道当前密码。

  • REPLACE 如果帐户的密码更改可能但不需要指定当前密码,则是可选的。