作爲 load balancer, Happroxy 常常作爲服務器的前端,向外界用戶提供服務的入口,如果能在入口處處理安全相關問題,將極大簡化後端的設計。事實上,Haproxy 不僅僅是一款開源出色的 load balancer(四層和七層),而且在安全上也相當出色。它配合內核 IP/TCP 協議棧,能夠較好的抵抗 DOS, DDOS 攻擊,還能通過限制單個 IP 的連接數和請求速率等,防止用戶的惡意行爲。
Haproxy 配置參數多的一塌糊塗,因而功能豐富,靈活多樣,本文拋磚引玉,更多的安全功能請詳見官網手冊。
TCP syn flood attacks
通過向服務器發送大量的 TCP syn 分組,惡意用戶實現了了 TCP syn flood 攻擊,幸運的是,簡單的配置內核網絡參數即可防止這種攻擊。
/etc/sysctl.conf
# Protection SYN flood
net.ipv4.tcp_syncookies = 1
net.ipv4.conf.all.rp_filter = 1
net.ipv4.tcp_max_syn_backlog = 1024
sysctl -p
Slowloris like attacks
一個 Http 請求通常包括頭部、url、methods 等,服務器需要接收整個 Http 請求後會做出響應。惡意用戶發送緩慢的 Http 請求,比如一個字節一個字節的發送頭部,服務器將一直處於 wating 狀態,從而耗費服務器的資源。Haproxy 通過配置 timeout
http-request 參數,當一個用戶的請求時間超過設定值時,Haproxy 斷開與該用戶的連接。
defaults
option http-server-close
mode http
<span style="color:#ff0000;">timeout http-request 5s</span> # 防止 Slowloris like attacks
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
default_backend bk_web
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
通過 telnet 登錄驗證結果
telnet 127.0.0.1 8080
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
HTTP/1.0 408 Request Time-out
Cache-Control: no-cache
Connection: close
Content-Type: text/html
<h1>408 Request Time-out</h1>
Your browser didn't send a complete request in time.
Connection closed by foreign host.
Limiting the number of connections per users
以網站爲例,普通用戶訪問網站,或者從網站下載東西時,瀏覽器一般會建立 5-7 個 TCP 鏈接。當一個惡意打開了大量 TCP 鏈接時,耗費服務器大量資源,影響其它用戶的訪問,因此我們需要根據實際情況,限制同一個用戶的鏈接數。
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
<span style="color:#ff0000;"> # 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</span>
default_backend bk_web
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
注:若某些用戶在同一個私有網段通過 NAT 訪問網站,這樣的配置存在不合理之處,最好把 NAT 處的公網地址添加到 whitelist.lst 文件中。
利用 apache 測試工具做驗證,和服務器一直保持建立 10 個鏈接。
ab -n 50000000 -c 10 http://127.0.0.1:8080/
用 telnet 打開第 11 個鏈接,服務器拒絕該鏈接。
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.
Limiting the connection rate per user
僅僅限制單個用戶的併發鏈接數並意味着萬事大吉,如果用戶在短時間內向服務器不斷的發送建立和關閉鏈接請求,也會耗費服務器資源,影響服務器端的性能,因此需要控制單個用戶的訪問速率。
通常情況下,考慮到用戶通過瀏覽器一般會建立 5-7 條 TCP 鏈接,我們可以認爲普通用戶在 3 秒內不應該建立超過 20 條鏈接。
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,<span style="color:#ff0000;">conn_rate(3s)</span>
# 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 or rate more than 20
tcp-request connection reject if { src_conn_cur ge 10 } <span style="color:#ff0000;">|| { src_conn_rate ge 20}</span>
tcp-request connection track-sc1 src
default_backend bk_web
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
注:若某些用戶在同一個私有網段通過 NAT 訪問網站,這樣的配置存在不合理之處,最好把 NAT 處的公網地址添加到 whitelist.lst 文件中。
測試,採用 ab 打開 20 個鏈接。(本次測試把 限制單個用戶併發數功能 去掉)
ab -n 20 -c 1 -r http://127.0.0.1:8080/
再用 telnet 打開第 21 個鏈接,服務器拒絕該請求。
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.
原文
Use a load-balancer as a first row of defense against DDOS
歡迎分享,我的微博:範小良gogogo