MySQL数据库安全加固方法
基本安全原则
选择稳定、无漏洞版本并及时升级更新、打补丁
配置防火墙策略,更改默认端口
避免使用弱口令,定期更新口令
严格的权限分配和访问控制
具体安全配置
系统层面配置
系统安装时,需要确认没有其他⽤户登录在服务器上。建议在服务器本地安装,不使⽤⽹络远程安装。
数据库版本选择稳定、无漏洞的版本,并及时更新、打补丁
查看系统防火墙或网络安全设备,是否有限制对MySQL数据库的访问
不设置环境变量或确保MYSQL_PWD环境变量未设置敏感信息
禁止使用命令行历史记录 Linux系统:
执行如下命令:
find / -name ".mysql_history"
查看是否存在mysql的历史命令记录文件,如果存在,则需要进行如下加固:
(1)删除.mysql_history文件;
(2)设置环境变量MYSQL_HISTFILE为/dev/null,并添加到shell的初始化脚本中,创建mysql_history到/dev/null的链接:
ln -s /dev/null $HOME/.mysql_history
服务器配置
严禁将数据库服务器允许从公⽹直接访问,也严禁将数据库服务器配置公⽹IP或通过⽹络设备映射出公⽹IP。
在局域⽹内限制开放的端口。需要其他额外的端口,需要提出申请,并有⽂档记录。
服务器不应该具备访问外⽹的能⼒(如有必要,可单向访问)。
新的服务器正式投⼊使⽤前,必须经过安全加固。
数据库通信安全
通信加密 show variables like ‘have_openssl’;
have_openssl=YES
服务端证书验证 查看my.cnf文件[Client] 字段,已配置ssl_verify_server_cert参数
SSL连接配置 1.show variables like ‘ssl_cert’;
2.show variables like ‘ssl_key’;
3.show variables like ‘ssl_ca’;
⽤户和密码配置
严格限制Mysql帐户,使用专用的最小权限账号运行Mysql数据库进程
重命名root账号
禁止数据库账号共用
控制最高权限只有管理员 使用如下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'));
确保返回结果只能是数据库管理员账号。
限制非管理员用户的权限 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 Super_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 Reload_priv = 'Y';
SELECT user, host FROM mysql.db WHERE Grant_priv = 'Y';
确保查询结果中不存在非管理员用户。
如果存在非管理员用户,使用如下命令进行权限回收:
REVOKE FILE ON *.* FROM '';
REVOKE PROCESS ON *.* FROM '';
REVOKE SUPER ON *.* FROM '';
REVOKE SHUTDOWN ON *.* FROM '';
REVOKE CREATE USER ON *.* FROM '';
REVOKE GRANT OPTION ON *.* FROM ;
其中user为上述查询到的非管理员用户。
合理控制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 .FROM ;
REVOKE INSERT ON .FROM ;
REVOKE UPDATE ON .FROM ;
REVOKE DELETE ON .FROM ;
REVOKE CREATE ON .FROM ;
REVOKE DROP ON .FROM ;
REVOKE ALTER ON .FROM ;
其中为查询到的未授权的用户,host为相关主机,database为相关数据库。
历史命令行密码设置为不可见 (1)先输入mysql -u admin -p
(2)根据命令行提示输入密码;
而不要在一整条命令中输入密码。
另外要控制mysql配置文件访问权限
删除默认test数据库,测试帐号,空密码、匿名帐号 bash drop database if exists ${dbname};
#删除冗余数据库, 如test
bash drop user ''
#清除无用用户(没有用户名的用户)
SELECT user,host FROM mysql.user WHERE user = '';
#使用该命令查询是否存在空账号
禁止root远程登录 use mysql;
# 切换到mysql数据库(这是MySQL自带的一个数据库,里面存放着一些root的配置信息);
update user set host = "localhost" where user = "root" and host = "%";
# 修改root用户的host属性,确保其为localhost,这表示只能本地访问(%表示可以远程访问);
flush privileges; #刷新
关闭Old_Passwords mysql> show variables like ‘%password%’;
+—————+——-+
| Variable_name | Value |
+—————+——-+
| old_passwords | OFF | ####这里表明已经关闭了旧密码选项
+—————+——-+
1 row in set (0.00 sec)
secure_auth选项设置 如果客户端采用Old_passwords发起连接请求,如果服务器端设置了secure_auth,则客户端会拒绝连接请求,可以根据安全需求在配置文件中做相应配置。
维护脚本禁止存放明文密
确保所有用户都要求使用非空密码登录 执行如下语句查询是否有用户不需要密码即可登录:
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);
文件权限配置
控制二进制日志文件的权限 mysql的运行会产生很多日志,例如二进制日志、错误日志、慢查询日志等等,Mysql命令行下执行如下命令:
show variables like 'log_bin_basename';
在终端命令行执行如下命令:
ls .*
对于发现的每一个文件,执行如下命令:
ls -l | egrep "^-[r|w]{2}-[r|w]{2}----\s*.*$"
# 根据输出确认日志文件的权限设置是否存在问题。
对于每个日志文件,修改其权限和属组如下:
chmod 660 chown mysql:mysql
控制数据目录、基准目录的访问权限 数据目录是mysql数据库存放的位置,在mysql命令行界面下执行如下命令:
show variables where variable_name = 'datadir';
在终端命令行下执行如下命令:
ls -l /.. | egrep "^d[r|w|x]{3}------\s*.\s*mysql\s*mysql\s*\d*.*mysql"
# 其中是第一条命令的执行结果
如果存在问题,linux环境下在终端执行如下命令进行加固:
chmod 700 #仅MySQL数据库用户有读写权限
chown mysql:mysql
同理控制基准目录权限 ,仅DBA和数据库用户可访问
控制错误日志文件的权限 Mysql命令行下执行如下命令:
show variables like 'log_error';
在终端命令行执行如下命令:
ls .*
对于发现的每一个文件,执行如下命令:
ls -l | egrep "^-[r|w]{2}-[r|w]{2}----\s*.*$"
# 根据输出确认日志文件的权限设置是否存在问题。
对于每个日志文件,修改其权限和属组如下:
chmod 660 chown mysql:mysql
控制慢查询日志文件的权限 Mysql命令行下执行如下命令:
show variables like 'slow_query_log_file';
在终端命令行执行如下命令:
ls .*
对于发现的每一个文件,执行如下命令:
ls -l | egrep "^-[r|w]{2}-[r|w]{2}----\s*.*$"
根据输出确认日志文件的权限设置是否存在问题。
对于每个日志文件,修改其权限和属组如下:
chmod 660 chown mysql:mysql
控制通用日志文件的权限 Mysql命令行下执行如下命令:
show variables like 'general_log_file';
在终端命令行执行如下命令:
ls .*
对于发现的每一个文件,执行如下命令:
ls -l | egrep "^-[r|w]{2}-[r|w]{2}----\s*.*$"
# 根据输出确认日志文件的权限设置是否存在问题。
对于每个日志文件,修改其权限和属组如下:
chmod 660 chown mysql:mysql
控制审计日志文件的权限 Mysql命令行下执行如下命令:
show global variables where variable_name = 'audit_log_file';
在终端执行如下命令:
ls -l | egrep "^-rw[-x]rw[-x][-r][-w][-x][ \t]*[0-9][ \t]*mysql[
\t]*mysql.*$"
# 根据输出确认日志文件的权限设置是否存在问题。
对于每个日志文件,修改其权限和属组如下:
chmod 660 chown mysql:mysql
审计和日志
开启错误日志审计功能 错误日志包括数据库运行和停止过程中的一系列活动信息,有助于分析数据库运行过程中的一些异常活动,一般情况下需要开启错误日志记录功能,使用如下命令查询:
SHOW variables LIKE 'log_error';
确保返回结果为非空,如果为空,需要在mysql数据库配置文件中增加相关配置
确保日志存放在非系统区域 日志文件随着数据库的运行会不断增加,如果存放在系统区域,则会影响系统的正常运行,使用如下命令进行查询:
SELECT @@global.log_bin_basename;
确保返回结果不是如下路径:/、/var、/usr
关闭原始日志功能 原始日志选项会决定一些敏感信息是否会被明文写进日志中,例如查询日志、慢查询日志、二进制日志,确保数据库配置文件中存在如下配置项:
Log-raw = OFF