Konstas.Engineering Notes
Networking · Cybersecurity · Infrastructure
Cybersecurity

A Field Guide to Denial-of-Service Attacks

Articles · July 2026 · Ioannis (John) Konstas

A denial-of-service attack has one goal — make a service unavailable — and a dozen ways to reach it, operating at different layers with wildly different economics. Understanding the taxonomy matters because the defenses don't transfer: what stops a volumetric flood does nothing against a slow application-layer attack, and vice versa. Here's the map, current through the attacks defining 2026.

Three families by what they exhaust

1. Volumetric — exhaust the pipe

Fill the target's bandwidth so legitimate packets can't get through. The math favors the attacker through reflection and amplification: send a small spoofed query to a third-party server that answers a much larger response to the victim.

2. Protocol/state — exhaust the connection table

Consume finite per-connection resources rather than bandwidth.

3. Application-layer (Layer 7) — exhaust the app

Low-bandwidth, high-impact: mimic legitimate requests that are cheap to send and expensive to serve.

The mitigation stack

Attack familyPrimary defense
VolumetricUpstream scrubbing / anycast CDN with capacity far exceeding any botnet; BGP flowspec to drop at the edge
Protocol/stateSYN cookies, connection rate limits, stateful firewall tuning
Application-layerWAF, per-client rate limiting, bot management, request-cost budgeting, up-to-date protocol stacks

The strategic point: absorbing volumetric attacks requires more capacity than the attacker can muster, which for most organizations means a cloud scrubbing provider or anycast CDN — you cannot out-bandwidth a global botnet from a single data center. Layer 7 is the opposite: the fight is about telling human from bot cheaply, per request.

Defensive rate limiting, done right

Naive rate limits punish shared-NAT users and miss distributed attacks. A token-bucket limiter keyed on a real identity signal, with graceful backpressure, is the workhorse — here in Lua for an edge proxy:

-- Token bucket per client key (e.g., API key, or IP+ASN for anonymous)
-- Backed by shared memory / Redis; returns true if the request may proceed.
local function allow(key, rate, burst)
    local now = ngx.now()
    local b = bucket_store:get(key) or { tokens = burst, ts = now }
    -- Refill based on elapsed time, capped at burst
    b.tokens = math.min(burst, b.tokens + (now - b.ts) * rate)
    b.ts = now
    if b.tokens < 1 then
        bucket_store:set(key, b, 60)
        return false                       -- 429 Too Many Requests
    end
    b.tokens = b.tokens - 1
    bucket_store:set(key, b, 60)
    return true
end

-- Prefer a stable identity over raw IP; fall back thoughtfully
local key = ngx.var.http_x_api_key
          or (ngx.var.remote_addr .. ":" .. (ngx.var.asn or "0"))
if not allow(key, 10, 40) then            -- 10 req/s sustained, burst 40
    return ngx.exit(429)
end

Combine it with connection-level timeouts (kill Slowloris), a WAF for signatures, and — critically — a runbook that shifts you behind scrubbing when volumetric traffic exceeds your local capacity. During an attack is the wrong time to read the CDN's onboarding docs.

Before the attack

DoS is a resource-exhaustion problem in disguise. Identify which resource each attack drains — pipe, connection table, or application — and defend that specific one; there is no single shield.

← All articles

Research and direction by Ioannis (John) Konstas; compiled and finalized with AI assistance.

👁· views