MariaDB 10.4 中的身份验证 — 理解变化

MariaDB Server 10.4 带来了很多安全相关的变化。其中一些仅仅是优化(例如 MDEV-15649),一些改进了现有功能使其更健壮(MDEV-15473, MDEV-7598)或更方便(MDEV-12835, MDEV-16266)。还有一些是用户要求的 MySQL 兼容性功能(MDEV-7597, MDEV-13095)。

但任何 MariaDB Server 用户,无论是经验丰富的专家还是新手,在发出第一个 SQL 语句之前,首先要做的就是登录。连接到数据库服务器并进行身份验证。10.4 版本也对此过程进行了更改。如果您是新用户,希望您会发现 MariaDB Server 更易于使用、更直观,并且在密码方面遇到的麻烦更少。但如果您已经使用 MariaDB Server 一段时间了,新的行为有时可能会让您感到困惑。本文解释了哪些内容已更改以及 MariaDB Server 现在是如何工作的。

简而言之

密码存储方式已更改。所有用户帐户、密码和全局权限现在都存储在 mysql.global_priv 表中。那 mysql.user 表呢?它仍然存在,并且拥有与以前完全相同的列集,但它现在是 mysql.global_priv 表的一个视图。如果您使用的工具有分析 mysql.user 表的功能 — 它们应该会像以前一样继续工作。

每个帐户可以指定多种身份验证方法。它们都将作为备选方案。例如,DBA 可以开始将用户迁移到更安全的 ed25519 密码插件,但为了过渡期,保留旧的 SHA1 插件作为备选方案。

新安装的默认身份验证现在更安全。开放给所有人、拥有所有权限的 root 帐户终于不再默认存在了。安装脚本也不会再对你喊“请记住为 MariaDB root 用户设置密码!”,因为 root 帐户会自动安全创建。

详细信息

从技术上讲,新的 MariaDB 安装将有两个拥有所有权限的帐户——root 和拥有数据目录的 OS 用户,通常是 mysql。它们的创建方式如下:

CREATE USER root@localhost IDENTIFIED VIA unix_socket OR mysql_native_password USING 'invalid'
CREATE USER mysql@localhost IDENTIFIED VIA unix_socket OR mysql_native_password USING 'invalid'

使用 unix_socket 意味着如果您是系统的 root 用户,您可以无需密码以 root@locahost 身份登录。这项技术早在 MariaDB 10.0 版本中,就由 Otto Kekäläinen 在 Debian 的 MariaDB 包中首创。它基于一个简单的事实,即要求系统 root 输入密码并不能增加额外的安全性——root 反正拥有所有数据文件和所有进程内存的完全访问权限。但不要求密码意味着,没有 root 密码可供遗忘(再见,那些无数的“如何重置 MariaDB root 密码”教程)。如果您想编写脚本来处理一些繁琐的数据库工作,则无需将 root 密码以明文形式存储在脚本中供使用(再见,debian-sys-maint 用户)。

尽管如此,一些用户抱怨他们希望无需使用 sudo 就能以 MariaDB root 身份登录。这就是为什么在 10.4 版本中,root 用户有了第二种身份验证方法——传统的 MariaDB 密码。默认情况下,它被禁用(“invalid”不是一个有效的密码哈希),但可以使用通常的 SET PASSWORD 语句设置密码。而且仍然可以通过 sudo 保留无密码访问!

现在,如果您在本地安装 MariaDB(例如,从 tarball 安装)会发生什么?您肯定不希望使用 sudo 才能登录。这就是为什么 MariaDB 创建了第二个拥有所有权限的用户,其名称与拥有数据目录的系统用户相同。在本地(非系统级)安装中,这将是安装 MariaDB 的用户——她会自动获得方便的无密码类 root 访问权限,因为坦率地说,她反正可以访问所有数据文件。

即使 MariaDB 是系统级安装的,您可能也不想以系统 root 身份运行数据库维护脚本——现在您可以以系统 mysql 用户身份运行它们。并且您会知道,即使您在 shell 脚本中打错了字,它们也永远不会破坏您的整个系统。

操作指南

“这一切都很棒,”您可能会想,“但我是一名经验丰富的 MariaDB DBA,我闭着眼睛都能写 SQL,从现在开始我需要做些什么不同的事情吗?”不幸的是,是的。

在系统级安装 MariaDB 后,您习惯做的第一件事是登录到未受保护的 root 帐户并保护它,即设置 root 密码

$ sudo dnf install MariaDB-server
$ mysql -uroot
...
MariaDB> set password = password("XH4VmT3_jt");

这现在不仅不必要,而且根本行不通——因为没有未受保护的 root 帐户。要以 root 身份登录,请使用

$ sudo dnf install MariaDB-server
$ sudo mysql

请注意,这意味着您是通过 unix socket 连接,而不是 tcp。如果您在系统级 /etc/my.cnf 文件中设置了 protocol=tcp,请使用 sudo mysql --protocol=socket

在本地安装 MariaDB 后,您也习惯于使用 mysql -uroot 连接到未受保护的 root 帐户。这现在也行不通了,只需使用 mysql 连接,无需指定用户名。

您想要恢复密码登录,不再使用 unix_socket 身份验证了吗?运行

ALTER USER root@localhost IDENTIFIED VIA mysql_native_password USING PASSWORD("verysecret")

忘记您的 root 密码了吗?没问题——您仍然可以使用 sudo 连接并更改密码。哦,您也移除了 unix_socket 身份验证吗?在这种情况下,请按以下步骤操作:

  1. 使用 --skip-grant-tables 重新启动 MariaDB
  2. 登录到未受保护的服务器
  3. 运行 FLUSH PRIVILEGES(请注意,在 10.4 之前这是最后一步,现在不再是了)
  4. 运行 SET PASSWORD FOR root@localhost 更改 root 密码

您想查看权限表内部吗?旧的 mysql.user 表仍然存在,您可以像以前一样从中进行 select 操作,尽管您不能再更新它了。它没有显示备选的身份验证插件?是的,这是切换到 mysql.global_priv 表的原因之一——复杂的身份验证规则无法适应关系表的固定结构。但是,您当然也可以从新表中进行 select 操作。例如,使用

select concat(user, '@', host, ' => ', json_detailed(priv)) from mysql.global_priv;

就是这样。记住,确保密码安全最好的方法就是没有密码。玩得开心!