5个强化MySQL数据库的基本步骤


数据库一直是您平均架构的重要组成部分,可以说是最重要的部分。现在,这种趋势已经转向您的基础设施的大部分功能,这些功能是一次性的,无状态的,这会给您的数据库带来更大的可靠性和安全性,因为所有其他服务器不可避免地将状态信息与其余数据一起存储在数据库中。

您的数据库是每个攻击者都希望捕获的头奖。随着攻击越来越复杂,网络变得越来越敌对,比以往更重要的是采取额外措施来加强数据库。

由于其速度和总体易用性,MySQL一直是开发人员和管理员喜爱的数据库。不幸的是,这种易用性是以牺牲安全性为代价的。尽管MySQL可以配置严格的安全控制,但您的普通默认MySQL配置可能不会使用它们。在本文中,我将介绍您应该采取的五个重要步骤来强化MySQL数据库。


步骤1:设置强密码


所有数据库用户使用强密码是很重要的。鉴于大多数人不会经常手动登录数据库,请使用密码管理器或命令行工具pwgen为您的数据库帐户创建一个随机的20个字符的密码。即使您使用额外的MySQL访问控制来限制特定帐户可以登录的位置(例如严格限制帐户到本地主机),这一点也很重要。


设置密码的最重要的MySQL帐户是root用户。在许多系统中默认情况下,该用户将没有密码。特别是,当您安装MySQL时,基于Red Hat的系统不会设置密码; 虽然基于Debian的系统会在交互式安装时提示您输入密码,但非交互式安装(如您可能会使用配置管理器执行)会跳过它。另外,在交互式安装过程中,您仍然可以跳过设置密码。

你可能会认为不使用密码离开root用户不是一个很大的安全风险。毕竟,用户被设置为“root @ localhost”,您可能认为这意味着在成为该用户之前必须对该机器进行root操作。不幸的是,这意味着任何可以从本地主机触发MySQL客户端的用户都可以使用以下命令作为MySQL root用户登录:

$ mysql — user root

因此,如果您没有为root用户设置密码,那么任何能够在您的MySQL机器上获得本地shell的人现在都可以完全控制您的数据库。

要修复此漏洞,请使用mysqladmin命令为root用户设置密码:

$ sudo mysqladmin password

不幸的是,MySQL以root用户身份运行后台任务。一旦设置了密码,这些任务就会中断,除非您将密码硬编码到/root/.my.cnf文件中:

[mysqladmin]
user = root
password = yourpassword


不幸的是,这意味着您必须将密码以纯文本形式保存在主机上。但是您至少可以使用Unix文件权限来限制对该文件的访问权限,仅限于root用户:

$ sudo chown root:root /root/.my.cnf
$ sudo chmod 0600 /root/.my.cnf



步骤2:删除匿名用户


匿名帐户是既没有用户名也没有密码的MySQL帐户。您不希望攻击者在没有密码的情况下对数据库进行任何类型的访问,因此请在此命令的输出中查找以空白用户名记录的任何MySQL用户:

> SELECT Host, User FROM mysql.user;
+ — — — — — — — — — — — — + — — — -+
| Host | User |
+ — — — — — — — — — — — — + — — — -+
| 127.0.0.1 | root |
| ::1 | root |
| localhost | |
| localhost | root |
+ — — — — — — — — — — — — + — — — -+
4 rows in set (0.00 sec)

在这些root用户的中间是一个匿名用户(localhost),在用户列中有空白。你可以用这个命令摆脱那个特定的匿名用户:

> drop user “”@”localhost”;
> flush privileges;


如果您确定了其他匿名用户,请务必将其删除。



步骤3:遵循最小特权原则


最小特权原则是一种可以总结如下的安全原则:


只给一个帐户访问它需要做的工作,没有更多。

这个原理可以通过多种方式应用于MySQL。首先,在使用GRANT命令向特定用户添加数据库权限时,请确保将访问权限限制为用户需要访问的数据库:

> grant all privileges on mydb.* to someuser@”localhost” identified by ‘astrongpassword’;
> flush privileges;


如果该用户只需要访问某个特定的表(比如users表),可以使用``mydb.users``替换``mydb。*``(允许访问所有表)成为。

许多人会授予用户对数据库的完全访问权限; 但是,如果您的数据库用户只需要读取数据但不更改数据,请执行授予对数据库的只读访问权限的额外步骤:

> grant select privileges on mydb.* to someuser@”localhost” identified by ‘astrongpassword’;
> flush privileges;


最后,许多数据库用户不会从本地主机访问数据库,并且管理员通常会创建它们,如下所示:

> grant all privileges on mydb.* to someuser@”%” identified by ‘astrongpassword’;
> flush privileges;


这将允许“someuser”从任何网络访问数据库。但是,如果您有一组定义良好的内部IP或者甚至更好 - 建立了VLAN,以便所有应用程序服务器与其他主机位于不同的子网上,那么请利用限制“someuser”的方式,以便帐户只能从特定网络访问数据库:

> grant all privileges on mydb.* to someuser@10.0.1.0/255.255.255.0 identified by ‘astrongpassword’;
> flush privileges;


步骤4:启用TLS


如果攻击者可以通过网络读取密码或其他敏感数据,那么设置强密码只能让您获得目标。因此,使用TLS保护所有网络流量比以往任何时候都更加重要。


MySQL也不例外。

幸运的是,在MySQL中启用TLS相对简单。一旦你的主机有了有效的证书,只需在``[mysqld]``部分的主my.cnf文件中添加以下几行:

[mysqld]
ssl-ca=/path/to/ca.crt
ssl-cert=/path/to/server.crt
ssl-key=/path/to/server.key


为了获得额外的安全性,还可以在ssl-cipher配置选项中添加已批准的密码列表,而不是只接受默认的密码列表,其中可能包括较弱的TLS密码。我推荐Mozilla安全/服务器端TLS页面推荐的现代或中间密码套件。

一旦在服务器端建立了TLS,您还可以限制客户端,使其必须使用TLS进行连接,方法是将“REQUIRE SSL”添加到您的GRANT语句中:

> grant all privileges on mydb.* to someuser@10.0.1.0/255.255.255.0 identified by ‘astrongpassword’ REQUIRE SSL;
> flush privileges;


步骤5:加密数据库的秘密


尽管现在大多数人都知道用单向散列(理想情况下是像bcrypt这样的慢散列)来保护用户数据库存储的密码是多么重要,但通常没有多少考虑用加密来保护数据库中的其他敏感数据。事实上,许多管理员会告诉你他们的数据库已被加密,因为磁盘本身已被加密。这实际上会危及您的数据库强化,并不是因为磁盘加密存在缺陷或不正确的做法,而仅仅是因为它会给您带来错误的安全感。


如果有人从您的服务器上窃取磁盘(或者在您忘记擦除磁盘后用它们进行二手购买),则磁盘加密可以保护您的数据库数据,但在数据库本身运行时,磁盘加密不会保护您,因为该驱动器需要处于将被读取的解密状态。

为了保护数据库中的数据,您需要在存储敏感字段之前采取额外的加密措施。这样,如果攻击者发现某种方式执行完整的数据库转储,那么您的敏感字段仍然受到保护。

有许多方法可以对数据库中的字段进行加密,并且MySQL支持本机加密命令。无论您选择哪种加密方法,我都建议避免使用需要将解密密钥存储在数据库本身上的加密方法。

理想情况下,您应该将解密密钥作为本地GPG密钥存储在应用程序服务器上(如果您使用GPG进行加密),或将其作为环境变量存储在应用程序服务器上。这种方式即使攻击者可能找到破坏应用程序服务器上的服务的方式,他也必须将该攻击转变为本地shell访问才能获得解密密钥。

MySQL强化Maxim:掌握最低特权原则

有很多方法可以锁定你的MySQL服务器。具体执行这些步骤的方式取决于您自己的数据库的设置方式以及它在网络中的位置。


虽然前面的五个步骤将有助于保护您的数据库,但我认为,掌握最重要的整体步骤是最小特权原则。您的数据库可能存储了一些最有价值的数据,如果您确保用户和应用程序只有最低限度的访问权限才能完成他们的工作,那么如果黑客找到方法,您将限制攻击者能够执行的操作妥协该用户或应用程序。