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 身份验证吗?在这种情况下,请按以下步骤操作:
- 使用
--skip-grant-tables
重新启动 MariaDB - 登录到未受保护的服务器
- 运行
FLUSH PRIVILEGES
(请注意,在 10.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;
就是这样。记住,确保密码安全最好的方法就是没有密码。玩得开心!
> CREATE USER root@localhost IDENTIFIED VIA unix_socket OR mysql_native_password USING ‘invalid’
为什么这还不够?
CREATE USER root@localhost IDENTIFIED VIA unix_socket
这就是 Debian 从 10.0 版本以来一直在使用的。对大多数用户来说这工作得很好。采用这种方法,任何以 root@localhost 身份登录的人都必须拥有 sudo 权限。但我们收到了一些抱怨,说有些用户希望他们旧的设置能工作,并在不 sudo 到系统 root 的情况下以 root@localhost 身份登录。
使用 10.4 的方法,可以使用 sudo,作为一种方便的无密码选项。但也可以执行
sudo mysql -e ‘SET PASSWORD=PASSWORD(“foobar”)’
然后允许某人使用“mysql –user=root –password=foobar”登录,而无需 sudo。
也就是说,SET PASSWORD 会成功,之后 unix_socket 和 password=foobar 都将生效。
如果创建用户时缺少
OR mysql_native_password USING ‘invalid’
,set password
会失败吗?如果是这样,那就有点不好。
如果不是,那
OR mysql_native_password USING ‘invalid’
的意义何在?我同意为一个用户设置多种身份验证方法很棒,自从引入基于 socket 的身份验证以来,我就一直想要这个功能。
是的。如果您只有
CREATE USER root@localhost IDENTIFIED VIA unix_socket
,并且您执行SET PASSWORD
,它会失败,因为它无法为 unix_socket 插件设置密码。您需要至少有一个支持“密码”概念的插件,SET PASSWORD
才能成功。起初我很高兴读到所有这些变化,但我对关于 unix_sockets 身份验证的这一说法有些担心
“要求系统 root 输入密码并不能增加额外的安全性——root 反正拥有所有数据文件和所有进程内存的完全访问权限。”
我只部分同意这一点:是的,作为 root 用户您可以访问文件,但您无法直接从文件中提取数据。允许 root 用户通过 unix socket 无密码登录,会使任何人都能更容易地提取数据。也许攻击者对整个数据集不感兴趣,而是想更多地了解应用程序的设置或仅仅是部分敏感数据。现在攻击者只需发出查询,就能获取特定数据,而无需先复制整个数据集。
当然,攻击者可以重置 root 密码,但这可能会因为守护进程的重启而被注意到。在攻击者提取/导出数据之前,这也是一个额外的步骤。更重要的是:一些有能力成为 root 的用户(系统管理员)可能没有理由能够登录到数据库,那么为什么要授予他们这项权限呢?
用一些现实世界中的例子来打个比方:把车库前门敞开并不会增加任何额外的安全性,因为窃贼可以打扮成您,而且您反正可以在您房子的范围内自由行走。这只部分正确,因为窃贼无法直接进入您的车库四处查看。相反,如果他/她只对里面停放的珍贵法拉利感兴趣,就必须偷走整个车库或暴力破解它。当然,我相信我的隔壁邻居在进入我的院子时是值得信任的,但我仍然宁愿他们不要在我的车库里窥探。
我个人认为,拥有 unix_socket 登录作为一种身份验证方法是一个很好的改进,但我不认为默认启用它是好主意。正如我们从过去学到的那样:一个空(root)密码是个坏主意,大多数用户仅仅因为懒惰而根本不更改它。我认为这对许多运行自己的(私有)服务器或运行 docker 的人来说会受到欢迎,但对于在大型组织中运行它的人来说则不然。但这只是我的两分钱。
是的,这正是重点。你无法真正*保护*自己免受 root 用户的侵害,你只能让提取数据变得更令人恼火、更不方便。一个 root 用户总是可以复制所有数据文件并在其上启动一个独立的 mysqld 进程。或者一个 root 可以编辑内存中的 mysqld 镜像,只在那里更改 root 密码,无需重启。或者——一个容易得多的方法——一个 root 可以将 gdb 附加到 mysqld 进程,并使任何密码都能通过身份验证。
请注意,我当然同意在某些情况下,DBA 可能不希望 root 用户因某些原因拥有无密码访问权限。但这正说明了它为何可以轻松禁用,它不是一个固有的硬编码的直通后门。
我相信对于大多数安装来说,不设置 root 密码可以提高易用性,并实际上提高安全性。当不适用时——DBA 可以用一个命令禁用它。
让我在这里为 MariaDB 辩护一次。:)
unix_socket 是为了解决其目标问题而进行的最佳发明之一——Art,您不需要使用它(我能理解有些人不想要它),但它并没有降低安全性。密码通常是一种糟糕的身份验证方式,而基于 socket 的身份验证解决了像那个丑陋的 debian-sys-maint 用户这样的用例——它无法解决其他用例,对于这些用例有其他解决方案(加密、TLS、其他身份验证方法)。我不会将它用于常规应用程序身份验证,但它非常适合避免为管理员类型帐户维护容易泄露的密码。
我对新的身份验证表还不太确定,需要等待看看它在实践中如何工作,现在下结论还为时过早。
你好
我刚安装好。但一切似乎都不工作。我怎么登录到 mariadb 10.04?这简直太难了。
谢谢
如果您在安装或使用 MariaDB 时遇到问题,请随时在 Zulip 或邮件列表中寻求帮助,相关信息可在 https://mariadb.org.cn/get-involved/ 查看