大家一定知道max_connect_errors参数,但是可能很多时候却误解了这个参数。
max_connect_errors是一个MySQL中与访问安全有关的一个参数,它负责阻止过多尝试失败的客户端以防止暴力破解密码的情况。但是经过实际测试,发现此参数并不能真正的阻止恶意的客户端恶意访问MySQL Server,下面我就来对这个参数的作用以及测试过程做个说明。
max_connect_errors这个参数可以动态修改设置,所以你可以在命令行直接设置:
set global max_connect_errors=10
但是一旦MySQL服务重启,上面设置的值就失效了,如果想要永久生效,还需要修改MySQL参数文件,在其中添加此参数的设置
有的人可能觉得设置完此参数后,就可以正常拦截同一个client,密码错误的访问连续超过10次的情况了,而现实是这样的么?经过本人在5.6.24上测试,发现此参数是没有作用的。如果想要此参数生效,需要具备至少下面的两个条件:
只有设置参数skip_name_resolve为OFF时,参数max_connect_errors才能生效,否则不能生效,即
skip_name_resolve=OFF
max_connect_errors=10
说明:在MySQL5.6.24中,skip_name_resolve参数的设置是只读的,只能通过修改配置文件并重启的方式来修改此参数,并且此参数修改即使在参数文件中设置skip_name_resolve=OFF也是不能生效的,MySQL实例启动后此参数还是为skip_name_resolve=ON,所以需要在参数文件中把此参数去掉或注释掉,才能设置skip_name_resolve=OFF的结果,如 #skip_name_resolve
设置完上面的两个参数后,你可能会觉得max_connect_errors=10设置后,就可以阻止client访问MySQL,如果有超过10次的错误访问(比如密码错误),此client就会被block,从而此client将不能再访问MySQL,如果有访问就会收到下面错误提示:
ERROR 1129 (HY000): Host 'xxx.xxx.xxx.xxx' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'
但是其实不是,只有通过下面telnet方式测试的方式才会触发此参数的作用,达到设置的max_connect_errors阈值后触发此参数的作用,并锁定此client。而通过输错密码的方式连接mysql,是不能触发此参数并锁定client的,也就是说只有通过telnet 进行测试端口的有效性时,此参数才能生效,并且达到参数设置的次数时会锁定进行连接的client,否则(通过错误密码连接的方式)是不会锁定的
此种验证有效:telnet 172.16.1.2 8888
执行telnet 172.16.1.2 8888 10次后,如下,会报下面错误提示,这时候此ip将被禁止访问MySQL
Trying 172.16.1.2... Connected to 172.16.1.2. Escape character is '^]'. N5.6.24-log K]qA1nYT!w|+ZhxF1c#|kmysql_native_password^]!#08S01Got packets out of orderConnection closed by foreign host.
ERROR 1129 (HY000): Host 'xxx.xxx.xxx.xxx' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'
此种验证无效:mysql -h 172.16.1.2 -utest -ptest1 -P 8888
上面的test用户的密码本来为test,测试时故意设置为test1,但是超过10次后,不会有上面的错误提示,此client ip也不会被锁定
锁定后,在mysql中查询下面表,可以看到相关记录SUM_CONNECT_ERRORS为10与参数max_connect_errors设置相同
localhost.performance_schema>select * from performance_schema.host_cache\G
*************************** 1. row ***************************
IP:xxxxxxx
HOST: xxxxxxxxxx
HOST_VALIDATED: YES
SUM_CONNECT_ERRORS: 10
COUNT_HOST_BLOCKED_ERRORS: 2
COUNT_NAMEINFO_TRANSIENT_ERRORS: 0
COUNT_NAMEINFO_PERMANENT_ERRORS: 0
COUNT_FORMAT_ERRORS: 0
COUNT_ADDRINFO_TRANSIENT_ERRORS: 0
COUNT_ADDRINFO_PERMANENT_ERRORS: 0
COUNT_FCRDNS_ERRORS: 0
COUNT_HOST_ACL_ERRORS: 0
COUNT_NO_AUTH_PLUGIN_ERRORS: 0
COUNT_AUTH_PLUGIN_ERRORS: 10
COUNT_HANDSHAKE_ERRORS: 5
COUNT_PROXY_USER_ERRORS: 0
COUNT_PROXY_USER_ACL_ERRORS: 0
COUNT_AUTHENTICATION_ERRORS: 33
COUNT_SSL_ERRORS: 0
COUNT_MAX_USER_CONNECTIONS_ERRORS: 0
COUNT_MAX_USER_CONNECTIONS_PER_HOUR_ERRORS: 0
COUNT_DEFAULT_DATABASE_ERRORS: 0
COUNT_INIT_CONNECT_ERRORS: 0
COUNT_LOCAL_ERRORS: 0
COUNT_UNKNOWN_ERRORS: 0
FIRST_SEEN: 2017-07-01 12:38:53
LAST_SEEN: 2017-07-01 12:45:16
FIRST_ERROR_SEEN: 2017-07-01 12:38:53
LAST_ERROR_SEEN: 2017-07-01 12:45:16
如果不采取错误,此block锁定会一直生效,从而阻止client暴力访问的情况,解除锁定的方法如下:
1. mysql> flush hosts;
2. mysqladmin flush-hosts
3. truncate table performance_schema.host_cache;或delete from performance_schema.host_cache;
4. 或者等待该记录从host cache中被挤掉。
以上是我在5.6.24环境上的测试结果,在其他版本也有过一点测试,但不是很完整,如果对此有疑义,欢迎一起交流沟通,谢谢!