1-系统安全配置
1.1 数据库存放位置检查
在linux系统中,数据库文件不宜存放在 /,/var,/usr目录内,执行以下命令进行检查
mysql> select @@datadir;
# 或者
mysql> show variables where variable_name='datadir';
加固方法
# 设置指定安全的路径
mysql> set global datadir='路径' ;
# 或者修改配置文件my.cnf(linux)或my.init(windows)中的datadir值
datadir='路径'
1.2 以最小权限账号运行mysql
- windows系统:打开任务管理器,查看运行mysql的是什么权限账号,不能是administrator
- linux系统: 不是是高权限账号(root)运行mysql,也不可以是在高权限用户组内
# ps命令查看进程, grep命令过滤结果
ps -ef | grep mysql
加固方法
# 1. 创建低权限账号和组
groupadd mysql
useradd -r -g mysql mysql
# 2. 给新建账号添加密码
passwd mysql
# 3. 修改MYSQL安装目录的权限(提前关闭mysql服务)
chown -R mysl.mysql mysql安装路径
# 4. 读写执行权限最小化755
chmod 755 mysql安装根路径
chmod 755 mysql安装后执行目录(bin)
chmod 755 mysql安装后lib库(libexec)
chmod -R go-rwx mysql数据存储目录(data)
# 5.重启mysql服务即可
service mysqld start
使用其它Linux用户启动mysqld,增加user选项指定/etc/my.cnf选项文件或服务器数据目录的my.cnf选项文件中的[mysqld]组的用户名。
vim /etc/my.cnf
[mysqld]
user=mysql
1.3 禁用mysql命令行历史记录
查看系统中是存在.mysql_history文件,若存在则需要加固
find / -name ".mysql_history"
加固方法
echo "export MYSQL_HISTORY=dev/null" >> /etc/profile
ln -s /dev/null .mysql_history文件路径
rm -r .mysql_history文件路径
1.4 检查MYSQL_PWD环境变量
使用如下命令,查看MYSQL_PWD环境变量是否设置了敏感信息
grep MYSQL_PWD /proc/*/environ
2-密码安全配置
2.1 空密码检查
# 检查是否存在密码长度为0的用户
mysql> select user,host from mysql.user where length(authentication_string) = 0;
# 通过mysql.user系统表查看全部数据库用户状态
mysql> select user,host,authentication_string,password_lifetime,account_locked from mysql.user;
2.2 密码复杂度配置
MySQL 系统自带有 validate_password 插件,此插件可以验证密码强度,未达到规定强度的密码不允许被设置。MySQL 5.7 及 8.0 版本默认情况下均不启用该插件。
(1)插件安装检查
进入 MySQL 命令行,通过 show plugins 或者查看 validate_password 相关参数可以判断是否已安装此插件
# 插件安装检查,返回为空表示未安装
mysql> show variables like 'validate%';
(2)validate_password 插件安装
# 安装插件
mysql> INSTALL PLUGIN validate_password SONAME 'validate_password.so';
# 查看 validate_password 相关参数
mysql> show variables like 'validate%';
+--------------------------------------+--------+
| Variable_name | Value |
+--------------------------------------+--------+
| validate_password_check_user_name | ON |
| validate_password_dictionary_file | |
| validate_password_length | 8 |
| validate_password_mixed_case_count | 1 |
| validate_password_number_count | 1 |
| validate_password_policy | MEDIUM |
| validate_password_special_char_count | 1 |
+--------------------------------------+--------+
7 rows in set (0.00 sec)
(3)参数释意
1、validate_password_policy
代表密码策略,默认是MEDIUM 可配置的值有以下:
0 or LOW 仅需需符合密码长度(由参数validate_password_length指定)
1 or MEDIUM 满足LOW策略,同时还需满足至少有1个数字,小写字母,大写字母和特殊字符
2 or STRONG 满足MEDIUM策略,同时密码不能存在字典文件(dictionary file)中
2、validate_password_dictionary_file
用于配置密码的字典文件,当validate_password_policy设置为STRONG时可以配置密码字典文件,字典文件中存在的密码不得使用。
3、validate_password_length
用来设置密码的最小长度,默认值是8
4、validate_password_mixed_case_count
当validate_password_policy设置为MEDIUM或者STRONG时,密码中至少同时拥有的小写和大写字母的数量,默认是1最小是0;默认是至少拥有一个小写和一个大写字母。
5、validate_password_number_count
当validate_password_policy设置为MEDIUM或者STRONG时,密码中至少拥有的数字的个数,默认1最小是0
6、validate_password_special_char_count
当validate_password_policy设置为MEDIUM或者STRONG时,密码中至少拥有的特殊字符的个数,默认1最小是0
(4)密码复杂度策略设置
# 设置密码长度至少10位
mysql> set global validate_password_length = 10;
Query OK, 0 rows affected (0.00 sec)
(5)配置文件写入
如果想让密码复杂度策略永久生效,可以在 /etc/mysql/mysql.conf.d/mysqld.cnf 文件中写入如下配置
[mysqld]
plugin-load = "validate_password.so"
validate-password = FORCE_PLUS_PERMANENT
validate_password_length = 8
validate_password_policy = 1
validate_password_mixed_case_count = 1
validate_password_number_count = 1
validate_password_special_char_count = 1
2.3 密码有效期检查
(1)设置全局过期策略
# 运行中临时生效
mysql> SET GLOBAL default_password_lifetime = 90;
Query OK, 0 rows affected (0.01 sec)
# 修改配置文件使得永久生效
[mysqld]
default_password_lifetime = 90
# 查询全局密码过期时间
mysql> show global variables like 'default_password_lifetime';
(2)设置单个用户密码过期策略
# 通过mysql.user系统表查看全部数据库用户状态
mysql> select user,host,password_expired,password_lifetime,password_last_changed,account_locked from mysql.user;
# 设置user1用户密码立即过期
mysql> ALTER USER 'user1'@'%' PASSWORD EXPIRE;
# 设置user1用户密码永不过期
mysql> ALTER USER 'user1'@'%' PASSWORD EXPIRE NEVER;
# 设置user1用户密码90天过期
mysql> ALTER USER 'user1'@'%' PASSWORD EXPIRE INTERVAL 90 DAY;
# 设置user1用户密码使用全局密码过期策略
mysql> ALTER USER 'user1'@'%' PASSWORD EXPIRE DEFAULT;
3-用户安全配置
3.1 远程管理限制
(1)原则上,应当禁止远程登录(至少要禁止root直接远程登录数据库)
执行以下SQL语句检查 host 字段是否仅为 127.0.0.1 或 localhost 或 ::1
mysql> select user,host from mysql.user where user='root';
(2)其它用户如需远程连接,应做访问范围限制
执行以下SQL语句检查是否存在任意IP登录的用户
mysql> select user,host from mysql.user where host = '%';
(3)远程管理用户配置方法
<password> 指定远程连接时使用的密码,与本地密码可不同(但需符合密码复杂度要求)
mysql> GRANT ALL PRIVILEGES ON <databases-name>.* TO 'user'@'<ip>' IDENTIFIED BY '<password>' WITH GRANT OPTION;
mysql> FLUSH PRIVILEGES;
# 例如:给teacher用户分配student数据库,只允许192.168.56.%网段远程连接并设置口令为Admin123
mysql> GRANT ALL PRIVILEGES ON student.* TO 'teacher'@'192.168.56.%' IDENTIFIED BY 'Admin123' WITH GRANT OPTION;
mysql> FLUSH PRIVILEGES;
3.2 删除默认数据库和用户
mysql> show databases;
mysql> drop database test; #删除数据库test
mysql> use mysql;
mysql> delete from db; #删除存放数据库的表信息,因为还没有数据库信息。
mysql> delete from user where not (user='root'); #删除初始非root的用户
mysql> delete from user where user='root' and password=''; #删除空密码的root尽量重复操作
mysql> flush privileges; #强制刷新内存授权表。
3.3 特权账号检查
user表和db表中存放着可以授予数据库用户的权限,确保只有管理员账号才能访问所有数据库
执行如下SQL语句, 确保返回结果只能是数据库管理员账号
mysql> 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');
mysql> 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'));
3.4 限制非管理员用户的权限
user表中的权限列有:
file_priv:表示是否允许用户读取数据库所在主机的本地文件;
Process:表示是否允许用户查询所有用户的命令执行信息;
Super_priv:表示用户是否有设置全局变量、管理员调试等高级别权限;
Shutdown_priv:表示用户是否可以关闭数据库;
Create_user_priv:表示用户是否可以创建或删除其他用户;
Grant_priv:表示用户是否可以修改其他用户的权限;
应确保只有数据库管理员才有上述权限,使用如下sql语句查看拥有各个权限的数据库账号,确保查询结果中不存在非管理员用户
mysql> select user, host from mysql.user where File_priv = 'Y';
mysql> select user, host from mysql.user where Process_priv = 'Y';
mysql> select user, host from mysql.user where Process_priv = 'Y';
mysql> SELECT user, host FROM mysql.user WHERE Shutdown_priv = 'Y';
mysql> SELECT user, host FROM mysql.user WHERE Create_user_priv = 'Y';
mysql> SELECT user, host FROM mysql.user WHERE Grant_priv = 'Y';
mysql> SELECT user, host FROM mysql.db WHERE Grant_priv = 'Y';
如果存在非管理员用户,可以使用如下命令进行权限回收,其中<user>为上述查询到的非管理员用户
mysql> REVOKE FILE ON *.* FROM '<user>';
mysql> REVOKE PROCESS ON *.* FROM '<user>';
mysql> REVOKE SUPER ON *.* FROM '<user>';
mysql> REVOKE SHUTDOWN ON *.* FROM '<user>';
mysql> REVOKE CREATE USER ON *.* FROM '<user>';
mysql> REVOKE GRANT OPTION ON *.* FROM <user>;
3.5 控制DML/DDL操作授权
DML/DDL语句包括创建或修改数据库结构的权限,例如insert、update、delete、create、drop和alter语句,在任何数据库中都要控制用户的此类权限,确保只授权给有业务需求的非管理员用户。
在MySQL命令行下执行如下命令进行检查
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';
在上述查询结果中,应该具有针对性地为每个用户设置相关数据库权限,使用如下命令进行相关权限的回收,其中<user>为查询到的未授权的用户,host为相关主机,database为相关数据库
mysql> REVOKE SELECT ON <host>.<database> FROM <user>;
mysql> REVOKE INSERT ON <host>.<database> FROM <user>;
mysql> REVOKE UPDATE ON <host>.<database> FROM <user>;
mysql> REVOKE DELETE ON <host>.<database> FROM <user>;
mysql> REVOKE CREATE ON <host>.<database> FROM <user>;
mysql> REVOKE DROP ON <host>.<database> FROM <user>;
mysql> REVOKE ALTER ON <host>.<database> FROM <user>;
4-文件权限配置
4.1 配置数据目录的访问权限
数据目录是mysql数据库存放的位置,在MySQL命令行界面下执行如下命令:
mysql> show variables where variable_name = 'datadir';
在终端命令行下执行如下命令:
# <datadir>是上述命令的执行结果
ls -l <datadir>/.. | egrep "^d[r|w|x]{3}------\s*.\s*mysql\s*mysql\s*\d*.*mysql"
若存在问题,执行如下命令进行加固
chmod 700 <datadir>
chown mysql:mysql <datadir>
4.2 配置二进制日志文件的权限
mysql的运行会产生很多日志,例如二进制日志、错误日志、慢查询日志等等,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>
4.3 配置错误日志文件的权限
在MySQL命令行下执行如下命令:
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.4 配置慢查询日志文件的权限
在MySQL命令行下执行如下命令:
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>
4.5 配置通用日志文件的权限
在MySQL命令行下执行如下命令:
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>
4.6 配置审计日志文件的权限
在MySQL命令行下执行如下命令:
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>
5-入侵防护
5.1 设置连接超时时间
# 查看空闲连接超时时间
mysql> SHOW GLOBAL VARIABLES LIKE '%timeout%'
# 修改空闲连接超时时间
mysql> SET GLOBAL wait_timeout=1800
6-审计和日志
6.1 开启错误日志审计功能
错误日志包括数据库运行和停止过程中的一系列活动信息,有助于分析数据库运行过程中的一些异常活动,一般情况下需要开启错误日志记录功能,使用如下命令查询:
mysql> SHOW variables LIKE 'log_error';
确保返回结果为非空,如果为空,需要在mysql数据库配置文件中增加如下配置
# 在/etc/my.cnf加入配置
[mysqld_safe]
log-error=log文件路径
6.2 确保日志存放在非系统区域
使用如下命令进行查询:
mysql> SELECT @@global.log_bin_basename;
确保返回结果不是如下路径:/、/var、/usr
6.3 关闭原始日志功能
原始日志选项会决定一些敏感信息是否会被明文写进日志中,例如查询日志、慢查询日志、二进制日志,确保数据库配置文件中存在如下配置项:
[mysqld_safe]
Log-raw = OFF