MySQL最佳安全配置指导手册

本文旨在帮助用户在快速完成 MySQL 部署后,只需要很少的时间就可以完成 MySQL的安全配置。这些安全配置可以帮助用户抵御大多数常用形式的黑客攻击行为。本文选取MySQL5.7 版本+Linux 系统作为安全配置演示对象。所有安全配置项都会展示检测方式和修补方法。以帮助用户快速判断是否存在配置问题并进行修补。

说明:本文档中安全配置项仅供参考,部分配置项需结合实际环境及测试验证正常方可应用到生产环境中。

1操作系统级别安全配置

本节包含和MySQL数据库所运行的操作系统密切相关的安全配置项

1.1确保数据文件在非系统分区

建议理由:

操作系统上有明确的系统分区和非系统分区。如果数据文件在系统分区,会提高整个系统因为磁盘空间用尽发生拒绝服务的几率。

检查手段:

(1)进入数据库执行下列语句

show variables where variable_name = ‘datadir’;

(2)df –h <上面的地址返回值>

如果发现结果中存在/ /var /usr说明数据文件在系统分区建议换区

修复建议:迁移走数据文件

(1)停止数据库服务

service MySQL stop

(2)拷贝数据文件到非系统分区

cp –rp <老地址> <新地址>

(3)修改MySQL配置文件中datadir的值成新地址

(4)启动MySQL数据库

service MySQL start

1.2确保MySQL操作系统账号权限最小化

建议理由:

MySQL在操作系统上的账号权限最小化有助于减小MySQL数据库漏洞造成的影响。防止黑客利用MySQL漏洞入侵操作系统,造成更大损失。

检查手段:

假设MySQL账号为MySQL

ps -ef | egrep “^MySQL.*$”

如果没有返回行,则权限存在问题

修复建议:创建一个仅用于运行MySQL和直接相关进程的用户。

1.3禁止MySQL链接历史记录

建议理由:

MySQL会把客户端登陆的交互执行记录保存在.MySQL_history文件中。该记录有可能会暴露登陆过程中的敏感信息。建议删除该记录

检查手段:

检查.MySQL_history文件是否存在(默认在home下)

find /home -name “.MySQL_history”

如果有返回行说明存在,建议删除。

修复建议:删除并禁止继续记录

(1)如果存在.MySQL_history,则删除

(2)创建链接,防止.MySQL_history再次生成

ln -s /dev/null $HOME/.MySQL_history

或采用修改MySQL_history的环境变量让它的值等于/dev/null

1.4禁止MySQL_PWD的使用

建议理由:

MySQL_PWD是一种用于存储MySQL密码的环境变量。而且是以明文形式存储,带来了非常大的安全隐患。

检查手段:

检查MySQL_PWD环境变量是否存在于某个进程中

grep MySQL_PWD /proc/*/environ

如果有返回行说明那个进程使用了MySQL_PWD环境变量。

修复建议:对使用MySQL_PWD环境变量的脚本和进程,建议不再使用该环境变量。

1.5禁止MySQL操作系统账号登陆

建议理由:

MySQL的操作做系统账号在安装完数据库后,不应该有其他用途。建议禁止该账号登陆操作系统。此举在防止黑客利用MySQL数据库漏洞反射shell有极佳效果。

检查手段:

假设MySQL数据库操作系统账号就是MySQL执行下列命令

getent passwd MySQL | egrep “^.*[ \ /bin\ / false| \ / sbin \ / nologin]$”

如果没有返回行则说明存在安全隐患。

修复建议:执行下列语句禁止MySQL登陆

usermod -s /sbin/nologin MySQL

1.6禁止MySQL使用默认端口

建议理由:

使用默认端口,会更容易被黑客在网络中发现数据库。改成其他端口有助于隐藏数据库,防止被黑客入侵。

检查手段:

执行sql确认端口

show global variables like ‘port’;

如果返回是3306,则说明需要修改端口

修复建议:修改配置文件更改端口

修改为非3306端口

2文件系统权限安全配置

本节包含MySQL关键文件的安全配置项。

2.1确保数据文件最小权限

建议理由:

限制数据文件的访问权限,有助于阻碍不法分子直接从数据文件中读取数据甚至读取或替换MySQL.user表中的用户和密码信息。

检查手段:

(1)执行sql定位数据文件地址

show variables where variable_name = ‘datadir’;

(2)检查路径权限是否符合最小权限原则

ls -l /.. | egrep “^d[r|w|x]{3}——\s*.\s*MySQL\s*MySQL\s*\d*.*MySQL”

如果没有返回行,则说明存在安全问题

修复建议:请执行以下语句

chmod 700 <‘datadir’>

chown MySQL:MySQL <‘datadir’>

2.2确保log_bin_basename文件最小权限

建议理由:

限制日志文件的权限将有益于保护数据信息不泄露,或被恶意修改。

检查手段:

(1)执行sql定位日志文件地址

show variables like ‘log_bin_basename’;

(2)检查日志文件的权限是660属于MySQL

修复建议:请执行以下语句

chmod 660 <‘log file’>

chown MySQL:MySQL <‘log file’>

2.3确保log_error文件最小权限

建议理由:

限制日志文件的权限将有益于保护数据信息不泄露,或被恶意修改。

检查手段:

(1)执行sql定位日志文件地址

show global variables like ‘log_error’;

(2)检查日志文件的权限是660属于MySQL

修复建议:请执行以下语句

chmod 660 <‘log file’>

chown MySQL:MySQL <‘log file’>

2.4确保slow_query_log文件最小权限

建议理由:

限制日志文件的权限将有益于保护数据信息不泄露,或被恶意修改。

检查手段:

(1)执行sql定位日志文件地址

show variables like ‘slow_query_log_file’;

(2)检查日志文件的权限是660属于MySQL

修复建议:请执行以下语句

chmod 660 <‘log file’>

chown MySQL:MySQL <‘log file’>

2.5确保relay_log_basename文件最小权限

建议理由:

限制日志文件的权限将有益于保护数据信息不泄露,或被恶意修改。

检查手段:

(1)执行sql定位日志文件地址

show variables like ‘relay_log_basename’;

(2)检查日志文件的权限是660属于MySQL

修复建议:请执行以下语句

chmod 660 <‘log file’>

chown MySQL:MySQL <‘log file’>

2.6确保general_log_file文件最小权限

建议理由:

限制日志文件的权限将有益于保护数据信息不泄露,或被恶意修改。

检查手段:

(1)执行sql定位日志文件地址

show variables like ‘general_log_file’;

(2)检查日志文件的权限是660属于MySQL

修复建议:请执行以下语句

chmod 660 <‘log file’>

chown MySQL:MySQL <‘log file’>

2.7确保密钥文件最小权限

建议理由:

限制密钥文件的访问权限,防止密钥文件被盗取,被替换,被破解等情况的发生。

检查手段:

(1)执行sql定位密钥文件地址

show variables where variable_name = ‘ssl_key’;

(2)检查路径权限是否符合最小权限原则

ls -l | egrep “^-r——–[ \t]*.[ \t]*MySQL[ \t]*MySQL.*$”

如果没有返回行,则说明存在安全问题

修复建议:请执行以下语句

chmod 400 <ssl_key_value>

chown MySQL:MySQL <ssl_key_value>

2.8确保插件目录最小权限

建议理由:

限制插件目录的权限,防止有人恶意添加插件,这些插件会在MySQL启动时和MySQL同时启动。如果被插入恶意插件,可能会导致MySQL被控制。

检查手段:

(1)执行sql定位插件目录地址

show variables where variable_name = ‘plugin_dir’;

(2)检查路径权限是否符合最小权限原则

ls -l /.. | egrep “^drwxr[-w]xr[-w]x[ \t]*[0-9][ \t]*MySQL[ \t]*MySQL.*plugin.*$”

如果没有返回行,则说明存在安全问题

修复建议:请执行以下语句

chmod 755 <plugin_dir Value>

chown MySQL:MySQL <plugin_dir Value>

3 MySQL基本安全配置

本节包含MySQL数据库自身的基本安全配置项

3.1确保使用最新版MySQL数据库

建议理由:

新版MySQL数据库会修复一些bug和所有已知数据库漏洞,能极大的提高数据库的安全性。

检查手段:

执行sql检查数据库版本

SHOW VARIABLES WHERE Variable_name LIKE “version”;

修复建议:存在新版本请替换成新版本数据库。

3.2确保样例数据库删除

建议理由:

样例数据库可以被所有数据库用户访问,并且可以用来消耗系统资源,删除样例库可以减少黑客攻击面。

检查手段:

执行sql检查数据库是否存在样例库

SHOW DATABASES LIKE ‘test’;

修复建议:如果存在删除样例库

DROP DATABASE “test”;

3.3修改root用户名

建议理由:

MySQL默认用户root应该修改名称,以减小攻击面。防止黑客针对用户名进行密码猜测攻击。

检查手段:

执行sql检查数据库是否有默认用户root

SELECT user from MySQL.user where user=’root’;

如果有返回行则需要修改

修复建议:修改用户名

update user set name=’newname’ where name=’oldname’;

flush privileges;

3.4确保allow-suspicious-udfs设置成false

建议理由:

关闭allow-suspicious-udfs,可以防止通过共享对象文件加载存在威胁的UDFs函数。

检查手段:

(1)检查配置文件确定这个参数被设置成false

(2)检查MySQLd的启动参数中没有allow-suspicious-udfs参数

修复建议:

(1)从配置文件中把allow-suspicious-udfs设置成false

(2)启动参数中剔除allow-suspicious-udfs

3.5禁用local_infile

建议理由:

禁用local_infile可以阻止黑客利用sql注入来读取数据库文件,减小黑客给数据库带来的安全损失。

检查手段:用sql语句检查参数状态

SHOW VARIABLES WHERE Variable_name = ‘local_infile’;

如果返回值不是off,则存在安全问题

修复建议:在配置文件中加入下列内容,然后重启数据库

Local_infile=0

3.6确保skip-grant-tables设置成false

建议理由:

如果不关闭此参数,所有账号可以不受限制的访问任意数据库,会导敏感数据外泄。

检查手段:

打开配置文件检查skip-grant-tables是否被设置成false

修复建议:

在配置文件中把skip-grant-tables设置成false

3.7确保skip-symbolic-links开启

建议理由:

开启skip-symbolic-links可以禁止数据库用户删除或重命名数据文件目录之外的文件。

检查手段:用sql语句检查参数状态

SHOW variables LIKE ‘have_symlink’;

修复建议:

如果没有启动skip-symbolic-links建议把MySQL配置文件中的值设置成yes。

3.8确保插件daemon_memcached被禁用

建议理由:

任何人可以利用daemon_memcached来访问或修改一部分数据,给数据库造成信息泄漏的隐患。

检查手段:用sql语句检查参数状态

SELECT * FROM information_schema.plugins WHERE PLUGIN_NAME=’daemon_memcached’;

如果有返回行数说明有插件,需要删除

修复建议:删除插件语句如下

uninstall plugin daemon_memcached;

3.9确保secure_file_priv不是空

建议理由:

secure_file_priv限制客户端可以读取数据文件的路径。secure_file_priv设置合理的值可以有效降低sql注入后黑客读取数据库数据的可能性。

检查手段:用sql语句检查参数状态

SHOW GLOBAL VARIABLES WHERE Variable_name = ‘secure_file_priv’ AND Value<>”;

如果有返回内容说明安全,否则需要修复

修复建议:在配置文件中添加如下语句,然后重启数据库

secure_file_priv=<path_to_load_directory>

3.10确保sql_modeSTRICT_ALL_TABLES模式

建议理由:

sql_mode模式有三种,STRICT_TRANS_TABLES是其中一种模式。

STRICT_TRANS_TABLES模式会检查所有更新的数据,在一定程度可以给入侵者规避检测带来阻碍。

检查手段:用sql语句检查参数状态

SHOW VARIABLES LIKE ‘sql_mode’;

如果有返回的是STRICT_TRANS_TABLES说明安全,否则需要修复

修复建议:在配置文件中添加如下语句,然后重启数据库

sql_mode=STRICT_ALL_TABLES

3.11确保disconnect_on_expired_password参数是ON

建议理由:

disconnect_on_expired_password是用来控制客户端用失效密码来访问数据库的,关闭这个参数会给数据库带来安全风险。

检查手段:用sql语句检查参数状态

SHOW GLOBAL VARIABLES like ‘disconnect_on_expired_password’;

如果有返回的是ON说明安全,否则需要修复

修复建议:在配置文件中添加如下语句,然后重启数据库

disconnect_on_expired_password=ON

4 MySQL权限安全配置

这一节主要包含各种权限的安全配置

4.1确保只有管理员账号有所有数据库的访问权限

建议理由:

除了管理员账号,其他用户没必要有所有数据库的访问权限,过高的权限会导致安全问题。

检查手段:用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’));

如果返回的都是管理员账号说明安全,否则需要对用户清除权限

修复建议:

清除非管理员账号的过高部分权限

4.2非管理员账号file_priv不应该设置成Y

建议理由:

File_priv权限允许MySQL用户对磁盘进行读写操作。黑客很可能利用这一点盗取数据库中敏感数据。

检查手段:用sql语句检查

select user,host from MySQL.user where File_priv = ‘Y’;

如果返回的都是管理员账号则是安全的,否则需要对用户清除权限

修复建议:

REVOKE FILE ON *.* FROM ‘<user>’;

4.3非管理员账号process_priv不应该设置成Y

建议理由:

process_priv权限允许委托账号查看当前正在执行的sql语句,使用超越当前用户权限的权利可以被攻击者所利用。

检查手段:用sql语句检查

select user,host from MySQL.user where Process_priv = ‘Y’;

如果返回的都是管理员账号则是安全的,否则需要对用户清除权限

修复建议:

REVOKE PROCESS ON *.* FROM ‘<user>’;

4.4非管理员账号super_priv不应该设置成Y

建议理由:

super_priv权限允许委托账号执行任意语句,非管理员不应该具备该权限。

检查手段:用sql语句检查

select user,host from MySQL.user where Super_priv = ‘Y’;

如果返回的都是管理员账号则是安全的,否则需要对用户清除权限

修复建议:

REVOKE SUPER ON *.* FROM ‘<user>’;

4.5非管理员账号shutdown_priv不应该设置成Y

建议理由:

shutdown_priv权限允许委托账号关闭数据库,会造成一定安全隐患。

检查手段:用sql语句检查

SELECT user,host FROM MySQL.user WHERE Shutdown_priv = ‘Y’;

如果返回的都是管理员账号则是安全的,否则需要对用户清除权限

修复建议:

REVOKE SHUTDOWN ON *.* FROM ‘<user>’;

4.6非管理员账号create_user_priv不应该设置成Y

建议理由:

create_user_priv权限允许委托账号创建任意用户,会造成一定安全隐患。

检查手段:用sql语句检查

SELECT user,host FROM MySQL.user WHERE Create_user_priv = ‘Y’;

如果返回的都是管理员账号则是安全的,否则需要对用户清除权限

修复建议:

REVOKE CREATE USER ON *.* FROM ‘<user>’;

4.7非管理员账号grant_priv不应该设置成Y

建议理由:

Grant_priv权限允许委托账号对其他用户赋权,可能会被黑客利用造成一定安全隐患。

检查手段:用sql语句检查

SELECT user,host FROM MySQL.user WHERE Grant_priv = ‘Y’;

如果返回的都是管理员账号则是安全的,否则需要对用户清除权限

修复建议:

REVOKE Grant ON *.* FROM ‘<user>’;

4.8非管理员账号reload_priv不应该设置成Y

建议理由:

reload_priv权限可以对本地文件进行操作,可能会被黑客利用造成一定安全隐患。

检查手段:用sql语句检查

SELECT user,host FROM MySQL.user WHERE reload_priv = ‘Y’;

如果返回的都是管理员账号则是安全的,否则需要对用户清除权限

修复建议:

REVOKE reload ON *.* FROM ‘<user>’;

4.9非管理员账号repl_slave_priv不应该设置成Y

建议理由:

repl_slave_priv用于从主服务器上获得更新的数据,黑客很可能利用这一点盗取数据库中敏感数据。

检查手段:用sql语句检查

select user,host from MySQL.user where repl_slave_priv = ‘Y’;

如果返回的都是管理员账号则是安全的,否则需要对用户清除权限

修复建议:

REVOKE repl_slave ON *.* FROM ‘<user>’;

4.10确保DML/DDL权限只在特定用户手上

建议理由:

限制用户有INSERT,SELECT,UPDATE,DELETE,DROP,CREATE和ALTER权限。这些权限都会导致数据泄密等。

检查手段:用sql语句检查

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 ;

5审计和日志安全配置

5.1确保log_error日志启动

建议理由:

启用错误日志有可能会增加检测到针对MySQL的恶意攻击行为机会,为日后安全检查提供更多线索和证据。

检查手段:用sql语句检查

SHOW variables LIKE ‘log_error’;

如果返回空值,则存在安全问题需要修复

修复建议:

打开MySQL配置文件把log_error配置到一个有效路径

5.2确保日志文件在非系统分区

建议理由:

操作系统上有明确的系统分区和非系统分区。如果日志文件在系统分区,会提高整个系统因为磁盘空间用尽发生拒绝服务的几率。

检查手段:

(1)进入数据库执行下列语句

SELECT @@global.log_bin_basename;

(2)df –h <上面的地址返回值>

如果发现结果中存在/ /var /usr说明数据文件在系统分区建议换区

修复建议:打开MySQL配置文件

将log_bin设置成非系统分区路径

5.3确保log_raw被设置成off

建议理由:

语句中的密码在写入一般查询日志时会被服务器重写,不会以明文方式记录。但如果log-raw被设置成ture,则会记成明文。

检查手段:打开数据库配置文件

确定log_raw被设置成off,如果是off是安全的,但如果是on则需要修复

修复建议:打开MySQL配置文件

Log_raw=OFF

5.4确保log_warnings被设置成2

建议理由:

log_warnings适用于决定日志中记录的内容的。默认是1随着级别的调整会记录更多信息。调整到2有助于通过日志追查安全问题。

检查手段:

通过sql读取信息

SHOW GLOBAL VARIABLES LIKE ‘log_warnings’;

如果返回值是1需要调整到2

修复建议:打开MySQL配置文件

log_warnings=2

6身份认证安全配置

本节包含属于MySQL认证配置的安全配置

6.1确保密码不在全局变量中

建议理由:

MySQL配置文件(客户端部分)允许设置用户名和密码。使用密码参数可能会对用户的机密性造成负面影响。

检查手段:

打开数据库配置文件,检查用户名和密码参数

如果是空的是安全的,但如果不是空的则需要修复

修复建议:打开MySQL配置文件

清理参数内容

6.2确保sql_mode中含有NO_AUTO_CREATE_USER

建议理由:

NO_AUTO_CREATE_USER是sql_mode的一个选项,可以阻止grant语句在特定情况下自动创建用户,给数据库带来安全隐患。

检查手段:

通过sql观察参数

SELECT @@session.sql_mode;

如果返回值包含NO_AUTO_CREATE_USER是安全的,但如果不包含则需要修复

修复建议:打开MySQL配置文件

在sql_mode中添加参数NO_AUTO_CREATE_USER

6.3确保没有用户使用空密码

建议理由:

如果密码被设置成空密码,入侵者就可以绕过身份验证随意登录数据库,进行违规操作。

检查手段:

通过sql观察参数

SELECT User,host FROM MySQL.user WHERE authentication_string=”;

没有行数返回说明安全,否则需要配置

修复建议:给空白密码的账号配上密码

6.4确保default_password_lifetimes少于或等于90

建议理由:

密码需要定期更换,才能更有效的防止黑客破解。

检查手段:

通过sql观察参数

SHOW VARIABLES LIKE ‘default_password_lifetime’;

看返回值和90的关系如果大于90就需要修复

修复建议:设置全局变量

SET GLOBAL default_password_lifetime=90

6.5确保用户不允许所有ip访问

建议理由:

某一数据库用户支持所有ip访问,一旦账号密码泄露,数据库就变得很不安全。

检查手段:

通过sql观察参数

SELECT user,host FROM MySQL.user WHERE host = ‘%’;

结果集为空说明不存在问题,否则需要修复

修复建议:删除该用户或通过alter删除%指定特定ip

6.6确保无匿名帐户存在

建议理由:

匿名用户是空的,也没有密码,安全性很差,任意人员都可以利用匿名用户访问数据库。

检查手段:

通过sql观察参数

SELECT user,host FROM MySQL.user WHERE user = ”;

结果集为空说明不存在问题,否则需要修复

修复建议:删除匿名用户。

7网络安全配置

7.1确保have_ssl设置成yes

建议理由:

所有网络请求必须走SSL/TLS访问数据库,杜绝网络劫持和网络拦截

检查手段:

通过sql观察参数

SHOW variables WHERE variable_name = ‘have_ssl’;

返回yes不存在问题,否则需要修复

修复建议:开启ssh。

7.2确保ssl_type‘ANY’,’X509′,or ‘SPECIFIED’

建议理由:

所有网络请求必须走SSL/TLS访问数据库。SSL提供多种算法,其中一些算法安全性并不高,不能帮助用户杜绝网络劫持和网络拦截。建议设置ssl_type为高安全类型的加密算法,但这其中有一个隐患,如果客户端使用较低加密算法,会由于算法无法匹配导致链接失败。

检查手段:

通过sql观察参数

SELECT user,host,ssl_type FROM MySQL.user WHERE NOT HOST IN (‘::1’, ‘127.0.0.1’, ‘localhost’);

确保每个用户返回的ssl_type等于ANY,X509,or SPECIFIED

修复建议:使用GRANT语句来使用要求的SSL

GRANT USAGE ON *.* TO ‘my_user’@’app1.example.com’ REQUIRE SSL;

8复制数据传输中的安全配置

8.1确保MASTER_SSL_VERIFY_SERVER_CERT设置成yes1

建议理由:

在使用SSL时,证书验证对于验证正在进行连接的一方很重要。在这种情况下,从属(客户端)应该在继续连接之前验证主服务器的证书以验证主服务器。

MASTER_SSL_VERIFY_SERVER_CERT主要是用于检查证书,确保证书的合法性。

检查手段:

通过sql观察参数

select ssl_verify_server_cert from MySQL.slave_master_info;

ssl_verify_server_cert返回是1,否则需要修复

修复建议:修改MASTER_SSL_VERIFY_SERVER_CERT配置。

STOP SLAVE; — required if replication was already running

CHANGE MASTER TO MASTER_SSL_VERIFY_SERVER_CERT=1;

START SLAVE; — required if you want to restart replication

8.2确保master_info_repository设置成table

建议理由:

master_info_repository设置成table.客户端使用的密码存储在表中,相较于文件系统表中更为安全。

检查手段:

通过sql观察参数

SHOW GLOBAL VARIABLES LIKE ‘master_info_repository’;

master_info_repository返回是table,否则需要修复

修复建议:打开配置文件 set the master_info_repository value to TABLE