DDoS Attack Mitigation: Practical Response Guide

Identify DDoS attack types, take immediate mitigation steps, implement rate limiting, use CDN protection, and apply BGP blackholing and scrubbing center techniques.

Identifying Attack Types

Before you can mitigate a DDoS attack, you must identify what kind of attack you are facing. Different attacks require fundamentally different responses.

Volumetric attacks overwhelm your bandwidth capacity:

Attack Layer Amplification Peak Sizes
UDP flood L3/L4 1x 100+ Gbps
DNS amplification L3/L4 50-60x 600+ Gbps
NTP amplification L3/L4 556x 400+ Gbps
SSDP amplification L3/L4 30x 100+ Gbps
Memcached (CVE-2018-1000115) L3/L4 51,000x 1.7 Tbps (Akamai 2018 record)

Protocol attacks exhaust server state:

Attack Layer Target
SYN flood L4 TCP connection table
ACK flood L4 Firewall state table
Fragmented packet flood L3/L4 IP reassembly buffers
Ping of death L3 OS kernel (historical)

Application layer attacks exhaust server resources:

Attack Layer Target
HTTP flood L7 Web server CPU/memory
Slowloris L7 HTTP connections (slow headers)
RUDY L7 HTTP connections (slow POST)
DNS query flood L7 DNS resolver CPU
TLS exhaustion L6 SSL handshake CPU

Rapid identification:

# Check network traffic volume (is it volumetric?)
# On the server:
ifstat -i eth0 1 10      # Network throughput per second
sar -n DEV 1 10          # More detailed

# Check connection state (is it protocol-level?)
ss -s                    # Socket statistics summary
# Look for: many SYN_RECV = SYN flood
# Many TIME_WAIT = ACK flood or connection exhaustion

# Check application layer (is it HTTP flood?)
sudo tail -f /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -20
# Look for a single IP or small set of IPs making thousands of requests

Immediate Response Steps

The first 15 minutes of an attack determine whether you survive it or not.

# Step 1: Confirm it is an attack, not organic traffic
# Check traffic volume vs. normal baseline
netstat -i
cat /proc/net/dev   # Raw interface stats

# Step 2: Identify the attack source(s)
sudo tcpdump -i eth0 -n -c 1000 -w /tmp/attack.pcap
tcpdump -r /tmp/attack.pcap -n 'ip' | awk '{print $3}' | sort | uniq -c | sort -rn | head -20

# Step 3: Null route the most abusive IPs immediately
# Linux: black hole a specific IP (traffic accepted but discarded)
sudo ip route add blackhole 192.0.2.100/32

# Null route multiple IPs from a list
while read ip; do
    sudo ip route add blackhole "$ip/32"
done < /tmp/attack_ips.txt

# Step 4: Apply temporary rate limiting to buy time
sudo iptables -I INPUT -p tcp --dport 80 -m connlimit --connlimit-above 50 -j DROP
sudo iptables -I INPUT -p tcp --dport 80 -m limit --limit 1000/second --limit-burst 2000 -j ACCEPT
sudo iptables -I INPUT -p tcp --dport 80 -j DROP

# Step 5: Contact your hosting provider / upstream
# They can apply upstream ACLs or activate scrubbing at their edge
# Have your ASN, IP range, and traffic type ready

SYN flood specific:

# Enable SYN cookies (absorbs SYN floods without state table exhaustion)
sudo sysctl -w net.ipv4.tcp_syncookies=1

# Increase the SYN backlog queue
sudo sysctl -w net.ipv4.tcp_max_syn_backlog=4096

# Reduce SYN-ACK retries (drop half-open connections faster)
sudo sysctl -w net.ipv4.tcp_synack_retries=2

# Make permanent in /etc/sysctl.conf
echo "net.ipv4.tcp_syncookies = 1" >> /etc/sysctl.conf
echo "net.ipv4.tcp_max_syn_backlog = 4096" >> /etc/sysctl.conf

Rate Limiting and Filtering

Rate limiting reduces the impact of application layer attacks without blocking legitimate users.

Nginx rate limiting:

# /etc/nginx/nginx.conf — define rate limit zones
http {
    # Limit requests per IP: 10 requests per second
    limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;

    # Limit concurrent connections per IP
    limit_conn_zone $binary_remote_addr zone=conn_limit:10m;

    server {
        # Apply rate limit: allow bursts of 20 before enforcing limit
        limit_req zone=api burst=20 nodelay;

        # Limit to 20 simultaneous connections per IP
        limit_conn conn_limit 20;

        # Return 429 (Too Many Requests) instead of 503
        limit_req_status 429;
        limit_conn_status 429;
    }
}

iptables rate limiting (L4):

# Limit new TCP connections to 25 per second per IP
sudo iptables -I INPUT -p tcp --dport 80 -m state --state NEW \
  -m recent --set --name HTTP_NEW
sudo iptables -I INPUT -p tcp --dport 80 -m state --state NEW \
  -m recent --update --seconds 1 --hitcount 25 --name HTTP_NEW -j DROP

# Block IPs making more than 100 connections
sudo iptables -I INPUT -p tcp --dport 80 \
  -m connlimit --connlimit-above 100 -j REJECT --reject-with tcp-reset

# Rate limit ICMP flood
sudo iptables -I INPUT -p icmp --icmp-type echo-request \
  -m limit --limit 10/second --limit-burst 20 -j ACCEPT
sudo iptables -I INPUT -p icmp --icmp-type echo-request -j DROP

Geo-blocking (when attack is regionally concentrated):

# Install geoip module
sudo apt install xtables-addons-common libnet-cidr-lite-perl

# Block a country (use ISO 3166-1 alpha-2 code)
sudo iptables -I INPUT -m geoip --src-cc CN -j DROP

CDN-Based Protection

A CDN placed in front of your origin server absorbs volumetric attacks at the edge, before traffic reaches your infrastructure.

Cloudflare (most widely used):

# After proxying through Cloudflare:
# 1. Enable "I'm Under Attack" mode (IUAM) immediately
# Cloudflare Dashboard → Security → Settings → Security Level → "I'm Under Attack"
# This presents a JavaScript challenge to all visitors

# 2. Create firewall rules to block attack patterns
# Cloudflare Dashboard → Security → WAF → Custom Rules
# Example: Block requests with empty User-Agent
# (http.user_agent eq "")

# 3. Rate limiting rules
# Security → Rate Limiting → Create Rule
# Match: URI path = /api/*
# Requests: >100 per 10 seconds
# Action: Block for 1 hour

# 4. Lock down origin to only accept Cloudflare IPs
# This prevents attackers from bypassing Cloudflare by hitting origin directly
# Cloudflare IP ranges: https://www.cloudflare.com/ips/

# iptables rule to only allow Cloudflare
for ip in $(curl -s https://www.cloudflare.com/ips-v4); do
    sudo iptables -I INPUT -p tcp --dport 80 -s "$ip" -j ACCEPT
    sudo iptables -I INPUT -p tcp --dport 443 -s "$ip" -j ACCEPT
done
sudo iptables -A INPUT -p tcp --dport 80 -j DROP
sudo iptables -A INPUT -p tcp --dport 443 -j DROP

AWS Shield Standard and Advanced:

AWS Shield Standard is automatically included with all AWS accounts and protects against L3/L4 volumetric attacks. Shield Advanced adds L7 protection and 24/7 DDoS response team access.

# Enable AWS WAF rate limiting (if on ALB or CloudFront)
aws wafv2 create-rate-based-rule \
  --scope REGIONAL \
  --name RateLimitRule \
  --metric-name RateLimitRule \
  --rate-key IP \
  --rate-limit 2000 \
  --action '{"Block":{}}'

BGP Blackholing

BGP blackholing (RTBH — Remotely Triggered Black Hole) is an upstream filtering technique where you advertise a /32 route tagged with a specific BGP community that causes upstream routers to drop all traffic to that destination IP.

How it works:

  1. You announce a /32 prefix (your attacked IP) to your upstream provider.
  2. You tag it with the provider's blackhole community (e.g., 65535:666 for many providers, or provider-specific).
  3. The upstream router adds a null route for that /32 — traffic is dropped at the upstream, before reaching your bandwidth.
# Cisco IOS: announce a blackhole route with community
router bgp 65001
 network 192.0.2.100 mask 255.255.255.255 route-map BLACKHOLE-TAG

route-map BLACKHOLE-TAG permit 10
 set community 65535:666 additive

# Null route the host locally
ip route 192.0.2.100 255.255.255.255 Null0

# Different providers use different blackhole communities:
# Hurricane Electric: 6939:666
# Telia: 1299:7 (S-RTBH) or 1299:666
# Cogent: 174:666
# Most providers document these in their IRR records or NOC pages

Destination blackholing vs. source blackholing (SRTBH):

  • Destination blackholing — Drops all traffic TO your IP. Stops the attack but also blocks legitimate users. Use as a last resort.
  • Source blackholing (SRTBH) — Drops traffic FROM specific source IPs. Requires knowing the source and your provider supporting it. More surgical.

Scrubbing Centers

Scrubbing centers are specialized facilities that receive your traffic, filter out attack traffic, and forward clean traffic to your server.

Commercial scrubbing services:

Provider Capacity Approach
Cloudflare Magic Transit 100+ Tbps edge BGP advertisement + anycast
Akamai Prolexic 20 Tbps BGP diversion to scrubbing centers
Radware Multiple Tbps On-premise + cloud hybrid
Lumen (CenturyLink) 2+ Tbps Carrier-level scrubbing

How scrubbing works:

  1. During an attack, you re-announce your IP prefix via BGP to point to the scrubbing center.
  2. Attack traffic (volumetric) hits the scrubbing center's massive ingress capacity.
  3. The scrubbing center applies stateful inspection and filters attack packets.
  4. Clean traffic is forwarded to your actual servers via a GRE tunnel or MPLS circuit.
  5. After the attack ends, you revert the BGP announcement to resume normal routing.
# GRE tunnel from scrubbing center to your server (typical setup)
# On your server (the "clean" traffic destination):
sudo ip tunnel add gre1 mode gre remote SCRUBBING_CENTER_IP local YOUR_SERVER_IP ttl 255
sudo ip link set gre1 up
sudo ip addr add YOUR_ATTACKED_IP/32 dev gre1
sudo ip route add SCRUBBING_CENTER_IP via YOUR_GATEWAY

Post-Incident Analysis

After the attack ends, a structured analysis prevents recurrence and improves future response time.

Attack characterization:

# Analyze the pcap captured during the attack
tcpdump -r /tmp/attack.pcap -n | \
  awk '{print $3}' | \
  cut -d. -f1-4 | \
  sort | uniq -c | sort -rn > /tmp/source_ips.txt

# Summarize by /24 (likely botnet source distribution)
cat /tmp/source_ips.txt | \
  awk '{print $2}' | \
  cut -d. -f1-3 | \
  sort | uniq -c | sort -rn | head -20

# Peak traffic volume
# Check your bandwidth graphs in your monitoring system
# Grafana, Netdata, Zabbix, CloudWatch

# Check server logs for application-layer attack signatures
grep "HTTP/1" /var/log/nginx/access.log | \
  awk '{print $1, $7}' | \  # IP and URL
  sort | uniq -c | sort -rn | head -50

Post-incident checklist:

  1. Document attack start/end time, peak volume, attack type.
  2. Record what mitigations were applied and in what order.
  3. Calculate time-to-mitigate and time-to-recovery.
  4. Identify gaps: Were monitoring alerts timely? Was the runbook clear?
  5. Update runbooks with what worked and what did not.
  6. Implement permanent controls based on attack patterns:
  7. Add WAF rules for HTTP patterns seen in attack traffic
  8. Increase scrubbing subscription tier if overwhelmed
  9. Pre-negotiate blackhole communities with upstreams
  10. Configure auto-trigger for future attacks (BGP communities on threshold)

Metrics to track:

Metric Target
Time to detect < 5 minutes
Time to triage < 15 minutes
Time to mitigate L3/L4 < 30 minutes
Time to mitigate L7 < 1 hour
False positive rate on blocks < 1% of legitimate users