3-4-12-HAProxy高级功能与配置之haproxy 防范攻击
1. 慢查询工具
slowloris类型的攻击 , 客户端用非常非常慢的速度发送请求到服务器上。 通常是一个包头接一个包头或者更夸张的一个字符接一个字符 , 而每个包之间等待非常长的时间。这样服务器端就不得不等待所有请求全部接收完毕才能返回响应。这个攻击的目的是阻止正常用户访问我们提供的服务 , 所有的服务器资源都被用来等待处理慢查询了。
# On Aloha, the global section is already setup for you
# and the haproxy stats socket is available at /var/run/haproxy.stats
global
stats socket ./haproxy.stats level admin
defaults
option http-server-close
mode http
timeout http-request 5s
timeout connect 5s
timeout server 10s
timeout client 30s
listen stats
bind 0.0.0.0:8880
stats enable
stats hide-version
stats uri /
stats realm HAProxy\ Statistics
stats auth admin:admin
frontend ft_web
bind 0.0.0.0:8080
# Spalreadylit static and dynamic traffic since these requests have different impacts on the servers
use_backend bk_web_static if { path_end .jpg .png .gif .css .js }
default_backend bk_web
# Dynamic part of the application
backend bk_web
balance roundrobin
cookie MYSRV insert indirect nocache
server srv1 192.168.1.2:80 check cookie srv1 maxconn 100
server srv2 192.168.1.3:80 check cookie srv2 maxconn 100
# Static objects
backend bk_web_static
balance roundrobin
server srv1 192.168.1.2:80 check maxconn 1000
server srv2 192.168.1.3:80 check maxconn 10002. unfair用户
何谓一个"Unfair"用户?就是指这个用户(或者脚本)有不同于正常用户的行为:
打开太多连接
建立新连接的频率太快
http请求的频率太快使用太多的带宽
客户端不遵守RFC协议(IE for SMTP)
在保护我们站点不受怪异的行为伤害之前 , 我们需要了解正常的浏览器行为是什么样子的。 首先 , 用户会打开Chrome、Firefox、 Internet Explorer、Opera之间的一种 , 然后输入URL。浏览器首先去请求DNS解析IP地址 , 然后它会建立一个和服务器的连接 , 下载首页 , 分析其中的内容。 然后根据页面的HTML代码的连接去下载不同的对象 : javascript, css, 图片等等。 为了下载对象 , 对于每个域名 , 浏览器会打开6或7个TCP连接。等到所有对象下载完毕 ,浏览器会将这些对象叠加渲染出整个页面。
2.1 限制每个用户的连接数
根据之前的说明 , 每个用户浏览器会与webserver之间非常快的打开6或7个TCP连接 , 那么我们可以认为如果 一个用户打开了超过10个TCP连接就是不正常的行为。
以下示例作了每用户连接数的限制,重点在于25-32行。
# On Aloha, the global section is already setup for you
# and the haproxy stats socket is available at /var/run/haproxy.stats
global
stats socket ./haproxy.stats level admin
defaults
option http-server-close
mode http
timeout http-request 5s
timeout connect 5s
timeout server 10s
timeout client 30s
listen stats
bind 0.0.0.0:8880
stats enable
stats hide-version
stats uri /
stats realm HAProxy\ Statistics
stats auth admin:admin
frontend ft_web
bind 0.0.0.0:8080
# Table definition
stick-table type ip size 100k expire 30s store conn_cur
# Allow clean known IPs to bypass the filter
tcp-request connection accept if { src -f /etc/haproxy/whitelist.lst }
# Shut the new connection as long as the client has already 10 opened
tcp-request connection reject if { src_conn_cur ge 10 }
tcp-request connection track-sc1 src
# Split static and dynamic traffic since these requests have different impacts on the servers
use_backend bk_web_static if { path_end .jpg .png .gif .css .js }
default_backend bk_web
# Dynamic part of the application
backend bk_web
balance roundrobin
cookie MYSRV insert indirect nocache
server srv1 192.168.1.2:80 check cookie srv1 maxconn 100
server srv2 192.168.1.3:80 check cookie srv2 maxconn 100
# Static objects
backend bk_web_static
balance roundrobin
server srv1 192.168.1.2:80 check maxconn 1000
server srv2 192.168.1.3:80 check maxconn 1000配置文件解说:
# 定义一个以ip类型为key , 大小100K , 过期时间30秒的stick-table , 用于存储该IP对应的当前connection数量
stick-table type ip size 100k expire 30s store conn_cur
# 允许白名单用户的IP绕过限制
tcp-request connection accept if { src -f /etc/haproxy/whitelist.lst }
# 如果当前客户端ip的connection数量已经超过10个 , 则拒绝其发起的新连接
tcp-request connection reject if { src_conn_cur ge 10 }
tcp-request connection track-sc1 srcsrc_conn_cur 是ACL layer 4的fetch method , 作用是用当前发起连接的客户端源ip地址做key , 去stick-table中查找对应的当前connection数量 , 如果查到则返回实际数值 , 查不到则返回0。
注意:
如果
HAProxy用于代理多个域名 , 则需要增加conn_cur的数量 ,因为每个域名会有5-7个连接。如果多个用户在同一NAT设备后边 , 则这个限制会对他们产生不利影响 , 原因显而易见。
测试
#使用Apache bench打开10个连接:
ab -n 50000000 -c 10 http://127.0.0.1:8080/
#观察haproxy的stats输出:
echo “show table ft_web” | socat unix:./haproxy.stats -
#table: ft_web, type: ip, size:102400, used:1
0x7afa34: key=127.0.0.1 use=10 exp=29994 conn_cur=10
#我们打开telnet尝试建立新连接:
telnet 127.0.0.1 8080
Trying 127.0.0.1…
Connected to 127.0.0.1.
Escape character is ‘^]’.
Connection closed by foreign host.
#发现已经被HAProxy拒绝了。2.2 限制每用户建立连接的频率
我们可以认为3秒钟之内建立超过20个连接的用户就是非正常访问。
# On Aloha, the global section is already setup for you
# and the haproxy stats socket is available at /var/run/haproxy.stats
global
stats socket ./haproxy.stats level admin
defaults
option http-server-close
mode http
timeout http-request 5s
timeout connect 5s
timeout server 10s
timeout client 30s
listen stats
bind 0.0.0.0:8880
stats enable
stats hide-version
stats uri /
stats realm HAProxy\ Statistics
stats auth admin:admin
frontend ft_web
bind 0.0.0.0:8080
# Table definition
stick-table type ip size 100k expire 30s store conn_rate(3s)
# Allow clean known IPs to bypass the filter
tcp-request connection accept if { src -f /etc/haproxy/whitelist.lst }
# Shut the new connection as long as the client has already 10 opened
tcp-request connection reject if { src_conn_rate ge 10 }
tcp-request connection track-sc1 src
# Split static and dynamic traffic since these requests have different impacts on the servers
use_backend bk_web_static if { path_end .jpg .png .gif .css .js }
default_backend bk_web
# Dynamic part of the application
backend bk_web
balance roundrobin
cookie MYSRV insert indirect nocache
server srv1 192.168.1.2:80 check cookie srv1 maxconn 100
server srv2 192.168.1.3:80 check cookie srv2 maxconn 100
# Static objects
backend bk_web_static
balance roundrobin
server srv1 192.168.1.2:80 check maxconn 1000
server srv2 192.168.1.3:80 check maxconn 1000注意 : 如果多个用户在同一NAT设备后边 , 则这个限制也会对他们产生不利影响 , 原因同样显而易见。
测试
ab -n 10 -c 1 -r http://127.0.0.1:8080/
echo “show table ft_web” | socat unix:./haproxy.stats -
#table: ft_web, type: ip, size:102400, used:1
0x11faa3c: key=127.0.0.1 use=0 exp=28395 conn_rate(3000)=10
telnet 127.0.0.1 8080
Trying 127.0.0.1…
Connected to 127.0.0.1.
Escape character is ‘^]’.
Connection closed by foreign host.2.3 限制HTTP请求频率
# On Aloha, the global section is already setup for you
# and the haproxy stats socket is available at /var/run/haproxy.stats
global
stats socket ./haproxy.stats level admin
defaults
option http-server-close
mode http
timeout http-request 5s
timeout connect 5s
timeout server 10s
timeout client 30s
listen stats
bind 0.0.0.0:8880
stats enable
stats hide-version
stats uri /
stats realm HAProxy\ Statistics
stats auth admin:admin
frontend ft_web
bind 0.0.0.0:8080
# Use General Purpose Couter (gpc) 0 in SC1 as a global abuse counter
# Monitors the number of request sent by an IP over a period of 10 seconds
stick-table type ip size 1m expire 10s store gpc0,http_req_rate(10s)
tcp-request connection track-sc1 src
tcp-request connection reject if { src_get_gpc0 gt 0 }
# Split static and dynamic traffic since these requests have different impacts on the servers
use_backend bk_web_static if { path_end .jpg .png .gif .css .js }
default_backend bk_web
# Dynamic part of the application
backend bk_web
balance roundrobin
cookie MYSRV insert indirect nocache
# If the source IP sent 10 or more http request over the defined period,
# flag the IP as abuser on the frontend
acl abuse src_http_req_rate(ft_web) ge 10
acl flag_abuser src_inc_gpc0(ft_web)
tcp-request content reject if abuse flag_abuser
server srv1 192.168.1.2:80 check cookie srv1 maxconn 100
server srv2 192.168.1.3:80 check cookie srv2 maxconn 100
# Static objects
backend bk_web_static
balance roundrobin
server srv1 192.168.1.2:80 check maxconn 1000
server srv2 192.168.1.3:80 check maxconn 10002.4 检测漏洞扫描
如果有人尝试对我们的站点进行漏洞扫描 , 那么通过HAProxy可以追踪到不同的错误。
HAProxy可以监控每个用户产生错误的频率 , 并且根据这个频率决定进一步的操作。
# On Aloha, the global section is already setup for you
# and the haproxy stats socket is available at /var/run/haproxy.stats
global
stats socket ./haproxy.stats level admin
defaults
option http-server-close
mode http
timeout http-request 5s
timeout connect 5s
timeout server 10s
timeout client 30s
listen stats
bind 0.0.0.0:8880
stats enable
stats hide-version
stats uri /
stats realm HAProxy\ Statistics
stats auth admin:admin
frontend ft_web
bind 0.0.0.0:8080
# Use General Purpose Couter 0 in SC1 as a global abuse counter
# Monitors the number of errors generated by an IP over a period of 10 seconds
stick-table type ip size 1m expire 10s store gpc0,http_err_rate(10s)
tcp-request connection track-sc1 src
tcp-request connection reject if { src_get_gpc0 gt 0 }
# Split static and dynamic traffic since these requests have different impacts on the servers
use_backend bk_web_static if { path_end .jpg .png .gif .css .js }
default_backend bk_web
# Dynamic part of the application
backend bk_web
balance roundrobin
cookie MYSRV insert indirect nocache
# If the source IP generated 10 or more http request over the defined period,
# flag the IP as abuser on the frontend
acl abuse src_http_err_rate(ft_web) ge 10
acl flag_abuser src_inc_gpc0(ft_web)
tcp-request content reject if abuse flag_abuser
server srv1 192.168.1.2:80 check cookie srv1 maxconn 100
server srv2 192.168.1.3:80 check cookie srv2 maxconn 100
# Static objects
backend bk_web_static
balance roundrobin
server srv1 192.168.1.2:80 check maxconn 1000
server srv2 192.168.1.3:80 check maxconn 1000测试
ab -n 10 http://127.0.0.1:8080/dlskfjlkdsjlkfdsj
echo “show table ft_web” | socat unix:./haproxy.stats -
#table: ft_web, type: ip, size:1048576, used:1
0x8a9770: key=127.0.0.1 use=0 exp=5866 gpc0=1 http_err_rate(10000)=11.
#再次执行上边的ab命令 , 会得到如下错误:
apr_socket_recv: Connection reset by peer (104)
#说明HAProxy已经block这个IP。