MySQL网络安全-防syn攻击防暴力攻击

防syn泛滥攻击、暴力破解攻击
 
1)max_connect_errors 网络超时异常错误次数。非连接密码错误次数。
错误:ERROR 1129 (00000): Host 'xxx' is blocked because of many connection errors. Unblock with 'mysqladmin flush-hosts'
 
很多资料说,这个是密码输入错误的尝试次数超过max_connect_errors变量,MySQL就会阻塞这个客户端登录。
 
官方描述:
If more than this many successive connection requests from a host are interrupted without a successful connection, the server blocks that host from further connections. You can unblock blocked hosts by flushing the host cache. To do so, issue a FLUSH HOSTS statement or execute a mysqladmin flush-hosts command. If a connection is established successfully within fewer than max_connect_errors attempts after a previous connection was interrupted, the error count for the host is cleared to zero. However, once a host is blocked, flushing the host cache is the only way to unblock it. The default is 100.
 
大致如下:如果MySQL服务器连续接收到了来自于同一个主机的请求,而且这些连续的请求全部都没有成功的建立连接就被中断了,当这些连续的请求的累计值大于max_connect_errors的设定值时,MySQL服务器就会阻止这台主机后续的所有请求。
注意:其实这个就是因为由于网络异常而中止数据库连接。并没有提及密码错误尝试。
 
 
验证过程:
在MySQL数据库里面创建一个test账号,然后我们将max_connect_errors变量设置为3.
mysql> set global max_connect_errors=3;
Query OK, 0 rows affected (0.00 sec)
 
mysql> show variables like '%max_connect_error%';
+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| max_connect_errors | 3     |
+--------------------+-------+
1 row in set (0.00 sec)
 
然后我们在另外一台测试机器,以错误的密码去连接这个MySQL数据库,如下所示,即使前面输入了三次错误密码,第四次输入是也没有碰到上面错误。那么可以排除这个变量与密码错误输入有关系。
 
[root@mytestlnx02 tmp]# mysql -h10.20.57.24 -utest -p
Enter password:
ERROR 1045 (28000): Access denied for user 'test'@'mytestlnx02' (using password: YES)
 
[root@mytestlnx02 tmp]# mysql -h10.20.57.24 -utest -p
Enter password:
ERROR 1045 (28000): Access denied for user 'test'@'mytestlnx02' (using password: YES)
 
[root@mytestlnx02 tmp]# mysql -h10.20.57.24 -utest -p
Enter password:
ERROR 1045 (28000): Access denied for user 'test'@'mytestlnx02' (using password: YES)
 
[root@mytestlnx02 tmp]# mysql -h10.20.57.24 -utest -p
Enter password:
ERROR 1045 (28000): Access denied for user 'test'@'mytestlnx02' (using password: YES)
 
 
其实,关于某个IP客户端输入了错误密码,MySQL会在performance_schema数据库下的host_cache表中记录。它会累计记录在COUNT_AUTHENTICATION_ERRORS字段,如下所示:
 
mysql> select * from performance_schema.host_cache\G;
*************************** 1. row ***************************
                                        IP: 192.168.27.180
                                      HOST: gettestlnx02
                            HOST_VALIDATED: YES
                        SUM_CONNECT_ERRORS: 0
                 COUNT_HOST_BLOCKED_ERRORS: 0
           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: 0
                    COUNT_HANDSHAKE_ERRORS: 0
                   COUNT_PROXY_USER_ERRORS: 0
               COUNT_PROXY_USER_ACL_ERRORS: 0
               COUNT_AUTHENTICATION_ERRORS: 4
                          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: 2018-01-31 16:28:19
                                 LAST_SEEN: 2018-01-31 16:28:26
                          FIRST_ERROR_SEEN: 2018-01-31 16:28:19
                           LAST_ERROR_SEEN: 2018-01-31 16:28:26
1 row in set (0.00 sec)
 
官方资料介绍,COUNT_AUTHENTICATION_ERRORS的字段是统计被视为“阻塞”的连接错误的数量(根据max_connect_errors系统变量进行评估)。 只计算协议握手错误,并且仅用于通过验证的主机(HOST_VALIDATED = YES)。
 
MySQL客户端与数据库建立连接需要发起三次握手协议,正常情况下,这个时间非常短,但是一旦网络异常,网络超时等因素出现,就会导致这个握手协议无法完成,MySQL有个参数connect_timeout,它是MySQL服务端进程mysqld等待连接建立完成的时间,单位为秒。如果超过connect_timeout时间范围内,仍然无法完成协议握手话,MySQL客户端会收到异常,异常消息类似于: Lost connection to MySQL server at 'XXX', system error: errno,该变量默认是10秒.
 
那么我们就构造一个网络超时引起的数据库连接被中断案例吧,我们用Linux下的netem与tc命令模拟构造出复杂环境下的网络传输延时案例,如下设置后,此时从测试服务器去访问MySQL服务器,都会出现延时11秒:
 
[root@gettestlnx02 ~]# ping 10.20.57.24
PING 10.20.57.24 (10.20.57.24) 56(84) bytes of data.
64 bytes from 10.20.57.24: icmp_seq=1 ttl=62 time=0.251 ms
64 bytes from 10.20.57.24: icmp_seq=2 ttl=62 time=0.330 ms
64 bytes from 10.20.57.24: icmp_seq=3 ttl=62 time=0.362 ms
64 bytes from 10.20.57.24: icmp_seq=4 ttl=62 time=0.316 ms
 
 
[root@gettestlnx02 ~]# tc qdisc add dev eth0 root netem delay 11000ms
 
[root@gettestlnx02 ~]# ping 10.20.57.24
PING 10.20.57.24 (10.20.57.24) 56(84) bytes of data.
64 bytes from 10.20.57.24: icmp_seq=1 ttl=62 time=11000 ms
64 bytes from 10.20.57.24: icmp_seq=2 ttl=62 time=11000 ms
64 bytes from 10.20.57.24: icmp_seq=3 ttl=62 time=11000 ms
 
我们在测试服务器gettestlnx02连接MySQL数据库,如下所示(注意,如果你是在通过ssh连接这台服务器的话,此时在gettestlnx02上操作会相当慢。当然你也可以在MySQL服务器模拟网络延时,或者你将connect_timeout和网络延时都设小一点)
 
[root@gettestlnx02 ~]# mysql -h10.20.57.24 -utest -p
Enter password:
ERROR 2013 (HY000): Lost connection to MySQL server at 'reading authorization packet', system error: 0
 
如上所示,由于网络延时超过10秒,导致连接MySQL失败,此时,你在MySQL服务器上查询host_cache表时,那么你就会看到SUM_CONNECT_ERRORS变成1了,COUNT_HANDSHAKE_ERRORS也变成了1.
 
那么我们反复这样折腾三次,那么你会看到SUM_CONNECT_ERRORS变成3了,COUNT_HANDSHAKE_ERRORS也变成了3了.
mysql> select * from host_cache\G;
*************************** 1. row ***************************
                                        IP: 192.168.27.180
                                      HOST: gettestlnx02
                            HOST_VALIDATED: YES
                        SUM_CONNECT_ERRORS: 3
                 COUNT_HOST_BLOCKED_ERRORS: 1
           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: 0
                    COUNT_HANDSHAKE_ERRORS: 3
                   COUNT_PROXY_USER_ERRORS: 0
               COUNT_PROXY_USER_ACL_ERRORS: 0
               COUNT_AUTHENTICATION_ERRORS: 4
                          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: 2018-01-31 16:28:19
                                 LAST_SEEN: 2018-01-31 17:02:10
                          FIRST_ERROR_SEEN: 2018-01-31 16:28:19
                           LAST_ERROR_SEEN: 2018-01-31 17:02:10
1 row in set (0.00 sec)
 
然后我们用netem与tc 命令在测试服务器上取消网络延迟模拟,然后去测试连接MySQL数据库,如下测试所示:
 
[root@gettestlnx02 ~]# tc qdisc del dev eth0 root netem delay 11000ms
[root@gettestlnx02 ~]# mysql -h10.20.57.24 -utest -p
Enter password:
ERROR 1129 (HY000): Host '192.168.27.180' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'
 
此时就能构造出开头的错误了。
 
 
解决方案
  解决网络延迟。
 
临时解决方法:
 
1、将变量max_connection_errors的值设置为一个更大的值
mysql> set global max_connect_errors=150;
Query OK, 0 rows affected (0.00 sec)
 
可以在my.cnf配置文件里面配置。
 
2、使用flush hosts
mysql> flush hosts;
Query OK, 0 rows affected (0.00 sec)
 
mysql> select * from performance_schema.host_cache;
Empty set (0.00 sec)
 
 
2)那么host cache是什么呢?
 
简单来说,就是MySQL服务器在内存中维护一个包含客户端信息的缓存:IP地址,主机名和错误信息等。 服务器会将非本地TCP连接信息缓存起来。它不会缓存使用环回接口地址(127.0.0.1或者:: 1)建立的TCP连接,或者使用Unix套接字文件,命名管道或共享内存建立的连接。host cache信息可以通过performance_schema数据库下的host_cache表查询。
 
查看是否开启,性能模式。
  show variables like 'performance_schema';

开启性能模式,host_cache开会记录:
  set global performance_schema=on;

 

总结:关于参数max_connect_errors,这个不能作为防暴力破解密码攻击的手段。但可以防止SYN泛滥攻击。
但是在performance_schema.host_cache记录了COUNT_AUTHENTICATION_ERRORS数量,是可以作为密码错误参考的数据。


3)Aborted_clients & Aborted_connects状态变量

Aborted Connect表示尝试连接到MySQL服务器失败的次数。这个状态变量可以结合host_cache表和错误日志一起来分析问题。
引起这个状态变量激增的原因如下:
  1、 客户端没有权限但是尝试访问MySQL数据库。
  2、 客户端输入的密码有误。
  3、 错误的连接packet包信息。
  4、 超过连接时间限制,主要是这个系统变量connect_timeout控制(mysql默认是10s)

Aborted Clients表示由于客户端没有正确关闭连接而中止的连接数。
当Aborted Clients增大的时候意味着有客户端成功建立连接,但是由于某些原因断开连接或者被终止了,这种情况一般发生在网络不稳定的环境中。主要的可能性有:
  1、 客户端程序在退出之前未调用mysql_close()正确关闭MySQL连接。
  2、 客户端休眠的时间超过了系统变量wait_timeout和interactive_timeout的值,导致连接被MySQL进程终止。
  3、 客户端程序在数据传输过程中突然结束,网络异常。

还有一些原因导致两个变量增加:
  1、max_allowed_packet变量值太小,或者查询需要的内存比分配给mysqld的内存多。
  2、在Linux上使用Ethernet协议,包括半双工和全双工,可能产生异常。
  3、线程库的问题导致读取时中断。
  4、TCP/IP配置不当。
  5、Ethernets, hubs, switches, cables等硬件故障。


1、 客户端没有权限但是尝试访问MySQL数据库。
(1)使用不存在的账号访问MySQL。

  实验对比测试前,先将状态变量清零。
  mysql> flush status;
  Query OK, 0 rows affected (0.01 sec)

  mysql> show status like 'Abort%';
  +------------------+-------+
  | Variable_name | Value |
  +------------------+-------+
  | Aborted_clients | 0 |
  | Aborted_connects | 0 |
  +------------------+-------+
  2 rows in set (0.01 sec)

使用不存在的账号kkk访问MySQL后,你会发现状态变量Aborted_connects变为1了。
  mysql -ukkk -p12314 -h192.168.2.101 -P3006
  mysql> show status like 'Abort%';
  +------------------+-------+
  | Variable_name | Value |
  +------------------+-------+
  | Aborted_clients | 0 |
  | Aborted_connects | 1 |
  +------------------+-------+
  2 rows in set (0.01 sec)

(2)这个账号本身存在,但是只允许特定IP地址才能访问。
  mysql> grant all on *.* to 'kkk'@'192.168.2.102';

  192.168.2.103>mysql -ukkk -p12314 -h192.168.2.101 -P3006
  mysql> show status like 'Abort%';
  +------------------+-------+
  | Variable_name | Value |
  +------------------+-------+
  | Aborted_clients | 0 |
  | Aborted_connects | 1 |
  +------------------+-------+
  2 rows in set (0.00 sec)

(3)客户端输入的密码有误或者根本就是尝试各个密码。(暴力破解)
  192.168.2.103>mysql -ukkk -p12312312 -h192.168.2.101 -P3006
  mysql> show status like 'Abort%';
  +------------------+-------+
  | Variable_name | Value |
  +------------------+-------+
  | Aborted_clients | 0 |
  | Aborted_connects | 2 |
  +------------------+-------+
  2 rows in set (0.00 sec)
状态变量Aborted_connects就会发现状态变量Aborted_connects变为2了。


2、错误的连接packet包信息
  可以对MySQL的端口进行端口测试(ping 端口),因为psping的包就是不包含正确的包信息。
  下载:https://learn.microsoft.com/zh-cn/sysinternals/downloads/psping

  在客户端对MySQL服务所在的主机进行端口连通性验证(psping)
  C:\Users\Administrator>d:
  d:\>cd sss\PSTools
  d:\sss\PSTools>psping.exe 127.0.0.1:3306

  PsPing v2.12 - PsPing - ping, latency, bandwidth measurement utility
  Copyright (C) 2012-2023 Mark Russinovich
  Sysinternals - www.sysinternals.com

  TCP connect to 127.0.0.1:3306:
  5 iterations (warmup 1) ping test:
  Connecting to 127.0.0.1:3306 (warmup): from 127.0.0.1:49834: 0.15ms
  Connecting to 127.0.0.1:3306: from 127.0.0.1:49835: 0.27ms
  Connecting to 127.0.0.1:3306: from 127.0.0.1:49840: 0.24ms
  Connecting to 127.0.0.1:3306: from 127.0.0.1:49841: 0.29ms

  Sent = 3, Received = 3, Lost = 0 (0% loss),
  Minimum = 0.24ms, Maximum = 0.29ms, Average = 0.27ms


  mysql> show status like 'Abort%';
  +------------------+-------+
  | Variable_name | Value |
  +------------------+-------+
  | Aborted_clients | 0 |
  | Aborted_connects | 3 |
  +------------------+-------+
  2 rows in set (0.00 sec)
每psping一次Aborted_connects就加1.

从上可以看出,很多情况下,Aborted_connects都会增加。结合host_cache,以及warning_log来进行具体分析。

  1、 客户端没有权限但是尝试访问MySQL数据库。
  每次都会引起COUNT_AUTHENTICATION_ERRORS增1 ,第一次会引起COUNT_NAMEINFO_PERMANENT_ERRORS也增1

  2、 客户端输入的密码有误
  每次都会引起COUNT_AUTHENTICATION_ERRORS增1 ,第一次会引起COUNT_NAMEINFO_PERMANENT_ERRORS也增1

  set global log_warnings=2;
  例如:
  2018-06-20 22:44:16 18026 [Warning] IP address '192.168.xxx.xxx' could not be resolved: Name or service not known
  2018-06-20 22:44:16 18026 [Warning] Access denied for user 'kkkk'@'192.168.xxx.xxx' (using password: YES)
  2018-06-20 22:45:18 18026 [Warning] Access denied for user 'test'@'192.168.xxx.xxx' (using password: YES)

3、 错误的连接packet包信息
  每次引起COUNT_HANDSHAKE_ERRORS增1,
  每次引起SUM_CONNECT_ERRORS增1

4、 超过连接时间限制
  每次引起SUM_CONNECT_ERRORS增1,
  每次引起COUNT_HANDSHAKE_ERRORS增1
  第一次会引起COUNT_NAMEINFO_PERMANENT_ERRORS增1
注意: 3与4不会写入错误日志,3与4的区别可以通过COUNT_NAMEINFO_PERMANENT_ERRORS的值来区别。


4)Aborted_clients 变量

1、 客户端程序在退出之前未调用mysql_close()正确关闭MySQL连接。
  import mysql.connector

  try:
    dbcon=mysql.connector.connect(
    host='127.0.0.1',
    user='root' ,
    passwd='xxxxxxx',
    database='information_schema'
    )

    cursor= dbcon.cursor()
    sql_tex='select count(*) from MyDB.test'
    cursor.execute(sql_tex)
    dtlist= cursor.fetchall()
    print dtlist
  except mysql.connector.Error as e:
    print('operation the sql fail!{0}'.format(e))
  finally:
    cursor.close;
    # dbcon.close;

执行一下脚本,检查状态变量Aborted_clients,然后发现状态变量Aborted_clients的值增1了。

2、 客户端休眠的时间超过了系统变量wait_timeout和interactive_timeout的值,导致连接被MySQL进程终止
  将全局系统变量interactive_timeout 和wait_timeout设置为4秒
  mysql> set global interactive_timeout=4;
  mysql> set global wait_timeout=4;

客户端连接到MySQL数据库,不做任何操作,过来4秒后,操作就会出现错误“ERROR 2013 (HY000): Lost connection to MySQL server during query”

状态变量Aborted_clients变为1了。
  mysql> show status like 'Abort%';
  +------------------+-------+
  | Variable_name | Value |
  +------------------+-------+
  | Aborted_clients | 1 |
  | Aborted_connects | 0 |
  +------------------+-------+
  2 rows in set (0.00 sec

还有其他一些原因(客户端异常中断或查询超出了max_allowed_packet值)由于不方便构造,在此略过。


因此可以结合max_connect_errors,host_cache表,Aborted_clients,Aborted_connects以及错误日志来综合分析,某些情况的,获取同一IP来源的错误请求过多的IP,自动添加到防火墙禁止访问。

同时也可以抓包分析,在故障时间段或者复现时。
tcpdump -i eth0 port 3306 -s 1500 -w tcpdump.log

抓包工具有以下几种:
Wireshark:免费的开源抓包工具,适用于多个操作系统,捕获网络流量进行分析处理。可以打开tcpdump包进行分析。
Fiddler:针对HTTP(S)的免费抓包工具,适用于浏览器,可记录客户端和服务器之间的HTTP(S)流量。
Tcpdump:适用于无GUI界面的服务器。 

 
参考资料:
http://mysqlblog.fivefarmers.com/2013/08/08/understanding-max_connect_errors/
https://dev.mysql.com/doc/refman/8.4/en/performance-schema-host-cache-table.html
 
posted @ 2024-07-04 23:25  cdrcsy  阅读(1)  评论(0编辑  收藏  举报