分享到

简介

身份验证和授权是管理和保护 MySQL 服务器的必要考量。 身份验证(有时简称为“authn”)是指验证客户端是否允许以特定用户身份连接的一类策略和机制。 授权(有时简称为“authz”)是在身份验证之后进行的一个过程,用于确定帐户允许执行哪些操作。

在本指南中,我们将介绍 MySQL 提供的用于管理此 访问控制系统 的概念和组件。我们将讨论用户、角色、身份验证方法和权限之间的相互作用,这些要素共同解决了如何控制谁可以在 MySQL 数据库服务器上执行哪些操作的问题。

MySQL 如何配置身份验证和授权?

MySQL 通过许多不同的相关系统管理其身份验证和授权要求。从广义上讲,其组成部分是

  • 用户:用户是 MySQL 服务器上配置的单个帐户,充当身份。这些身份可以与身份验证方法耦合,以允许客户端以用户身份连接,并且可以获得权限,以允许它们以各种粒度级别访问和控制不同的数据库对象。MySQL 中的用户由一个 用户名称和一个 主机组成,用户从该主机连接。从不同的 主机连接的相同 用户名称被视为不同的用户。
  • 身份验证方法:身份验证方法是确定是否允许连接的客户端使用特定用户帐户的方法。这些方法通常涉及从客户端接受和验证密码,但也提供其他身份验证方法。
  • 权限:用户的功能和访问级别由直接授予他们的权限、通过角色成员资格获得的权限或通过对象所有权获得的权限定义。这些权限在各种范围内定义,并根据用户尝试执行的每个操作进行检查。
  • 角色:实际上,角色是可以应用于用户的权限集。将相关的权限组添加到角色中,然后通过角色成员资格分配这些权限,可以简化权限管理。

实际的访问控制过程分为两个不同的部分。首先,客户端以特定用户身份进行服务器身份验证。之后,将根据用户的授权权限检查每个操作,以确定是否允许或拒绝每个请求。

第 1 部分:身份验证

MySQL 访问控制系统的第一个阶段是验证连接。MySQL 根据以下因素决定是否接受连接请求

  • 您是否可以以请求的用户帐户身份成功进行身份验证
  • 该用户帐户是否在系统中被锁定

如果您连接的用户未锁定,并且您可以成功进行身份验证,则 MySQL 会接受连接,并允许您继续访问控制系统的第 2 部分。如果用户被标记为锁定,如果您的身份验证尝试失败,或者您提供用户无效,则 MySQL 将拒绝连接请求。

为了执行这些功能,MySQL 会参考其内部 mysql 数据库中 user 表中的以下列

用户

客户端连接的用户名帮助 MySQL 确定如何对用户进行身份验证。与下面的 主机字段结合使用时,它在 MySQL 中形成了一个完整的、唯一的身份。

mysql.user 表中,空白的 用户值将匹配客户端提供的任何用户。但是,当发生这种情况时,客户端在会话期间被视为匿名用户。这在 访问控制的第二阶段 中具有影响,在该阶段,服务器将针对匿名用户检查操作,而不是客户端提供的用户。

Host

客户端连接所在的主机被认为是用户身份的重要组成部分。在 MySQL 中,唯一的身份是由用户名和连接的主机组合而成的。

因此,来自 example.comuser1 与来自 test.orguser1 被认为是不同的。 User 字段和 Host 字段一起告诉 MySQL 要尝试验证哪个帐户。

plugin

一旦 MySQL 使用 UserHost 确定要为连接请求检索的正确记录,它将使用 plugin 字段来决定如何验证客户端。

用户的 plugin 字段定义用于验证用户凭据的身份验证方法。默认插件 caching_sha2_password 会将用户的密码与存储在表中的密码的哈希版本进行比较。

authentication_string

对于“本机”身份验证插件(那些仅使用 mysql.user 表中的信息来验证用户的插件), authentication_string 列包含用于检查用户密码的字符串。大多数情况下,这都是密码的哈希版本。如果本机插件的 authentication_stringmysql.user 表中为空,则客户端必须指定密码才能成功验证。

对于使用外部系统进行身份验证的插件, authentication_string 通常用于指定外部系统正确验证用户所需的其他信息(例如服务名称、其他识别信息等)。

account_locked

此列决定此特定用户帐户是否在系统中被锁定。帐户可以被数据库管理员手动锁定。帐户必须解锁才能继续。

确定 mysql.user 表中行的优先级

MySQL 使用以上五个字段来确定是否接受连接。但是,在某些情况下,多个条目可能会匹配客户端的连接。例如,客户端可能不提供主机,或者 mysql.user 表可能包含没有用户的行。MySQL 需要一种方法来确定这些行的优先级,以确定如何验证客户端。

为此,MySQL 在服务器启动时或接收到从磁盘重新加载信息的信号时,将 mysql.user 表中的行读入其内存。在读取行时,它还会根据特殊性对它们进行排序,以便表中的行按从最特殊到最不特殊排序。

首先,MySQL 根据 Host 列的特殊性对行进行排序。具有完整域名或 IP 地址的 Host 的行将被排序到堆栈的顶部,然后是那些在 Host 字段中使用通配符的那些行(将包含 %(匹配所有通配符)的行放在最后,作为最不特殊的条目),最后是 Host 为空的行。

MySQL 使用 User 列作为辅助排序字段。这意味着,如果两行具有相同的 Host 特殊性,则具有更特殊 User 条目的行将被优先考虑。 User 字段中不允许使用通配符。

User 字段包含以下内容:

  • 一个必须与提供的用户名完全匹配的字符串,或者
  • 一个空字段,它将匹配客户端提供的任何用户名,但将继续以匿名用户的身份进行会话

MySQL 只会使用 mysql.user 表中的一行来验证客户端连接。这意味着,如果身份验证失败或匹配错误的行,它将不会检查可能正确验证的替代方案。为了确定要使用哪一行来验证客户端连接请求,MySQL 从排序列表的顶部开始。它按顺序检查每一行,并使用找到的第一个与客户端连接匹配的行。

如果您不注意上述排序顺序,这可能会导致一些令人惊讶的结果。例如,包含 Host 值但不包含 User 的行将始终优先于包含 User 值但不包含 Host 的行。了解此排序系统将有助于您避免一整类身份验证问题。

如果您无法使用某个用户进行身份验证,请检查是否存在更具体的条目匹配。如果您可以连接,但无法执行您认为应该能够执行的操作,请验证 MySQL 是否允许您以请求的用户名而不是匿名用户身份访问,如上所述。

以下命令将打印出您当前验证的身份:

SELECT CURRENT_USER()

第 2 部分:授权

客户端的凭据验证后,MySQL 建立连接,然后进入访问控制系统的第二部分,以确定授权。MySQL 授权是一个持续的过程,它会将每个命令与用户帐户的特定权限进行比较。如果命令在用户权限的范围内,则允许该操作。如果不是,则服务器拒绝请求。

不同类型的权限

为了解释为什么某些权限存储在特定位置,有必要讨论 MySQL 中不同类型的权限。

权限范围

权限可以在不同的范围内分配,这决定了授予的权限的影响范围。某些权限仅在特定范围内有效,而其他权限可以根据您想要启用的粒度在不同的范围内分配。

全局权限是与特定数据库无关的权限。它们在整个 MySQL 服务器中都有效。许多全局权限与系统管理有关,并且与系统管理职责相关联,而不是直接与数据管理相关联。

数据库权限与 MySQL 服务器中的特定数据库相关联。在数据库范围内授予的权限会影响用户对数据库以及其中包含的任何数据库对象(如表)可以执行的操作。数据库权限可以授予特定数据库,也可以授予一般数据库。

对象权限使您能够控制数据库中的表、索引等。这些权限可以授予特定对象、特定数据库中特定类型的对象,或者可以授予整个服务器中特定类型的对象。

静态权限与动态权限

在内部,权限可以被归类为静态权限或动态权限。

静态权限内置于服务器中,无法注销(禁用)。无论服务器上启用了哪些组件,这些权限始终可用。一般来说,静态权限通常是基本权限(例如读取或写入数据的权限),它们适用于所有或大多数系统。

另一方面,动态权限取决于定义它们的插件或组件的可用性。这些权限可以在运行时注册或注销,以影响它们的可用性。未注册的权限无法授予,但已授予的权限会在启动时自动注册。动态权限始终是全局范围的(适用于整个 MySQL 服务器)。

权限定义位置

MySQL 的权限定义在内部 mysql 系统数据库的多个不同表中。这些表中定义的权限组合将决定用户在执行操作或访问数据库对象时所拥有的具体权限。以下是在 mysql 数据库中涉及权限定义的表:

  • user: 除了定义用于身份验证的用户帐户之外,user 表还定义了每个用户的静态全局权限。这些权限适用于整个 MySQL 服务器,不受任何插件或组件可用性的影响。
  • global_grants: global_grants 表定义了每个用户的动态全局权限。由插件或组件定义的任何权限都将在此表中注册。
  • db: db 表定义了数据库级别的权限。db 表与 user 表一样,匹配用户的 UserHost 值,但还包含一个名为 Db 的列,用于定义该行的数据库范围。
  • tables_priv: tables_priv 表以类似于 db 表对数据库进行权限定义的方式定义了表级别的权限。为了启用表级别的范围,除了 UserHostDb 之外,还提供了一个名为 Table_name 的列。
  • columns_priv: columns_priv 表比 tables_priv 表更进一步,它在列级别确定访问权限。为了增加这种粒度,除了 tables_priv 表中提供的列之外,还包括一个名为 Column_name 的列。
  • procs_priv: procs_priv 表定义了执行存储过程和函数的权限。它使用 UserHostDbRoutine_nameRoutine_type 列来限定用户对不同类型过程的权限。
  • proxies_priv: proxies_priv 表定义了用户的代理权限。代理允许一个用户以另一个用户的身份行事,继承其权限。proxies_priv 表使用 UserHost 列来匹配用户,然后使用名为 Proxied_hostProxied_user 的单独列来定义匹配用户可以扮演的角色。

这些表中用户帐户的匹配方式与我们之前描述的 mysql.user 表加载到内存中并进行排序的方式类似。

要显示当前与用户关联的权限,可以输入以下命令:

SHOW GRANTS FOR '<user>'@'<host>';

您还可以使用以下命令查看非权限帐户属性:

SHOW CREATE USER '<user>'@'<host>';

角色

角色是与授权过程相关的另一个组成部分。角色 是由管理员创建的命名权限集合,可以用来简化权限管理。将一组权限授予角色后,您可以通过将用户添加为该角色的成员来将这些权限授予用户。

因此,如果您想让多个用户能够在特定表中插入和更新数据,可以创建一个具有这些权限的角色。然后,您可以通过向该角色添加或删除用户来控制谁可以在该表中插入和更新数据。这会为不同类型的用户创建特定定义的访问级别,并有助于确保在所有帐户中一致地应用访问级别。

角色对参与其身份验证过程的复杂性影响很小。但是,我们在这里提到它们,是因为它们是管理权限的一种有用方法。

结论

身份验证和授权是 MySQL 安全方法的重要组成部分。它们共同作为系统的访问控制控制器,通过规范谁可以连接到服务器,可以查看和交互哪些结构以及可以访问哪些数据来进行控制。了解这些系统之间的交互方式可以帮助您配置安全的策略,这些策略可以保护您的数据,同时不会妨碍所有合法操作。

关于作者
Justin Ellingwood

Justin Ellingwood

Justin 从 2013 年开始撰写有关数据库、Linux、基础架构和开发人员工具的文章。他目前与妻子和两只兔子住在柏林。他通常不需要以第三人称写作,这对所有相关人员来说都是一种解脱。