MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,一般和PHP、JSP搭配使用。如果你想学习MySQL,请访问我们的MySQL教程。
在安全性配置方面,我们对MySQL数据库的整体要求是:机密性、完整性、可用性。
常见Mysql配置文件:linux系统下是my.conf,windows环境下是my.ini。下面以mysql 5.7版本为例,介绍mysql常见的安全策略、配置、加固方式等等,有些策略可能只针对Linux操作系统,更多策略可以参考CIS Mysql Benchmark相关文档。
一、操作系统级别安全配置
1、不要将数据库放在系统分区
Windows系统:直接检查是否将数据库放置在C盘。
Linux系统:在终端连接上mysql数据库,执行如下命令:
- show variables where variable_name = 'datadir';
然后返回shell命令行:
- df -h <datadir>
其中datadir是上一条命令的返回值。上述命令的返回值不应是/、/var、/usr
2、使用专用的最小权限账号运行mysql数据库进程
Windows系统:直接打开任务管理器,查看运行mysql进程的操作系统账号,不能为administrator账号。
Linux系统:Shell命令行运行如下命令:
- ps -ef | grep mysql
查看mysql服务的运行账号是否为root或其他高权限账号,如果是的,则需要创建一个非管理员专用账号来运行mysql服务(或者至少给root账号设置一个高强度的密码)。
3、禁止使用mysql命令行历史记录
Linux系统,执行如下命令:
- find / -name ".mysql_history"
查看是否存在mysql的历史命令记录文件,如果存在,则需要进行如下加固:
- 删除.mysql_history文件;
- 设置环境变量MYSQL_HISTFILE为/dev/null,并添加到shell的初始化脚本中,创建mysql_history到/dev/null的链接:
- ln -s /dev/null $HOME/.mysql_history
4、确保MYSQL_PWD环境变量未设置敏感信息
Windows系统下进入cmd命令行,然后敲入:“Set”,出来的结果是按字母顺序排列的。查看是否设置了环境变量MYSQL_PWD。
Linux系统下使用如下命令:
- grep MYSQL_PWD /proc/*/environ
查看MYSQL_PWD环境变量是否设置了敏感信息。确认那个配置文件或脚本设置了MYSQL_PWD环境变量。
5、改变root目录
Unix操作系统中的chroot可以改变当前正在运行的进程及其子进程的root目录。重新获得另一个目录root权限的程序无法访问或命名此目录之外的文件,此目录被称为“chroot监狱”。
通过利用chroot环境,你可以限制MySQL进程及其子进程的写操作,增加服务器的安全性。
你要保证chroot环境的一个专用目录,如/chroot/mysql。此外,为了方便利用数据库的管理工具,你可以在MySQL配置文件的[client]部分改变下面的参数:
- [client]
- socket = /chroot/mysql/tmp/mysql.sock
二、安装
1、使用数据库专用服务器
使用专用的服务器安装mysql服务可以减少mysql服务的攻击面,尽量卸载或删除操作系统上的不必要的应用或服务,减少其他应用的安装可能给mysql的运行带来的安全风险。
2、不要复用数据库账号
运行mysql服务的操作系统账号不要用来运行其他应用或服务,这样可以避免其他应用或服务器被攻击给mysql服务带来影响。
3、历史命令行密码设置为不可见
使用如下命令:
- mysql -u admin -p password
连接mysql数据库服务,退出后查看历史命令,确认password是否为明文。建议使用如下命令方式登录:
- 先输入mysql -u admin -p
- 根据命令行提示输入密码;
而不要在一整条命令中输入密码。另外要控制mysql配置文件访问权限。
三、文件权限控制
1、控制数据目录的访问权限
数据目录是mysql数据库存放的位置,在mysql命令行界面下执行如下命令:
- show variables where variable_name = 'datadir';
在终端命令行下执行如下命令:
- ls -l <datadir>/.. | egrep "^d[r|w|x]{3}------\s*.\s*mysql\s*mysql\s*\d*.*mysql"
其中<datadir>是第一条命令的执行结果。如果存在问题,linux环境下在终端执行如下命令进行加固:
- chmod 700 <datadir>
- chown mysql:mysql <datadir>
2、控制二进制日志文件的权限
mysql的运行会产生很多日志,例如二进制日志、错误日志、慢查询日志等等,Mysql命令行下执行如下命令:
- show variables like 'log_bin_basename';
在终端命令行执行如下命令:
- ls <log_bin_basename>.*
对于发现的每一个文件,执行如下命令:
- ls -l <log_bin_basename.nnnnn> | egrep "^-[r|w]{2}-[r|w]{2}----\s*.*$"
根据输出确认日志文件的权限设置是否存在问题。对于每个日志文件,修改其权限和属组如下:
- chmod 660 <log file>
- chown mysql:mysql <log file>
3、控制错误日志文件的权限
Mysql命令行下执行如下命令:
- show variables like 'log_error';
在终端命令行执行如下命令:
- ls <log_error>.*
对于发现的每一个文件,执行如下命令:
- ls -l <log_error> | egrep "^-[r|w]{2}-[r|w]{2}----\s*.*$"
根据输出确认日志文件的权限设置是否存在问题。对于每个日志文件,修改其权限和属组如下:
- chmod 660 <log file>
- chown mysql:mysql <log file>
4、控制慢查询日志文件的权限
Mysql命令行下执行如下命令:
- show variables like 'slow_query_log_file';
在终端命令行执行如下命令:
- ls <slow_query_log_file>.*
对于发现的每一个文件,执行如下命令:
- ls -l <slow_query_log_file> | egrep "^-[r|w]{2}-[r|w]{2}----\s*.*$"
根据输出确认日志文件的权限设置是否存在问题。对于每个日志文件,修改其权限和属组如下:
- chmod 660 <log file>
- chown mysql:mysql <log file>
5、控制通用日志文件的权限
Mysql命令行下执行如下命令:
- show variables like 'general_log_file';
在终端命令行执行如下命令:
- ls <general_log_file>.*
对于发现的每一个文件,执行如下命令:
- ls -l <general_log_file> | egrep "^-[r|w]{2}-[r|w]{2}----\s*.*$"
根据输出确认日志文件的权限设置是否存在问题。对于每个日志文件,修改其权限和属组如下:
- chmod 660 <log file>
- chown mysql:mysql <log file>
6、控制审计日志文件的权限
Mysql命令行下执行如下命令:
- show global variables where variable_name = 'audit_log_file';
在终端执行如下命令:
- ls -l <audit_log_file> | egrep "^-rw[-x]rw[-x][-r][-w][-x][ \t]*[0-9][ \t]*mysql[\t]*mysql.*$"
根据输出确认日志文件的权限设置是否存在问题。对于每个日志文件,修改其权限和属组如下:
- chmod 660 <audit_log_file>
- chown mysql:mysql <audit_log_file>
四、通用安全配置
1、安装最新的补丁
在mysql命令行下查询MySQL的版本:
- SHOW VARIABLES WHERE Variable_name LIKE "version";
确认是否由需要安装的补丁包,如果有请安装。
2、删除test数据库
Mysql数据库默认安装好后,存在一个名为test的数据库,如果存在,请执行如下命令删除:
- Drop database “test”
3、确保读取本地文件的参数设置为失效
Mysql命令行下,使用如下命令:
- SHOW VARIABLES WHERE Variable_name = 'local_infile';
查看结果是否为OFF。
如果该命令为ON,则数据库用户可以通过LOAD DATA INFILE 或者 SELECT local_file 读取到数据库所在操作系统本地的文件。LOCAL INFILE命令列示了所有的用户。解决此问题的最佳方法是在MySQL配置中禁用它,在CentOS中找到/etc/my.cnf或在Ubuntu中找到/etc/mysql/my.cnf,在[mysqld]部分增加下面一行:set-variable=local-infile=0。搞定。
- Local-infile=0;
然后重启数据库服务。
4、经常备份数据库
任何系统都有可能发生灾难。服务器、MySQL也会崩溃,也有可能遭受入侵,数据有可能被删除。只有为最糟糕的情况做好了充分的准备,才能够在事后快速地从灾难中恢复。企业最好把备份过程作为服务器的一项日常工作。
五、权限配置
1、控制可以访问所有数据库的账号
Mysql数据库下的user表和db表中存放着可以授予数据库用户的权限,确保只有管理员账号才能访问所有数据库。可以访问mysql数据库的用户或许可以查看密码哈希值、修改用户权限等等。
使用如下sql语句:
- SELECT user, host FROM mysql.user
- WHERE (Select_priv = 'Y') OR (Insert_priv = 'Y') OR (Update_priv = 'Y')
- OR (Delete_priv = 'Y') OR (Create_priv = 'Y') OR (Drop_priv = 'Y');
- SELECT user, host FROM mysql.db WHERE db = 'mysql'
- AND ((Select_priv = 'Y') OR (Insert_priv = 'Y') OR (Update_priv = 'Y')
- OR (Delete_priv = 'Y') OR (Create_priv = 'Y') OR (Drop_priv = 'Y'));
确保返回结果只能是数据库管理员账号。
2、限制非管理员用户的权限
Mysql.user表中的权限列有:
- file_priv:表示是否允许用户读取数据库所在主机的本地文件;
- Process:表示是否允许用户查询所有用户的命令执行信息;
- Super_priv:表示用户是否有设置全局变量、管理员调试等高级别权限;
- Shutdown_priv:表示用户是否可以关闭数据库;
- Create_user_priv:表示用户是否可以创建或删除其他用户;
- Grant_priv:表示用户是否可以修改其他用户的权限;
应确保只有数据库管理员才有上述权限,使用如下sql语句查看拥有各个权限的数据库账号:
- select user, host from mysql.user where File_priv = 'Y';
- select user, host from mysql.user where Process_priv = 'Y';
- select user, host from mysql.user where Process_priv = 'Y';
- SELECT user, host FROM mysql.user WHERE Shutdown_priv = 'Y';
- SELECT user, host FROM mysql.user WHERE Create_user_priv = 'Y';
- SELECT user, host FROM mysql.user WHERE Grant_priv = 'Y';
- SELECT user, host FROM mysql.db WHERE Grant_priv = 'Y';
确保查询结果中不存在非管理员用户。如果存在非管理员用户,使用如下命令进行权限回收:
- REVOKE FILE ON *.* FROM '<user>';
- REVOKE PROCESS ON *.* FROM '<user>';
- REVOKE SUPER ON *.* FROM '<user>';
- REVOKE SHUTDOWN ON *.* FROM '<user>';
- REVOKE CREATE USER ON *.* FROM '<user>';
- REVOKE GRANT OPTION ON *.* FROM <user>;
其中user为上述查询到的非管理员用户。
3、合理控制DML/DDL操作授权
DML/DDL语句包括创建或修改数据库结构的权限,例如insert、update、delete、create、drop和alter语句,在任何数据库中都要控制用户的此类权限,确保只授权给有业务需求的非管理员用户。Mysql命令行下执行如下命令:
- SELECT User,Host,Db FROM mysql.db WHERE Select_priv='Y'
- OR Insert_priv='Y' OR Update_priv='Y' OR Delete_priv='Y' OR Create_priv='Y'
- OR Drop_priv='Y' OR Alter_priv='Y';
上述查询到的用户只能对特地的数据库才有相关的权限,使用如下命令进行相关权限的回收:
- REVOKE SELECT ON <host>.<database> FROM <user>;
- REVOKE INSERT ON <host>.<database> FROM <user>;
- REVOKE UPDATE ON <host>.<database> FROM <user>;
- REVOKE DELETE ON <host>.<database> FROM <user>;
- REVOKE CREATE ON <host>.<database> FROM <user>;
- REVOKE DROP ON <host>.<database> FROM <user>;
- REVOKE ALTER ON <host>.<database> FROM <user>;
其中<user>为查询到的未授权的用户,host为相关主机,database为相关数据库。
4、避免从互联网访问MySQL数据库
直接通过本地网络之外的计算机改变生产环境中的数据库是异常危险的。有时,管理员会打开主机对数据库的访问:
- > GRANT ALL ON *.* TO ';root'@'%'
这其实是完全放开了对root的访问。所以,把重要的操作限制给特定主机非常重要:
- > GRANT ALL ON *.* TO 'root'@'localhost';
- > GRANT ALL ON *.* TO 'root'@'myip.athome'
- > FLUSH PRIVILEGES
此时,你仍有完全的访问,但只有指定的IP(不管其是否静态)可以访问。
5、禁用或限制远程访问
前面说过,如果使用了远程访问,要确保只有定义的主机才可以访问服务器。这一般是通过TCP wrappers、iptables或任何其它的防火墙软件或硬件实现的。为限制打开网络socket,管理员应当在my.cnf或my.ini的[mysqld]部分增加下面的参数:
- skip-networking
这些文件位于windows的C:\Program Files\MySQL\MySQL Server 5.1文件夹中,或在Linux中,my.cnf位于/etc/,或位于/etc/mysql/。这行命令在MySQL启动期间,禁用了网络连接的初始化。请注意,在这里仍可以建立与MySQL服务器的本地连接。
另一个可行的方案是,强迫MySQL仅监听本机,方法是在my.cnf的[mysqld]部分增加下面一行:
- bind-address=127.0.0.1
如果企业的用户从自己的机器连接到服务器或安装到另一台机器上的web服务器,你可能不太愿意禁用网络访问。此时,不妨考虑下面的有限许可访问:
- mysql> GRANT SELECT, INSERT ON mydb.* TO ';someuser'@'somehost'
这里,你要把someuser换成用户名,把somehost换成相应的主机。
6、降低系统特权
常见的数据库安全建议都有“降低给各方的特权”这一说法。对于MySQL也是如此。一般情况下,开发人员会使用最大的许可,不像安全管理一样考虑许可原则,而这样做会将数据库暴露在巨大的风险中。为保护数据库,务必保证真正存储MySQL数据库的文件目录是由”mysql” 用户和” mysql”组所拥有的。
- shell>ls -l /var/lib/mysql
此外,还要确保仅有用户”mysql”和root用户可以访问/var/lib/mysql目录。
Mysql的二进制文件存在于/usr/bin/目录中,它应当由root用户或特定的”mysql”用户所拥有。对这些文件,其它用户不应当拥有“写”的访问权:
- shell>ls -l /usr/bin/my*
7、降低用户的数据库特权
有些应用程序是通过一个特定数据库表的用户名和口令连接到MySQL的,安全人员不应当给予这个用户完全的访问权。如果攻击者获得了这个拥有完全访问权的用户,他也就拥有了所有的数据库。查看一个用户许可的方法是在MySQL控制台中使用命令SHOW GRANT:
- >SHOW GRANTS FOR ';user'@'localhost'
为定义用户的访问权,使用GRANT命令。在下面的例子中,user1仅能从dianshang数据库的billing表中选择:
- > GRANT SELECT ON billing.dianshang TO 'user1'@'localhost';
- > FLUSH PRIVILEGES;
如此一来,user1用户就无法改变数据库中这个表和其它表的任何数据。另一方面,如果你要从一个用户移除访问权,就应使用一个与GRANT命令类似的REVOKE命令:
- > REVOKE SELECT ON billing.ecommerce FROM 'user1'@'localhost';
- > FLUSH PRIVILEGES;
六、审计和日志
1、开启错误日志审计功能
错误日志包括数据库运行和停止过程中的一系列活动信息,有助于分析数据库运行过程中的一些异常活动,一般情况下需要开启错误日志记录功能,使用如下命令查询:
- SHOW variables LIKE 'log_error';
确保返回结果为非空,如果为空,需要在mysql数据库配置文件中增加相关配置。
2、确保日志存放在非系统区域
日志文件随着数据库的运行会不断增加,如果存放在系统区域,则会影响系统的正常运行,使用如下命令进行查询:
- SELECT @@global.log_bin_basename;
确保返回结果不是如下路径:/、/var、/usr
3、关闭原始日志功能
原始日志选项会决定一些敏感信息是否会被明文写进日志中,例如查询日志、慢查询日志、二进制日志,确保数据库配置文件中存在如下配置项:
- Log-raw = OFF
七、认证
1、Old_passwords环境变量设置
Old_passwords决定了使用PASSWORD()函数和IDENTIFIED BY 、CREATE USER 、GRANT 等语句是时的hash算法:
- 0 - authenticate with the mysql_native_password plugin
- 1 - authenticate with the mysql_old_password plugin
- 2 - authenticate with the sha256_password plugin
设置为mysql_old_password代表弱hash算法,可以快速通过密码字典进行暴力破解。使用如下命令查询相关值:
- SHOW VARIABLES WHERE Variable_name = 'old_passwords';
确保返回值不为1。
2、secure_auth 选项设置
如果客户端采用Old_passwords发起连接请求,如果服务器端设置了secure_auth,则客户端会拒绝连接请求,可以根据安全需求在配置文件中做相应配置。
3、密码保存
确保密码没有明文保存在全局配置文件中。
4、确保所有用户都要求使用非空密码登录
执行如下语句查询是否有用户不需要密码即可登录:
- SELECT User,host
- FROM mysql.user
- WHERE (plugin IN('mysql_native_password', 'mysql_old_password')
- AND (LENGTH(Password) = 0
- OR Password IS NULL))
- OR (plugin='sha256_password' AND LENGTH(authentication_string) = 0);
5、不存在空账号
使用如下命令查询是否存在空账号:
- SELECT user,host FROM mysql.user WHERE user = '';
八、网络设置
如果mysql数据库服务器与应用是跨信任域部署的,则需要考虑在数据库服务器与应用服务器之间建立ssl通道进行数据传输,不过这种场景一般很少见,在此不详细描述。
参考:https://www.2cto.com/database/201510/447903.html
http://blog.csdn.net/ilnature2008/article/details/54587553
转载本站内容时,请务必注明来自W3xue,违者必究。