MySQL安全加固:第二部分

100 阅读13分钟

MySQL安全加固:第二部分

Hudson译 原文

在前一篇文章中我们已经介绍了 MySQL一系列安全选项,应用这些选项可以使你的MySQL数据库更安全。它们包括:

  • MySQL通用安全措施;
  • 控制MySQL中的访问;
  • 在MySQL中创建、更改和删除用户;
  • 授予和撤销MySQL用户的权限;
  • 检查MySQL中分配给用户的权限。

在本文中,我们将深入探讨其他选项,包括:

  • MySQL中的帐户类别;
  • MySQL中的角色;
  • MySQL中的保留帐户;
  • MySQL中的密码管理;
  • MySQL中的帐户锁定;
  • MySQL提供的安全插件;
  • 保护MySQL备份的安全。

请再次记住,我们不会完全涵盖您需要了解的所有内容,但我们会尽力为您自己的研究提供良好的起点。

MySQL中的帐户类别

MySQL 8引入了账户类别。要点如下:

  • 有两个独立的帐户类别:普通用户和系统用户;
  • 普通用户是指没有 SYSTEM_USER 权限的用户– 系统用户是指具有SYSTEM_USER权限的用户;
  • 普通用户可以修改普通帐户–这样的用户不能修改系统帐户;
  • 系统用户可以修改系统帐户和普通帐户;
  • 普通帐户可以由普通用户和系统用户修改;
  • 系统帐户只能由系统用户修改。

要在MySQL安全方面使用帐户类别,请记住,SYSTEM_USER权限会影响诸如帐户操纵、终止会话和语句之类的事情 —— MySQL中的这个概念允许对某些帐户进行某些修改,从而使MySQL更安全。帐户类别还可以用来保护系统帐户不受普通帐户的操纵:为此,不要向普通帐户授予mysql模式修改权限。

要授予帐户SYSTEM_USER权限,请对创建的帐户使用以下查询:

GRANT SYSTEM_USER ON *.* TO system_user;

MySQL中的角色

在MySQL中,角色是权限的集合。当为用户帐户授予角色时,则授予与该角色关联的所有权限。可以

使用CREATE ROLE语句创建角色:

CREATE ROLE ‘role_1’, ‘role_2’;

角色名称由用户部分和主机部分组成–用户部分不能为空,如果未指定,则主机部分默认为“%”。 创建角色时,应为其分配权限。可以使用GRANT语句分配权限:

  • GRANT ALL ON demo_database.* TO ‘demo_user’;
    将demo_user用户授予 demo_database 数据库上所有权限;

  • GRANT INSERT, SELECT, UPDATE, DELETE ON database.* TO ‘demo_user’;
    将demo_user dabasase 数据库上的INSERT、SELECT、UPDATE和DELETE权限

  • GRANT SELECT ON demo_database.* TO ‘demo_user’; 将向名为demo_user的用户授予demo_database数据库上的SELECT权限。

要将角色分配给单个用户,请使用以下语法:

GRANT ‘role_name’ TO ‘user_name’@’localhost’;

要为单个用户分配多个角色,请使用以下语法:

GRANT ‘role_1’, ‘role_2’ TO ‘user_name’@’localhost’;

要同时将角色分配给多个用户,请使用以下语法:

GRANT ‘role_name’ TO ‘user1’@’localhost’, ‘user2’@’localhost’;

角色有助于防止安全事件,因为如果攻击者错误地知道权限不高的用户的密码,并假定该用户的角色非常“强大”,那么您的应用程序(和数据库)可能会得到很好的保护。

MySQL中的保留帐户

当涉及到保留帐户时,请记住MySQL在数据目录初始化期间创建的帐户。MySQL中有几个帐户应被视为保留帐户:

  • “root”@“localhost”–此帐户是一个超级用户帐户,在所有MySQL数据库中具有上帝般的权限(它可以在任何MySQL数据库上执行任何操作)。值得注意的是,还可以重命名root用户,以避免暴露具有高度特权的帐户。要重命名帐户,请运行以下命令
RENAME USER ‘root’@’localhost’ TO ‘username’@’localhost’;
  • 确保刷新权限:FLUSH PRIVILEGES

  • 'mysql.sys'@'localhost'– 此帐户是一个系统用户,用于定义sys模式中的视图、过程和函数。在MySQL 5.7.9中添加,以避免重命名root帐户时可能出现的问题。

  • 'mysql.session'@'localhost”– 插件在内部使用此帐户访问服务器。

在这种情况下,您不能做很多安全方面的工作,但请记住root帐户具有上帝般的特权,这意味着它可以跨任何MySQL数据库执行任何操作,在决定授予谁可以访问该帐户的权限时要小心谨慎。此外,请记住其他MySQL帐户的用途。

MySQL中的密码管理

MySQL还支持密码管理功能。其中包括:

  • 定期使密码过期的能力;
  • 避免密码重复使用的能力;
  • 生成密码的能力;
  • 检查所使用密码强度的能力;
  • 在多次登录失败后暂时锁定用户的能力。

现在,我们将进一步研究这些选项。 要手动让密码过期,请使用ALTER USER语句,如下所示:

ALTER USERuser’@’localhost’ PASSWORD EXPIRE;

要设置全局策略,请修改my.cnf文件,以便它包含default_password_lifetime参数。该参数在[mysqld]节下定义(以下示例将密码生存期设置为3个月(90天)):

default_password_lifetime=90

如果希望密码永不过期,请将参数default_password_litetime设置为0。还可以为特定用户设置密码过期。如果要为名为demo_user的用户设置密码过期间隔,可以使用以下示例:

ALTER USER ‘demo_user’@’localhost’ PASSWORD EXPIRE INTERVAL 90 DAY;

要禁用密码过期:

ALTER USER ‘demo_user’@’localhost’ PASSWORD EXPIRE NEVER;

要重置全局密码过期策略,请执行以下操作:

ALTER USER ‘demo_user’@’localhost’ PASSWORD EXPIRE DEFAULT;

密码重用限制不允许重用密码–要使用此功能,请使用password_history和password_reuse_interval变量。你可以把这些变量放在my.cnf文件中中,如下示例,或者在运行时通过在下面的语句前面添加SETPERSIST来设置它们。

要禁止重复使用之前使用过的5个密码中的任何一个密码(超过365天),请使用:

password_history=5
password_reuse_interval=365

要允许重复使用,至少需要更改5次密码:

ALTER USER ‘demo_user’@’localhost’ PASSWORD HISTORY 5;

创建用户时也可以这样做 – 将ALTER USER替换为CREATE USER。 要在创建用户时生成随机密码,请运行:

CREATE USER demo_user@localhost IDENTIFIED BY RANDOM PASSWORD;

要将用户的密码更改为随机生成的密码,请执行以下操作:

SET PASSWORD FOR demo_user@localhost TO RANDOM;

您的随机密码将显示在下面。 请记住,默认的随机密码长度为20个字符。长度可以由generated_random_password_length变量控制,该变量的范围为5到255。 要检查使用的密码的强度,可以使用VALIDATE_PASSWORD_STRENGTH变量 – 该函数显示0到100之间的数字,其中0是最弱的,100是最强的:select validate_password_strength('密码');

MySQL中的帐户锁定

MySQL 8.0.19还引入了临时锁定用户帐户的功能。这可以使用变量FAILED_LOGIN_ATTEMPTS和PASSWORD_LOCK_TIME完成。 要在创建用户时启用帐户锁定,请运行:

CREATE USER ‘demo_user’@’localhost’ IDENTIFIED BY ‘password’ FAILED_LOGIN_ATTEMPTS 5 PASSWORD_LOCK_TIME 5;

FAILED_LOGIN_ATTEMPTS后的值指定帐户锁定失败次数,PASSWORD_LOCK_TIME后的值以天为单位指定帐户锁定时间。也可以将PASSWORD_LOCK_TIME指定为UNBOUN DED,表示在帐户解锁之前一直锁定。

MySQL提供的安全插件

MySQL 还提供了几个插件,可以进一步增强安全功能。MySQL提供:

  • 身份验证插件;
  • 连接控制插件;
  • 密码验证插件;
  • 审计插件;
  • 防火墙插件;

这些插件可用于多种安全方面的用途:

身份验证插件

身份验证插件允许用户在MySQL中的多种可插入身份验证方法之间进行选择。它们可以与CREATE USER或ALTER USER语句一起使用。下面是一个示例:

CREATE USER ‘user_1’@’localhost’ IDENTIFIED WITH mysql_native_password BY ‘password’;

此查询将使用本机密码哈希方法实现身份验证。

连接控制插件

如果连接尝试次数超过一定数量,连接控制插件可能会增加服务器对连接尝试的响应延迟,它们能够阻止潜在的暴力攻击。这个插件库是在5.7.17版本中引入的,它可以通过my.cnf添加到MySQL中,或在运行时将插件加载到服务器。为了将插件添加到my.cnf,在[mysqld]下添加以下行:

plugin-load-add=connection_control.so

修改文件后,保存更改并重新启动MySQL。要在运行时将插件加载到服务器中,请运行:

INSTALL PLUGIN CONNECTION_CONTROL SONAME ‘connection_control.so’;
INSTALL PLUGIN CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS SONAME ‘connection_control.so’;

根据需要调整.so 后缀。 如果您正确完成了所有操作, CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS 表应该包含所有失败的连接尝试。

密码验证插件

如果使用得当,密码验证插件可以让用户使用更高强度的密码。密码验证插件可以通过my.cnf安装,或在运行时将插件加载到服务器。要通过my.cnf安装,在[mysqld]下面添加以下行,然后重新启动服务器:

plugin-load-add=validate_password.so

要在运行时加载插件,请运行以下语句:

INSTALL PLUGIN validate_password SONAME ‘validate_password.so’;

要在运行时加载插件并防止其被删除,请将validate-password=FORCE_PLUS_PERMANENT添加到my.cnf。 要在插件未初始化时阻止服务器运行,请使用值为FORCE或FORCE_PLUS_PERMANENT的 validate-password选项。

还可以更改密码强度策略:为此,请将validate_password_policy值更改为LOW、MEDIUM或STRONG。LOW值只检查密码长度,MEDIUM策略添加一些条件,STRONG策略添加一个条件,即由4个或更多字符组成的密码子字符串必须与字典文件中的单词不匹配,字典文件可以通过修改validate_password_dictionary_file变量来指定。

Keyring插件

Keyring插件可以使服务器组件和插件安全地存储敏感信息以供检索。要将插件加载到MySQL中,请在[mysqld]下面添加以下内容:

early-plugin-load=keyring_file.so

要指定keyring vault文件,请添加以下内容(keyring_vault_config变量应指向配置文件):

loose-keyring_vault_config=/var/lib/mysql_keyring/keyring_vault.conf”

keyring文件应包含vault_url变量,用于与定义vault服务器地址,secret_mount_point变量,用了定义 keyring vault存储密钥的安装点以及应由vault服务器定义的令牌。 (可选)还可以定义vault_ca变量(它应该指向用于签署vault证书的ca证书)。 重新启动服务器以使更改生效;

审计插件

审计插件可以监控、记录和阻止MySQL服务器上执行的活动。要安装MySQL Enterprise Audit,请运行位于MySQL实例共享目录中的脚本(避免将MySQL实例的密码放在终端中–使用my.cnf):

mysql < /path/to/audit_log_filter_linux_install.sql

您还可以防止插件在运行时被删除-在[mysqld]部分添加以下内容:

audit_log=FORCE_PLUS_PERMANENT

重新启动服务器以应用更改。请注意,基于规则的日志记录默认情况下不会记录可审计的事件,因此要使其记录所有内容,请创建一个过滤器:

SELECT audit_log_filter_set_filter(‘log_filter’, ‘{ “filter”: { “log”: true } }’);

然后将其分配给一个帐户:

SELECT audit_log_filter_set_user(‘%’, ‘log_filter’);

注意,审计插件仅在MySQL Enterprise Edition中可用;

防火墙插件

防火墙插件可以使用户允许或拒绝基于特定模式执行特定SQL语句。MySQL 5.6.24引入了MySQL Enterprise Firewall,它能够通过监视、警报和阻止未经授权的活动来保护数据:它能够阻止SQL注入攻击、监视威胁、阻止可疑流量以及检测数据库中的入侵。防火墙还可以记录被阻止的语句-可以对其进行检查,还可以观察批准和拒绝的语句的实时计数。

要安装MySQL Enterprise Firewall,只需安装Windows上安装MySQL Server时启用它, 也可以在 MySQL Workbench 6.3.4的帮助下安装、禁用或卸载它。还可以通过在MySQL安装的共享目录中运行脚本手动安装防火墙。要启用防火墙,请在[mysqld]下面添加以下行,然后重新启动服务器:

mysql_firewall_mode=ON

防火墙也可以在运行时启用:

SET GLOBAL mysql_firewall_mode = ON;

或者,要保留防火墙(这意味着在每次后续服务器重新启动时不必重新启用防火墙):

SET PERSIST mysql_firewall_mode = ON;

然后,将FIREWALL_ADMIN权限授予管理防火墙的任何帐户,并将FIREVALL_USER权限授予应只能访问其自身防火墙规则的任何帐户。另外,授予mysql数据库中防火墙存储过程的EXECUTE权限。为了让防火墙发挥作用,向其注册配置文件,然后训练防火墙了解数据库可以执行的允许语句,然后告诉防火墙根据设置的白名单匹配传入语句。每个配置文件都有一个操作模式-关闭、记录、保护或检测。OFF禁用配置文件,RECORDING训练防火墙,PROTECTING允许或拒绝语句执行,DETECTING检测(但不阻止)入侵尝试。指定配置文件的规则可以通过将其值设置为reset来重置。OFF将禁用配置文件。要设置模式,请使用以下查询,其中name是配置文件名称,OFF是操作模式:

CALL mysql.sp_set_firewall_mode(name, ‘OFF’);

防火墙插件也仅在MySQL Enterprise Edition中可用。

保护MySQL备份

就MySQL备份而言,您有两种选择。

  • 如果您使用mysqldump,可以将用户名和密码存储在my.cnf中,并像这样调用mysqldump(以下命令将把所有数据库转储到文件/home/backup.sql中):
$ mysqldump --defaults-extra-file=/var/lib/my.cnf --single-transaction --all-databases > /home/backup.sql
  • 通过将您的用户名和密码存储在my.cnf,您不需要在终端中写入密码 - 这样的备份方法更安全,因为当转储正在运行时,可以通过ps -ax命令查看该命令。

  • 您还可以考虑使用mysqldump secure, 这是一个符合POSIX标准的包装器脚本,能够压缩和加密备份,同时考虑到强大的安全性。

  • 可以使用OpenSSL对备份进行加密

    • 只需获取备份,然后使用以下命令对其进行加密:
  $ openssl enc -aes-256-cbc -salt -in backup.tar.gz -out backup.tar.gz.enc -k password

上面的命令将当前目录中创建一个新的加密文件backup.tar.gz.enc。文件将使用您选择的密码进行加密(将密码替换为所需密码)。稍后可以通过运行以下命令对文件进行解密:

  $ openssl aes-256-cbc -d -in backup.tar.gz.enc -out backup.tar.gz -k password

用密码替换密码。

  • mysqldump还有另一个选项来加密备份(以下示例还使用gzip压缩备份):
 $ mysqldump --all-databases --single-transaction --triggers --routines | gzip | openssl  enc -aes-256-cbc -k password > backup.xb.enc

用自己的密码替换密码。

  • 您还可以使用mariabackup或xtrabackup加密备份。以下是MariaDB文档中的一个示例:
  $ mysqldump --all-databases --single-transaction --triggers --routines | gzip | openssl  enc -aes-256-cbc -k password > backup.xb.enc

用自己的密码替换密码。

  • 备份也可以使用ClusterControl 加密-如果为特定备份启用了加密选项,则ClusterControl将使用AES-256 CBC加密备份(加密发生在备份节点上)。如果备份存储在控制器节点上,则使用socat或netcat以加密格式传输备份文件。如果启用压缩,ClusterControl将首先压缩备份,然后对其进行加密。如果加密密钥不存在,将自动生成,然后存储在CMON配置的backup_encryption_key选项中。请记住,这个密钥是编码的,应该先解码。为此,请运行以下命令:
  $ cat /etc/cmon.d/cmon_ClusterID.cnf | grep ^backup_encryption_key | cut -d"'" -f2 | base64 -d > keyfile.key

该命令将读取backup_encryption_key并将其值解码为二进制输出。密钥文件可用于解密备份,如下所示:

 $ cat backup.aes256 | openssl enc -d -aes-256-cbc -pass file:/path/to/keyfile.key > backup_file.xbstream.gz

有关更多示例,请查看ClusterControl文档.

结论

在这两篇于MySQL安全的帖子中,我们介绍了MySQL的一些安全措施,如果您觉得需要加强MySQL实例的安全性,这些措施会很有用。虽然我们并没有完全涵盖所有内容,但我们认为这些要点可以作为一个良好起点。