MySQL数据库安全评估工具MySQL Database Security Assessment Tool
MySAT执行多项测试以分析数据库配置和安全策略。MySAT可以帮助评估并因此提高MySQL数据库的安全性。
MySAT是一个简单的SQL脚本,它易于理解,易于维护。MySAT的结果是一份HTML格式的报告。
MySQL数据库安全评估工具 https://github.com/meob/MySAT
MySAT在HTML中生成一个简单明了的报告。MySAT报告包含3个部分:
安全检查结果
配置摘要和细节
与GDPR文章和CIS基准以及CVE短名单的交叉引用
以下是mysql 8.0.33数据库为例,容器实例名c2mysql
mysql docker容器內执行
复制SQL到容器內
docker cp mysat.80.sql c2mysql:/home
docker cp mysat.css c2mysql:/home
#进入容器
docker exec -it c2mysql /bin/bash
#执行生成检测报告
mysql --user=root -pxxxxxxxxxxxx --skip-column-names -f < mysat.80.sql > MySAT.htm
#把结果导出
docker cp c2mysql:/home/MySAT.htm MySAT.htm
报告示例:
MySQL加固
MySQL所使用的 SQL 语言是用于访问数据库的最常用标准化语言。MySQL 软件采用了双授权政策,分为社区版和商业版,由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,一般中小型网站的开发都选择 MySQL 作为网站数据库。
mysql目录结构
配置文件,也就是后缀为.cnf
的文件,大家自己看看文件内容就知道每个文件的作用了。
我们来看mysql的帮助信息,里面有一条指明了mysql的配置文件是哪个,然后根据我们的情况就可以确定,mysql配置文件为/etc/mysql/my.cnf
,因为其它两个文件不存在。
root@NF:~# mysql --help |grep -A 1 'Default options'
Default options are read from the following files in the given order:
/etc/my.cnf etc/mysql/my.cnf ~/.my.cnf
那我们查看一下/etc/mysql/my.cnf
文件的内容(跟/etc/mysql/mysql.cnf
内容一样)主要有下面这些信息,也说明了/etc/mysql/my.cnf
是全局配置,~/.my.cnf
(隐藏文件本环境下无此文件)是个人用户设置。
# The MySQL database server configuration file.
#
# You can copy this to one of:
# - "/etc/mysql/my.cnf" to set global options,
# - "~/.my.cnf" to set user-specific options.
!includedir /etc/mysql/conf.d/
#表示包含/etc/mysql/conf.d/这个路径下面的配置文件,前提是必须以为.cnf为后缀
!includedir /etc/mysql/mysql.conf.d/
#表示包含/etc/mysql/mysql.conf.d/这个路径下面的配置文件,前提是必须以为.cnf为后缀
然后我们看/etc/mysql/mysql.conf.d/mysql.conf.d,这个文件里面提供了mysql常用的基本配置。
那我们在此文件编辑mysql的配置,发现是可以失效的,它包含于/etc/mysql/my.cnf文件,所以编辑mysql配置的时候就编辑/etc/mysql/mysql.conf.d/mysql.conf.d文件即可。
其它的相关文件,其实就是理解linux各个主要目录是什么作用的。
/usr/lib/mysql # 动态库文件(.so文件,so=shared object)
/usr/bin/mysql # mysql命令,安装的软件的命令,usr指Unix System Resource
/usr/share/mysql # mysql共享数据,主要是一些帮助文档
/etc/mysql # mysql配置文件目录
/etc/init.d/mysql # 服务管理脚本(启动,停止,关闭等)
/var/lib/mysql # 默认的数据文档存储目录
/var/log/mysql # mysql日志文件(查询语句记录,报错日志,慢查询日志等)
00 关注官方安全更新公告
在不影响业务正常运行的情况下,及时更新软件,打补丁。
https://www.oracle.com/security-alerts/
01 禁止数据库用户的密码为空并设置密码有效期
执行如下执行SQL语句检查密码是否为空:
select user,host from mysql.user where length(authentication_string) = 0;
或
select user,host,authentication_string,password_lifetime,account_locked from mysql.user;
若存在空密码的数据库用户,则执行如下命令设置数据库用户密码,且密码必须满足密码策略的要求:
set password for 'user'@'host' = password('yourpassword');
set password for 'testtest'@'192.168.56.1' = password('testtest');
另外还要注意:
禁用或限制匿名、默认账户、测试账户的访问权限;(禁用账户)
应重命名或删除默认账户,修改默认账户的默认口令;
应及时删除或停用多余的、过期的账户,避免共享账户的存在;
删除了默认数据库TEST。(旧版本会有默认的测试数据库)
禁用数据库用户的语句
ALTER USER 'user'@'host' ACCOUNT LOCK;
查看密码有效期(全局变量)
mysql> show global variables like 'default_password_lifetime';
+---------------------------+-------+
| Variable_name | Value |
+---------------------------+-------+
| default_password_lifetime | 0 |
+---------------------------+-------+
1 row in set (0.00 sec)
配置密码有效期全局变量,编辑mysql配置文件,添加下面内容。
default_password_lifetime = 180
配置某个用户的密码有效期,使用ALTER USER命令为每个具体的用户账户单独设置特定的值,它会自动覆盖密码过期的全局策略。要注意ALTER USER语句的INTERVAL的单位是“天”。
ALTER USER 'root'@'localhost' PASSWORD EXPIRE INTERVAL 180 DAY;
02 检查数据库用户的密码是否为弱口令
有些人为了方便,可能会把数据库用户的密码设置为弱口令,现在的数据库会以mysql5加密算法加密口令,可以去MD5解密的平台输入密文,看能否得出明文。
https://www.cmd5.com/
https://www.somd5.com/
如果是弱口令,则要求更改其数据库用户的口令。
关于MySQL密码你应该知道的那些事 - cenalulu
MySQL:密码加密方式 - xuejianbest
03 密码复杂度配置
在数据库配置文件/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
validate-password = FORCE_PLUS_PERMANENT
值为FORCE_PLUS_PERMANENT
表示强制启用该插件,并且不能被卸载。
validate_password_policy
表示密码策略,有三个值,与其对应的策略见下表:
值
密码策略
0 或 LOW
校验密码长度变量
1 或 MEDIUM
校验密码长度、数字、小写/大写和特殊字符4个变量
2 或 STRONG
校验密码长度、数字、小写/大写、特殊字符和字典文件5个变量
简言之,对于密码数字、小写/大写和特殊字符这三个变量,只有当密码策略为中或强时才是有效的。
其它参数含义见下面的引用文章。
那么最低要求配置如下
效果:密码不能与用户名一致,密码长度8位以上(包含8位)、至少有一个数字、一个大写字母、一个小写字母、一个特殊字符。
mysql> show variables like '%validate_password%';
+--------------------------------------+--------+
| Variable_name | Value |
+--------------------------------------+--------+
| validate_password_check_user_name | OFF |
| 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)
安装和卸载插件
validate_password插件相关参数的介绍
MySql5.6使用validate password 插件加强密码强度的安装及使用方法 - wangmm0218
04 登录失败和连接超时设置
mysql有个连接超时的插件,相当于登录失败锁定策略,可根据业务需要进行最低配置。
默认配置如下:
mysql> show variables like "%connection_control%";
+-------------------------------------------------+-------+
| Variable_name | Value |
+-------------------------------------------------+-------+
| connection_control_failed_connections_threshold | 3 |
| connection_control_max_connection_delay | 86400 |
| connection_control_min_connection_delay | 1000 |
+-------------------------------------------------+-------+
3 rows in set (0.00 sec)
connection_control_failed_connections_threshold
失败尝试的次数,默认为3,表示当连接失败3次后启用连接控制0表示不开启
connection_control_max_connection_delay
响应延迟的最大时间
connection_control_min_connection_delay
响应延迟的最小时间,默认1000微秒,1秒
然后是超时时间设置。
查看和设置 连接超时相关的两个参数interactive_timeout和wait_timeout,其值应当至多为30分钟。
show global variables like 'interactive_timeout';
show global variables like 'wait_timeout';
set global interactive_timeout=1800;
set global wait_timeout=1800;
interactive_timeout:交互式连接超时时间(mysql工具、mysqldump等)
wait_timeout:非交互式连接超时时间、默认的连接mysql api程序、jdbc连接数据库等
简单来说,通过mysql客户端连接数据库是交互式连接,通过jdbc连接数据库是非交互式连接。
连接控制插件安装
MySQL安全插件:Connection-Control Plugins 的利与弊 - leonpenn
MySQL 插件之 连接控制插件(Connection-Control) - ZhenXing_Yu
MySQL连接超时相关的两个参数interactive_timeout和wait_timeout的区别和解释 - young5201314
MySQL参数max_connect_errors分析释疑 - 潇湘隐者
MySQL状态变量Aborted_connects与Aborted_clients浅析 -海东潮
05 启用SSL
查看是否启用SSL(如果启用了SSL需要进行配置才能正常远程连接管理)。
validate-password = FORCE_PLUS_PERMANENT
值为FORCE_PLUS_PERMANENT
表示强制启用该插件,并且不能被卸载。
validate_password_policy
表示密码策略,有三个值,与其对应的策略见下表:
值
密码策略
0 或 LOW
校验密码长度变量
1 或 MEDIUM
校验密码长度、数字、小写/大写和特殊字符4个变量
2 或 STRONG
校验密码长度、数字、小写/大写、特殊字符和字典文件5个变量
简言之,对于密码数字、小写/大写和特殊字符这三个变量,只有当密码策略为中或强时才是有效的。
其它参数含义见下面的引用文章。
那么最低要求配置如下
效果:密码不能与用户名一致,密码长度8位以上(包含8位)、至少有一个数字、一个大写字母、一个小写字母、一个特殊字符。
mysql> show variables like '%validate_password%';
+--------------------------------------+--------+
| Variable_name | Value |
+--------------------------------------+--------+
| validate_password_check_user_name | OFF |
| 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)
安装和卸载插件
validate_password插件相关参数的介绍
MySql5.6使用validate password 插件加强密码强度的安装及使用方法 - wangmm0218
04 登录失败和连接超时设置
mysql有个连接超时的插件,相当于登录失败锁定策略,可根据业务需要进行最低配置。
默认配置如下:
mysql> show variables like "%connection_control%";
+-------------------------------------------------+-------+
| Variable_name | Value |
+-------------------------------------------------+-------+
| connection_control_failed_connections_threshold | 3 |
| connection_control_max_connection_delay | 86400 |
| connection_control_min_connection_delay | 1000 |
+-------------------------------------------------+-------+
3 rows in set (0.00 sec)
connection_control_failed_connections_threshold
失败尝试的次数,默认为3,表示当连接失败3次后启用连接控制,0表示不开启
connection_control_max_connection_delay
响应延迟的最大时间
connection_control_min_connection_delay
响应延迟的最小时间,默认1000微秒,1秒
然后是超时时间设置。
查看和设置 连接超时相关的两个参数interactive_timeout和wait_timeout,其值应当至多为30分钟。
show global variables like 'interactive_timeout';
show global variables like 'wait_timeout';
set global interactive_timeout=1800;
set global wait_timeout=1800;
interactive_timeout:交互式连接超时时间(mysql工具、mysqldump等)
wait_timeout:非交互式连接超时时间、默认的连接mysql api程序、jdbc连接数据库等
简单来说,通过mysql客户端连接数据库是交互式连接,通过jdbc连接数据库是非交互式连接。
连接控制插件安装
MySQL安全插件:Connection-Control Plugins 的利与弊 - leonpenn
MySQL 插件之 连接控制插件(Connection-Control) - ZhenXing_Yu
MySQL连接超时相关的两个参数interactive_timeout和wait_timeout的区别和解释 - young5201314
MySQL参数max_connect_errors分析释疑 - 潇湘隐者
MySQL状态变量Aborted_connects与Aborted_clients浅析 -海东潮
05 启用SSL
查看是否启用SSL(如果启用了SSL需要进行配置才能正常远程连接管理)。
mysql> show variables like '%ssl';
+---------------+----------+
| Variable_name | Value |
+---------------+----------+
| have_openssl | DISABLED |
| have_ssl | DISABLED |
+---------------+----------+
2 rows in set (0.01 sec)
说明:如果数据库禁止远程管理(select user,host from mysql.user;
),则已经符合安全要求,此情况下已无需启用SSL。
MySQL SSL配置(mysql5.7和mysql5.6) - Yuki_xiong
MYSQL SSL配置与使用 - 德莱華
06 远程管理限制
其实最好还是应当禁止远程登录至少要禁止root直接远程登录管理数据库。
执行select user,host from mysql.user where user='root';
看访问地址是否仅为 127.0.0.1 或 localhost 或 ::1
其它用户如需远程连接,应做访问范围限制。
执行select user,host from mysql.user where host = '%';
若host字段为:% (允许任何IP连接),则说明不合规。
远程连接管理配置方法:
GRANT ALL PRIVILEGES ON <databases-name>.* TO 'user'@'<ip>' IDENTIFIED BY '<password>' WITH GRANT OPTION;
FLUSH PRIVILEGES;
<databases-name> 指定单个数据库名 也可以用 *(即所有数据库名)
user 指定一个数据库用户名
<ip> 指定一个IP、一个网段(包括B段、C段 192.168.1.%)、%(所有IP)
<password> 指定远程连接时使用的密码,与本地密码可不同(但需符合密码复杂度要求)
# 举例,给数据库用户teacher分配student数据库,只允许192.168.56.%网段远程连接并设置口令为Admin123。
GRANT ALL PRIVILEGES ON student.* TO 'teacher'@'192.168.56.%' IDENTIFIED BY 'Admin123' WITH GRANT OPTION;
FLUSH PRIVILEGES;
效果如下
最后可以在mysql.user表中看到账号的情况,也是从这里删除。
select user,host from mysql.user where account_locked='N' and host!='localhost';
drop user 'user'@'host';
知识补充-drop和delete的区别
drop
drop user XXX;删除已存在的用户,默认删除的是'XXX'@'%'这个用户,如果还有其他的用户(其它主机名),如'XXX'@'localhost'等,不会一起被删除。如果要删除'XXX'@'localhost',使用drop删除时需要加上host即drop user 'XXX'@'localhost'。
delete
delete from user where user='XXX' and host='localhost';其中XXX为用户名,localhost为主机名(即需指定主机名)。
drop和delete的区别
drop不仅会将user表中的数据删除,还会删除其他权限表的内容。而delete只删除user表中的内容,所以使用delete删除用户后需要执行FLUSH PRIVILEGES;刷新权限,否则下次使用create语句创建用户时会报错。
07 会话连接数配置
配置同样是在mysql配置文件中添加相关参数(max_connections = 100)。
mysql> show variables like "%connections";
+----------------------+-------+
| Variable_name | Value |
+----------------------+-------+
| max_connections | 100 |
| max_user_connections | 0 |
+----------------------+-------+
2 rows in set (0.01 sec)
max_connections是对整个服务器的用户做出限制,
max_user_connections是对每个用户的限制,
为0表示不限制。
root@NF:~$ grep max_connections etc/mysql/mysql.conf.d/mysqld.cnf
max_connections = 100
MySQL参数最大连接数max_connections - paul_hch
08 启用日志审计
mysql默认启用日志审计,记录的内容也符合相关安全要求,此项默认符合。
查看日志启用情况
查看变量,看相关日志是否启用show variables like 'log%';
或看mysql的配置文件,看相关日志的配置情况(根据业务需要启用相关日志和设置日志保存路径。)
# * Logging and Replication
#
# Both location gets rotated by the cronjob.
# Be aware that this log type is a performance killer.
# As of 5.1 you can enable the log at runtime!
#通用日志,将所有到达MySQL Server的SQL语句记录下来
general_log_file = var/log/mysql/mysql.log
general_log = 1
log_timestamps = SYSTEM
#
# Error log - should be very few entries.
#错误日志,文件内容不会很多
log_error = var/log/mysql/error.log
#
# Here you can see queries with especially long duration
#慢查询日志,记录SQL执行语句(执行时间超过2秒才会记录)
slow_query_log = 1
slow_query_log_file = var/log/mysql/mysql-slow.log
long_query_time = 2
log-queries-not-using-indexes
#
# The following can be used as easy to replay backup logs or for replication.
# note: if you are setting up a replication slave, see README.Debian about
# other settings you may need to change.
#二进制日志
server-id = 1
log_bin = var/log/mysql/mysql-bin.log
expire_logs_days = 10
max_binlog_size = 100M
#binlog_do_db = include_database_name
#binlog_ignore_db = include_database_name
来看一下日志内容,日志默认是分天存储的,一天一个文件并压缩保存。
相关日志(主要是查询日志和错误日志)应留存6个月以上。
日志记录的日期和时间应当是正确的,服务器需开启了NTP服务进行时间校对。
#Linux 检查NTP服务时间同步情况
ntpq -p -n
ntpstat
09 禁止.mysql_history文件记录信息
.mysql_history文件会记录MySQL操作历史(即数据库查询语句),包含敏感信息。为了避免敏感信息泄露,需要禁止使用。
检查所有.mysql_history文件是否链接到dev/null,若没连接到,则以root用户执行如下命令:
find -name ".mysql_history" | xargs
rm <your_path>/.mysql_history
ln -s dev/null <your_path>/.mysql_history
10 禁止mysql对系统文件进行读写操作
local_infile变量表示能否使用load data local infile命令。该变量默认为ON。该变量为OFF时,禁用客户端使用load data local infile命令。避免通过数据库查询语句造成的任意文件读写漏洞。
执行如下SQL语句:
show variables like 'local_infile';
若返回结果不为OFF,则在/etc/my.cnf配置文件中修改
[mysqld]
local_infile = 0
11 用户权限合理分配
执行下面语句,查看各账户和权限分配情况。请根据业务需求进行合理的权限分配,应遵循三权分立原则(分为系统管理员、安全管理员、安全审计员等,并检查系统各用户所属的权限组。如:系统管理员不能进行业务操作、审计操作审计员不能进行业务操作、系统管理操作安全员不能进行添加账号操作等)
select user,host,account_locked from mysql.user;
show grants for 'user'@'host';
select * from mysql.user where user='user' and host='host' \G;
不能存在特权用户
不存在越权访问情况(绕过访问控制策略)
mysql 数据库应当只允许root用户进行访问和管理
others
1.其它建议
最小权限原则
1.对于数据库,可以一个数据库用户分配一个数据库
2.对于mysql进程,不得以root用户运行,默认是采用了mysql用户运行。
更改默认开放端口3306
站库分离
2.一些常见语句记录
SET GLOBAL default_password_lifetime = 180;
#设置全局变量及赋值。
INSTALL PLUGIN validate_password SONAME 'validate_password.so';
#安装插件,这里是安装配置密码复杂度策略的插件。
3.关于更改数据库用户密码
update user set password=password('123') where user='root' and host='localhost';
# mysql 5.7以下
update mysql.user set authentication_string=PASSWORD('newpassword') where user='username' and host='localhost';
# mysql 5.7以上
alter user 'root'@'localhost' identified by 'newpassword';
# mysql 8.0以上
其实就是要注意密码的列名是什么,版本不一样,列名不同,可使select * from mysql.user \G;查看密码的列名。(\G 即把列数据逐行显示)
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
今天先到这儿,希望对云原生,技术领导力, 企业管理,系统架构设计与评估,团队管理, 项目管理, 产品管理,团队建设 有参考作用 , 您可能感兴趣的文章:
领导人怎样带领好团队
构建创业公司突击小团队
国际化环境下系统架构演化
微服务架构设计
视频直播平台的系统架构演化
微服务与Docker介绍
Docker与CI持续集成/CD
互联网电商购物车架构演变案例
互联网业务场景下消息队列架构
互联网高效研发团队管理演进之一
消息系统架构设计演进
互联网电商搜索架构演化之一
企业信息化与软件工程的迷思
企业项目化管理介绍
软件项目成功之要素
人际沟通风格介绍一
精益IT组织与分享式领导
学习型组织与企业
企业创新文化与等级观念
组织目标与个人目标
初创公司人才招聘与管理
人才公司环境与企业文化
企业文化、团队文化与知识共享
高效能的团队建设
项目管理沟通计划
构建高效的研发与自动化运维
某大型电商云平台实践
互联网数据库架构设计思路
IT基础架构规划方案一(网络系统规划)
餐饮行业解决方案之客户分析流程
餐饮行业解决方案之采购战略制定与实施流程
餐饮行业解决方案之业务设计流程
供应链需求调研CheckList
企业应用之性能实时度量系统演变
Openshift与Kubernetes的区别
如有想了解更多软件设计与架构, 系统IT,企业信息化, 团队管理 资讯,请关注我的微信订阅号:
作者:Petter Liu
出处:http://www.cnblogs.com/wintersun/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
该文章也同时发布在我的独立博客中-Petter Liu Blog。