İçeriğe geç

Teknik derinlik

HAProxy DDoS Sıkılaştırma ve Ayarlama

Son güncelleme: Ağustos 2026 · Stick table, timeout, bağlantı tavanı · Okuma süresi ~14 dk

Kapasitesi sabit bir salonun önünde tutulan bir kuyruk; vekilde uygulanan ve arkasındaki kaynağın hiç boğulmamasını sağlayan bağlantı limitlerini temsil ediyor.

HAProxy'nin DDoS açısından önemli denetimleri üçtür: kaynak başına davranışı izleyen stick table, yavaş istemcileri sınırlayan timeout kümesi, ve frontend, backend ile sunucu düzeyindeki maxconn. Birlikte, orta ölçekli bir selin emilip emilmeyeceğine ya da onu kaldıramayacak bir kaynağa iletilip iletilmeyeceğine karar verirler. Hiçbiri dolmuş bir hattın yaptığını değiştirmez.

HAProxy sık sık, bir saldırının ulaştığı ve karar verebilen ilk şeydir. Bağlantı düzeyindeki denetimleri uygulamak için doğal yer olmasının sebebi budur. Aynı sebeple, varsayılanları orta ölçekli bir selin olay olup olmayacağına en sık karar veren bileşendir.

Aşağıdakilerin tamamı vekilin kendisiyle ilgili. Hat tavanı hiçbiriyle değişmiyor.

0. Önce temel ölçüler

# Live counters, per frontend, backend and server
echo "show stat" | socat stdio /var/run/haproxy.sock | cut -d, -f1,2,5,8,34,35

# Current session rate and totals
echo "show info" | socat stdio /var/run/haproxy.sock | grep -E 'CurrConns|SessRate|MaxSessRate|CumConns'

# What the stick tables currently hold
echo "show table" | socat stdio /var/run/haproxy.sock

MaxSessRate ve CurrConns değerlerini, hakiki bir iş tepesini içeren bir dönem boyunca kaydedin. Aşağıdaki her limit bir varsayılana göre değil bu sayılara göre konur.

1. Bağlantı tavanları

global
    # Process-wide ceiling. Memory is roughly this × per-connection cost;
    # size it against measured RAM rather than optimistically.
    maxconn 60000

defaults
    mode http
    option httplog

frontend web
    bind :443 ssl crt /etc/haproxy/certs/
    # Frontend ceiling: what HAProxy itself will accept.
    maxconn 50000
    default_backend origin

backend origin
    # Per-server ceiling: what actually reaches the origin. Requests beyond
    # this queue in HAProxy rather than overwhelming the backend.
    server app1 10.0.0.11:8080 check maxconn 400
    server app2 10.0.0.12:8080 check maxconn 400
    # Bound the queue too — an unbounded queue converts an overload into
    # a latency collapse that looks like an outage anyway.
    timeout queue 5s

Önemli olan desen şu: yüksek bir frontend tavanı, çok daha düşük bir sunucu başına tavan, ve aralarında sınırları çizilmiş bir kuyruk. Bu, bir yükselişi arka uç arızasına değil eklenen gecikmeye ve atılan yüke çevirir.

2. Timeout’lar: yavaş HTTP’nin cevabı

defaults
    # The decisive one: how long a client may take to send complete headers.
    # Slowloris-class attacks exist entirely in the space this leaves open.
    timeout http-request    5s

    # Idle client connection.
    timeout client          30s
    # Half-closed client connection still consuming a slot.
    timeout client-fin      10s

    # Connecting to the backend, and backend idle.
    timeout connect         5s
    timeout server          30s
    timeout server-fin      10s

    # Keep-alive reuse window; shorter under pressure.
    timeout http-keep-alive 10s
    # Time a request may sit in the queue before being rejected.
    timeout queue           5s
    # Tarpit duration for requests you want to slow rather than reject.
    timeout tarpit          30s

Etkiyi varsaymak yerine doğrulayın:

# Open a connection and send headers one byte at a time; it should be
# closed after timeout http-request rather than held open.
printf 'GET / HTTP/1.1\r\nHost: example\r\n' | timeout 20 nc -q 20 127.0.0.1 443

3. Stick table: kaynak başına oran denetimi

frontend web
    bind :443 ssl crt /etc/haproxy/certs/

    # One table, several counters, tracked per source address.
    # 1m expiry keeps memory bounded; size against your real client count.
    stick-table type ip size 1m expire 1m store \
        conn_cur,conn_rate(10s),http_req_rate(10s),http_err_rate(10s)

    # Track every incoming connection against it.
    http-request track-sc0 src

    # Concurrent connections from one source.
    http-request deny deny_status 429 if { sc0_conn_cur gt 60 }

    # New connections per 10s from one source.
    http-request deny deny_status 429 if { sc0_conn_rate gt 200 }

    # Requests per 10s from one source.
    http-request deny deny_status 429 if { sc0_http_req_rate gt 400 }

    # Error rate — a source generating mostly 4xx is probing, not browsing.
    http-request deny deny_status 429 if { sc0_http_err_rate gt 100 }

Bir olay sırasında tablonun gerçekte ne tuttuğunu inceleyin:

# Sources currently over a threshold
echo "show table web data.http_req_rate gt 400" \
  | socat stdio /var/run/haproxy.sock

# Clear one entry after a false positive
echo "clear table web key 203.0.113.9" | socat stdio /var/run/haproxy.sock

Kaynak başına çekince burada da geçerli. Operatör düzeyinde adres paylaşımı yüzünden tek bir adres binlerce kullanıcıyı meşru olarak temsil edebilir. Bu eşiklerin, paylaşılan bir çıkışın ürettiğinin epeyce üstüne konması gerekir, yoksa bir saldırganı rahatsız etmeden önce bir mobil şebekeyi engellerler. Muhakemesi hız sınırlama sayfasında işleniyor.

4. Pahalı uç noktaları ayrıca korumak

frontend web
    # A second table keyed on the path group rather than the client,
    # so the limit protects the operation rather than punishing a user.
    stick-table type string len 64 size 100k expire 10s store http_req_rate(10s)

    acl expensive path_beg /search /report /export
    http-request track-sc1 base32 if expensive
    http-request deny deny_status 429 if expensive { sc1_http_req_rate gt 200 }

Bu ayrım, tek bir genel sınırdan belirgin biçimde daha az yanlış pozitif üretir. Sınır kullanıcıyı cezalandırmak yerine pahalı işlemi korur.

5. Reddetmek yerine yavaşlatmak

    # Tarpit holds the connection instead of returning immediately, which
    # costs the attacker a slot. Use sparingly — it costs you one too.
    http-request tarpit if { sc0_http_req_rate gt 800 }

    # Silently drop, no response at all.
    http-request silent-drop if { sc0_conn_rate gt 500 }

silent-drop açılmadan önce anlaşılmayı hak ediyor. TCP sıfırlaması göndermeden kapatır, yani saldırgana anında bir işaret yerine bir zaman aşımına mal olur, ve kural yanlışsa meşru bir istemciyi de aynı biçimde askıda bırakır.

6. TLS tarafındaki baskı

frontend web
    bind :443 ssl crt /etc/haproxy/certs/ \
        ciphers ECDHE+AESGCM:ECDHE+CHACHA20 \
        no-sslv3 no-tlsv10 no-tlsv11

    # Handshake rate per source: TLS renegotiation and handshake floods
    # consume CPU rather than bandwidth.
    stick-table type ip size 1m expire 1m store gpc0,conn_rate(10s)
# Watch handshake cost during a test
openssl s_time -connect 127.0.0.1:443 -new -time 10

7. İzleme

frontend stats
    bind 127.0.0.1:8404
    stats enable
    stats uri /stats
    stats refresh 5s
# Rejections by reason, from the log
awk '{print $11}' /var/log/haproxy.log | sort | uniq -c | sort -rn | head

# Queue depth and denied counters
echo "show stat" | socat stdio /var/run/haproxy.sock \
  | awk -F, 'NR==1 || $1=="origin" {print $1,$2,$3,$4,$5,$6}'

dreq ve dresp sayaçlarını, yani reddedilen istek ve cevapları, birinci sınıf ölçüt olarak izleyin. Olağan trafik sırasında yükselmeleri bir başarı değil bir yanlış pozitif olayıdır.

Güvenli devreye alma sırası

  1. Önce timeout’ları koyun. Yanlış pozitif riski en düşük olanlar bunlar, ve yavaş HTTP sınıfını anında cevaplıyorlar.
  2. maxconn değerini önce sunucu, sonra backend, sonra frontend düzeyinde ekleyin, her adımda kuyruk derinliğini ölçerek.
  3. Stick table’ları gözlem kipinde ekleyin, yani reddetmeden izleyin, ve en az bir iş tepesi boyunca dağılımı izleyin.
  4. Gözlenen eşikleri ancak bundan sonra rete çevirin, ve ölçtüğünüz tepenin epeyce üstüne koyun.
  5. clear table komutunu el kitabında tutun, çünkü ilk yanlış pozitif ona ihtiyaç duyacak.

Geri alma

# Validate before applying — a bad config that reloads is worse than one that fails
haproxy -c -f /etc/haproxy/haproxy.cfg

# Seamless reload, existing connections preserved
systemctl reload haproxy

# Revert
cp /etc/haproxy/haproxy.cfg.bak /etc/haproxy/haproxy.cfg && \
  haproxy -c -f /etc/haproxy/haproxy.cfg && systemctl reload haproxy

Dürüst sınır

Bu sayfadaki her denetim paket vardıktan sonra çalışıyor. HAProxy bir bağlantıya ne olacağına karar verir, ve iyi karar verir. Ancak kendisini besleyen hattı dolduran bir sel hiçbir karar noktasına ulaşmaz. Sunucu ve vekil ayarı tabanı yükseltir; tavan üst katmandadır. Bu sav temel sayfada uzun uzun, her denetim için ayrı ayrı ise güvenlik duvarı sınırı sayfasında işleniyor.

Sık sorulan sorular

Stick table nedir, DDoS açısından niçin önemli?
İsteğe ait bir şey üzerine, genellikle kaynak adres üzerine anahtarlanan, HAProxy'nin trafik aktıkça güncellediği ve karşısında karar verebildiği bellek içi bir kayıt. "Son on saniyedeki bağlantı oranını kaynak başına izle ve şunun üstündekini reddet" demenizi dış bir sisteme ihtiyaç duymadan sağlayan şey odur, ve HAProxy DDoS yapılandırmalarının çoğunun çekirdeğidir.
Yavaş HTTP saldırılarına karşı hangi timeout gerçekten önemli?
Belirleyici olan `timeout http-request`, çünkü bir istemcinin tam istek başlığını göndermek için ne kadar süre alabileceğini sınırlar. Slowloris sınıfı bir saldırının kötüye kullandığı şey tam olarak budur. `timeout client` ve `timeout client-fin` boşta ve yarı kapalı bağlantıları sınırlar. `timeout http-request` değeri hiç konmamış bir varsayılan yapılandırma, en yaygın tek boşluktur.
maxconn frontend'de mi backend'de mi konmalı?
İkisinde de, farklı sebeplerle. Frontend `maxconn` HAProxy'nin kendisinin ne kabul edeceğini sınırlar ve kendi belleğini korur. Backend ve sunucu başına `maxconn` ise kaynağa ne ulaştığını sınırlar, ve aradaki kuyruk bir sıçramayı kaynak arızası yerine gecikmeye çeviren şeydir. Yalnız frontend'i koymak problemi ileri taşır.
HAProxy hacimsel saldırılara karşı koruyor mu?
Korumuyor. Her paket yine hatta varır ve yine işlenir. HAProxy vardıktan sonra ne olacağına karar verir, ki bu bağlantı ve uygulama katmanı saldırıları için çok şey, doyma için hiçbir şey demektir.

Yayım: Ağustos 2026 · Son gözden geçirme: Ağustos 2026

Gözden geçirme, yukarıdaki kaynakların o tarihte yeniden okunduğu anlamına gelir; metin ancak esaslı bir değişiklik olduğunda yenilenir.

Bu rehber, üreticiler yeni modeller ve fiyatlandırma açıkladıkça güncellenir. Üreticileri nasıl karşılaştırıyoruz