[记录] MariaDB&MySQL 安全调优思路

内容目录:
内容一:数据库综合安全
1.1 保证运行数据库的系统是安全的
1.2 以最小权限用户运行数据库
1.2.1 停止数据库
1.2.2 修改数据库目录的
1.2.3 修改配置文件
1.2.4 启动数据库
1.3 将数据库版本升级到更新的版本

内容二:数据库库安全
2.1 删除所有不用的库
2.1.1 查看所有库的列表
2.1.2 删除测试库
2.2 删除所有测试库
2.2.1 方法一:手动删除所有测试库
2.2.1.1 查看所有库的列表
2.2.1.2 删除测试库
2.2.2 方法二:使用工具删除所有测试库
2.3 禁用客户端本地数据被读取
2.3.1 修改配置文件
2.3.2 重启数据库
2.4 保护数据的本地存储

内容三:数据库登陆安全
3.1 限制数据的导入导出
3.1.1 案例一:禁止数据的导入导出
3.1.1.1 修改配置文件
3.1.1.2 重启数据库
3.1.2 案例二:只允许将数据从 /root 目录导入或导出到 /root 目录
3.1.2.1 修改配置文件
3.1.2.2 重启数据库
3.1.3 案例三:部队数据作出导入和导出的限制
3.1.3.1 修改配置文件
3.1.3.2 重启数据库
3.2 删除无用和不需要的账号
3.2.1 查看所有账号
3.2.2 删除不需要的用户
3.2.2.1 删除用户的第一种方法:使用 drop 命令删除账号
3.2.2.2 删除用户的第二中方法:使用 delete 命令删除账号
3.3 mysql 数据库用户使用强密码
3.3.1 修改配置文件
3.3.2 重启数据库
3.3.3 确保 validate_password_policy 被设置的参数是 MEDIUM
3.3.3.1 进入数据库
3.3.3.2 查看 validate_password_policy 参数
3.4 设置账号密码有效期
3.4.1 对于 MariaDB 和 MySQL5.7 及以下的版本无法设置有效期,只能定期修改密码
3.4.2 设置账号默认有效期的方法 
3.4.2.1 修改账号密码默认的自动过期时间
3.4.2.2 让账号密码立刻过期
3.4.2.3 让账号密码永不过期
3.5 删除无密码账号
3.5.1 方法一:手动删除无密码账号
3.5.1.1 查看无密码账号
3.5.1.1.1 MariaDB 和 MySQL5.7 及以下版本查看无密码账号的方法
3.5.1.1.2 MySQL8.0 及以上版本查看无密码账号的方法
3.5.1.2 手动删除不需要的用户的方法
3.5.1.2.1 手动删除用户的第一种方法:使用 drop 命令删除账号
3.5.1.2.2 手动删除用户的第二种方法:使用 delete 命令删除账号
3.5.2 方法二:使用工具删除无密码账号
3.6 禁止非 root 用户 拥有 mysql.user 表访问权限
3.7 让用户只拥有最小但够用的权限
3.7.1 查看所有账号
3.7.2 数据库权限层级
3.7.3 查看每一个用户的权限
3.7.4 删除用户多余的权限

内容四:数据库网络安全
4.1 禁止或者限制远程登陆
4.1.1 禁止远程登陆
4.1.1.1 通过 MariaDB&MySQL 的配置文件禁止远程登录
4.1.1.1.1 修改配置文件
4.1.1.1.2 重启数据库
4.1.1.2 通过防火墙禁止远程登录
4.1.2 如果非要进行远程登录则要限制远程登录
4.1.2.1 限制具体的 IP 地址范围
4.1.2.2 禁止有较大权限的用户被远程登陆
4.2 对网络数据进行加密传输
4.2.1 生成 SSL
4.2.1.1 创建 CA 证书
4.2.1.2 创建服务端证书,并去除加密,并使用刚刚的 CA 证书进行签名
4.2.1.3 创建客户端证书,并去除加密,并使用刚刚的 CA 证书进行签名
4.2.1.4 对生成的证书进行验证
4.2.2 将 SSL 添加到 MariaDB&MySQL
4.2.2.1 将 SSL 放在指定的位置
4.2.2.2 修改配置文件
4.2.3  重启数据库
4.2.4 验证 SSL
4.2.4.1 查看 have_ssl 和 ssl 变量
4.2.4.2 查看 SSL 的状态
4.2.5 确保所有数据库用户使用 SSL
4.2.6 用户通过 SSL 连接数据库的方法

内容五:开启审计
5.1 开启审计
5.1.1 MariaDB 和 MySQL5.7 开启审计的方法
5.1.2 MySQL8.0 开启审计的方法
5.2 查看 MariaDB&MySQL 日志

具体的内容:
内容一:数据库综合安全
1.1 保证运行数据库的系统是安全的
步骤:略

1.2 以最小权限用户运行数据库
1.2.1 停止数据库
(1)MariaDB
# systemctl stop mariadb

(2)MySQL
# systemctl stop mysqld

1.2.2 修改数据库目录的
# chown -R mysql /var/lib/mysql

1.2.3 修改配置文件
# vim /etc/my.cnf
将部分内容修改如下:
[mysqld]
user=mysql
......

1.2.4 启动数据库
(1)MariaDB
# systemctl start mariadb

(2)MySQL
# systemctl start mysqld

1.3 将数据库版本升级到更新的版本

内容二:数据库库安全
2.1 删除所有不用的库
2.1.1 查看所有库的列表
> show databases;

2.1.2 删除测试库
> drop database <库名>

2.2 删除所有测试库
2.2.1 方法一:手动删除所有测试库
2.2.1.1 查看所有库的列表
> show databases;

2.2.1.2 删除测试库
> drop database <库名>

2.2.2 方法二:使用工具删除所有测试库
# sudo mysql_secure_installation

2.3 禁用客户端本地数据被读取
2.3.1 修改配置文件
# vim /etc/my.cnf
将部分内容修改如下:
[mysqld]
local-infile=0
...... 

2.3.2 重启数据库
(1)MariaDB
# systemctl restart mariadb

(2)MySQL
# systemctl restart mysqld

2.4 保护数据的本地存储
思路如下:
(1)使用加密的文件系统存储存放数据库的数据文件
(2)使用数据库之外的存储加密产品
(3)使用其他加密产品实现适当的数据保护

内容三:数据库登陆安全
3.1 限制数据的导入导出
3.1.1 案例一:禁止数据的导入导出
3.1.1.1 修改配置文件
# vim /etc/my.cnf
将部分内容修改如下:
[mysqld]
secure_file_priv=null
...... 

3.1.1.2 重启数据库
(1)MariaDB
# systemctl restart mariadb

(2)MySQL
# systemctl restart mysqld

3.1.2 案例二:只允许将数据从 /root 目录导入或导出到 /root 目录
3.1.2.1 修改配置文件
# vim /etc/my.cnf
将部分内容修改如下:
[mysqld]
secure_file_priv=/root/
...... 

3.1.2.2 重启数据库
(1)MariaDB
# systemctl restart mariadb

(2)MySQL
# systemctl restart mysqld

3.1.3 案例三:部队数据作出导入和导出的限制
3.1.3.1 修改配置文件
# vim /etc/my.cnf
删除以下内容:
......
secure_file_priv=*
...... 

3.1.3.2 重启数据库
(1)MariaDB
# systemctl restart mariadb

(2)MySQL
# systemctl restart mysqld

3.2 删除无用和不需要的账号
3.2.1 查看所有账号
> select user,host from mysql.user;

3.2.2 删除不需要的用户
3.2.2.1 删除用户的第一种方法:使用 drop 命令删除账号
> drop <账号名>;

3.2.2.2 删除用户的第二中方法:使用 delete 命令删除账号
> delete from mysql.user where user='<账号名>' and host='<主机名>';

3.3 mysql 数据库用户使用强密码
3.3.1 修改配置文件
# vim /etc/my.cnf
将部分内容修改如下:
[mysqld]
plugin-load=validate_password.so
......

3.3.2 重启数据库
(1)MariaDB
# systemctl restart mariadb

(2)MySQL
# systemctl restart mysqld

3.3.3 确保 validate_password_policy 被设置的参数是 MEDIUM
3.3.3.1 进入数据库
# MySQL -p

3.3.3.2 查看 validate_password_policy 参数
> show variables like 'validate_password_policy';
+--------------------------+--------+
| Variable_name            | Value  |
+--------------------------+--------+
| validate_password.policy | MEDIUM |
| validate_password_policy | MEDIUM |
+--------------------------+--------+
2 rows in set (0.01 sec)

(补充:MEDIUM 的含义是密码最小的长度是 8 ,并且必须要有一个特殊字符和一个数字)

3.4 设置账号密码有效期
3.4.1 对于 MariaDB 和 MySQL5.7 及以下的版本无法设置有效期,只能定期修改密码
> alter user 'root'@'localhost' identified by '<密码>';

3.4.2 设置账号默认有效期的方法 
3.4.2.1 修改账号密码默认的自动过期时间
> set global default_password_lifetime=<数字>;

(补充:这里的数字代表天数)

3.4.2.2 让账号密码立刻过期
> aleter user '<账号名>'@'<主机名>' password expire;

3.4.2.3 让账号密码永不过期
> aleter user '<账号名>'@'<主机名>' password expire never;

(补充:建议普通账号每 90 天修改一次密码,敏感账号每 30 天修改一次密码,服务账号每 365 天修改一次密码)

3.5 删除无密码账号
3.5.1 方法一:手动删除无密码账号
3.5.1.1 查看无密码账号
3.5.1.1.1 MariaDB 和 MySQL5.7 及以下版本查看无密码账号的方法
> select user, host, password from mysql.user;

3.5.1.1.2 MySQL8.0 及以上版本查看无密码账号的方法
> select user, host, authentication_string from mysql.user;

3.5.1.2 手动删除不需要的用户的方法
3.5.1.2.1 手动删除用户的第一种方法:使用 drop 命令删除账号
> drop user <账号名>;

3.5.1.2.2 手动删除用户的第二种方法:使用 delete 命令删除账号
> delete from mysql.user where user='<账号名>' and host='<主机名>';

3.5.2 方法二:使用工具删除无密码账号
# sudo mysql_secure_installation

3.6 禁止非 root 用户 拥有 mysql.user 表访问权限
# show grants for root@localhost \G;
select * from mysql.user where user='test' \G;

3.7 让用户只拥有最小但够用的权限
3.7.1 查看所有账号
> select user,host from mysql.user;

3.7.2 数据库权限层级
(1)全局层级权限:是指整个数据库级别的权限,存储在 mysql.user 表中
例:
> grant all on *.* ......
> show grants for <账号名>;
> select * from mysql.user where user='<账号名>'\G;

(2)库级层级权限:是指数据库中某个库的权限,存储在 mysql.db 和 mysql.host 表中
例:
> grant all on <库名>.* ......
> show grants for <账号名>;
> select * from mysql.db where user='<账号名>'\G;

(3)表级层级权限:是指数据库中某个库的某个表的权限,存储在 mysql.tables_priv 表中
例:
> grant all on <库名>.<表名> ......
> show grants for <账号名>;
> select * from mysql.tables_priv where user='<账号名>'\G;

(4)列级层级权限:是指数据库中某个库的某个表的某一单列的权限,存储在 mysql.columns_priv 表中
例:
> grant select(<字段名>,<字段名>) on <库名>.<表名> ......
> show grants for <账号名>;
> select * from mysql.columns_priv where user='<账号名>'\G;

(5)子程序层级权限:适用于已存储的子程序
create routing, alter routing, execute 和 grant 权限适用于已存储的子程序
create routing, alter routing, execute 和 grant 权限可以被授予为全局层级和数据库层级
alter routing, execute 和 grant 权限可以被授予为子程序层级,并存储在 mysql.procs_priv 表中
例:
> grant execute on <子程序名> <库名>.<表名> ......
> show grants for <账号名>;
> select * from mysql.procs_priv where user='<账号名>'\G;

3.7.3 查看每一个用户的权限
> show grants for '<账号名>'@'<主机名>';

3.7.4 删除用户多余的权限
如果有全局权限(如: FILE,PROCESS,SUPER, or SHUTDOWN 等权限),就删除这些权限
例:
> revoke <权限名> on *.* from <账号名>@<主机名>;
> flush privileages;

内容四:数据库网络安全
4.1 禁止或者限制远程登陆

(
补充:
查看可以远程登录的战号
> select user, host from mysql.user where host not in ('::1','127.0.0.1','localhost');
)

4.1.1 禁止远程登陆
4.1.1.1 通过 MariaDB&MySQL 的配置文件禁止远程登录
4.1.1.1.1 修改配置文件
# vim /etc/my.cnf
将部分内容修改如下:
[mysqld]
skip-networking
bind-address=127.0.0.1
......

(注意:加入 skip-networking 这一行会让 MariaDB&MySQL 不再使用和监听任何端口)

4.1.1.1.2 重启数据库
(1)MariaDB
# systemctl restart mariadb

(2)MySQL
# systemctl restart mysqld

4.1.1.2 通过防火墙禁止远程登录
通过硬件防火墙、软件防火墙、iptables 访问控制列表限制 3306 端口

4.1.2 如果非要进行远程登录则要限制远程登录
4.1.2.1 限制具体的 IP 地址范围
步骤:略

4.1.2.2 禁止有较大权限的用户被远程登陆
(1)有 grant option 权限的用户
(2)被给予了全局权限像是 grant all on *.* 权限的用户
(3)一个可以访问 mysql.user 表的用户

4.2 对网络数据进行加密传输
4.2.1 生成 SSL
(注意:创建 CA 证书、服务端证书、客户端证书时 Common Name 必须要有值,且必须相互不一样)
4.2.1.1 创建 CA 证书
# openssl genrsa 2048 > ca-key.pem
Generating RSA private key, 2048 bit long modulus
..+++
...................................+++
e is 65537 (0x10001)

# openssl req -new -x509 -nodes -days 3600 -key ca-key.pem -out ca.pem
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:
State or Province Name (full name) []:
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:ca #注意这里必须要有值,并且值要唯一
Email Address []:

4.2.1.2 创建服务端证书,并去除加密,并使用刚刚的 CA 证书进行签名
# openssl req -newkey rsa:2048 -days 3600 -nodes -keyout server-key.pem -out server-req.pem
Generating a 2048 bit RSA private key
.............+++
...+++
writing new private key to 'server-key.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:
State or Province Name (full name) []:
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []: #注意这里必须要有值,并且值要唯一
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

# openssl rsa -in server-key.pem -out server-key.pem
writing RSA key

# openssl x509 -req -in server-req.pem -days 3600 -CA ca.pem -CAkey ca-key.pem -set_serial 01 -out server-cert.pem
Signature ok
subject=/C=XX/L=Default City/O=Default Company Ltd
Getting CA Private Key

4.2.1.3 创建客户端证书,并去除加密,并使用刚刚的 CA 证书进行签名
# openssl req -newkey rsa:2048 -days 3600 -nodes -keyout client-key.pem -out client-req.pem
Generating a 2048 bit RSA private key
..................+++
..............................................+++
writing new private key to 'client-key.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:
State or Province Name (full name) []:
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []: #注意这里必须要有值,并且值要唯一
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

# openssl rsa -in client-key.pem -out client-key.pem
writing RSA key

# openssl x509 -req -in client-req.pem -days 3600 -CA ca.pem -CAkey ca-key.pem -set_serial 01 -out client-cert.pem
Signature ok
subject=/C=XX/L=Default City/O=Default Company Ltd
Getting CA Private Key

4.2.1.4 对生成的证书进行验证
# openssl verify -CAfile ca.pem server-cert.pem client-cert.pem
server-cert.pem: OK
client-cert.pem: OK

4.2.2 将 SSL 添加到 MariaDB&MySQL
4.2.2.1 将 SSL 放在指定的位置
# mv ca.pem /home/mysql/sslconfig/ca.pem
# mv server-cert.pem /home/mysql/sslconfig/server-cert.pem
# mv server-key.pem /home/mysql/sslconfig/server-key.pem

4.2.2.2 修改配置文件
# vim /etc/my.cnf
将部分内容修改如下:
[mysqld]
ssl-ca=/home/mysql/sslconfig/ca.pem
ssl-cert=/home/mysql/sslconfig/server-cert.pem
ssl-key=/home/mysql/sslconfig/server-key.pem
......

4.2.3  重启数据库
(1)MariaDB
# systemctl restart mariadb

(2)MySQL
# systemctl restart mysqld

4.2.4 验证 SSL
4.2.4.1 查看 have_ssl 和 ssl 变量
> show variables like 'have_%ssl';
> show variables like '%ssl%';

(补充:如果它们的参数为 yes ,表示服务端已经开启 SSL)

4.2.4.2 查看 SSL 的状态
> show status like 'ssl_cipher'

(补充:如果出现 “SSL:Cipher in use is DHE-RSA-AES256-SHA“ 则表示客户端已经使用 SSL 连接了)

4.2.5 确保所有数据库用户使用 SSL
> grant usage on <database>.<table> to '<用户>'@'<主机名>' reouter ssl;

4.2.6 用户通过 SSL 连接数据库的方法
> mysql -u <用户名> -p -h <主机名> --ssl-ca=/home/mysql/sslconfig/ca.pem

内容五:开启审计
5.1 开启审计
5.1.1 MariaDB 和 MySQL5.7 开启审计的方法
> set global log_warning=2;

5.1.2 MySQL8.0 开启审计的方法
> set global general_log = on;
> set global log_timestamps = SYSTEM;

5.2 查看 MariaDB&MySQL 日志
# find /I "Access denied for user" <logfile_name>.log
# grep -i 'Access denied for user' <logfile_name>.log

(注意:中止连接、失败连接、尝试连接都将被写进日志)