1. Overview of HTTP Flood Attacks
An HTTP flood attack is a type of Distributed Denial of Service (DDoS) attack where the attacker overwhelms the target server with a large number of forged HTTP requests (such as GET/POST), exhausting server resources (like connection count, CPU, memory) and preventing legitimate users from accessing the service. Unlike CC attacks, HTTP flood attacks focus more on high-frequency, low-complexity request impacts; the attack traffic typically mimics normal user behavior, making it difficult to filter directly.
2. Protection Strategies Against HTTP Flood Attacks
The core goal of protection is to distinguish between normal traffic and malicious traffic and dynamically intercept the attack source. Common strategies include:
-
Request Rate Limiting which counts the number of requests within a unit time based on IP or session; exceeding the threshold triggers protective actions.
-
Browser Fingerprint Verification which collects client browser characteristics (such as User-Agent, Canvas fingerprint) via JavaScript to verify if it is a real browser.
-
Cookie Challenge which forces the client to perform a cookie verification process; automated attack tools usually cannot handle dynamic cookies correctly.
-
IP Reputation Database Integration which combines real-time IP blacklists or third-party threat intelligence databases to intercept known malicious IPs.
3. LUA Code Implementation for HTTP Flood Protection
Below is an example of a protection scheme based on Cookie Challenge that dynamically generates random cookies to verify client legitimacy.
1. Variable Definition and Initialization
local uri = ngx.var.uri
-- Current request path
local ip_addr = ngx.var.remote_addr
-- Client IP
local cookie_val = ngx.var.cookie_waf_challenge or ""
-- Get client cookie
local threshold = 100
-- Maximum allowed requests within a unit time (e.g., 60 seconds)
local challenge_expire = 300
-- Cookie validity period (seconds)
2. Request Frequency Statistics and Interception Logic
-- Initialize shared memory (record IP request counts)
local http_flood = ngx.shared.http_flood
-- Count IP request frequency
local key = "req_count:" .. ip_addr local current_count, err = http_flood:incr(key, 1) if current_count == nil then http_flood:set(key, 1, 60)
-- First count, set 60 seconds expiration
elseif current_count >= threshold then
-- Trigger protection: generate cookie challenge
local challenge_key = "challenge:" .. ip_addr local challenge_code = http_flood:get(challenge_key) if challenge_code == nil then
-- Generate random cookie value
local random_str = string.gsub(ngx.md5(ngx.now() .. ip_addr), "%d", "") challenge_code = string.sub(random_str, 1, 12) http_flood:set(challenge_key, challenge_code, challenge_expire) end
-- Verify if the client carries the correct
Cookie if cookie_val ~= challenge_code then
-- Return challenge page
return ngx.exit(ngx.HTTP_FORBIDDEN) else
-- Verification passed, reset count
http_flood:delete(key) http_flood:delete(challenge_key) end end
-- Initialize shared memory (record IP request counts)
3. Challenge Page (HTML/JS)
When the request frequency exceeds the limit, return a page containing JavaScript that forces the client to complete cookie verification:
if ngx.status == ngx.HTTP_FORBIDDEN then
ngx.header.content_type = "text/html"
ngx.print([[
<!DOCTYPE html>
<html>
<head>
<title>Security Verification</title>
<script>
// Dynamically set cookie and retry
function setChallengeCookie() {
var xhr = new XMLHttpRequest();
xhr.open('GET', '/waf/challenge', true);
xhr.onload = function() {
if (xhr.status == 200) {
document.cookie = "waf_challenge=" + xhr.responseText + "; path=/";
location.reload(); // Reload the page to carry the cookie
}
};
xhr.send();
}
window.onload = setChallengeCookie;
</script>
</head>
<body>
<h1>Performing security verification, please wait...</h1>
</body>
</html>
]])
gx.exit(ngx.HTTP_OK)
end
4. Challenge Interface (Backend Cookie Generation)
Add an internal interface to generate dynamic cookie values:
location /waf/challenge {
internal;
content_by_lua_block {
local ip_addr = ngx.var.remote_addr
local challenge_key = "challenge:" .. ip_addr
local challenge_code = ngx.shared.http_flood:get(challenge_key)
ngx.print(challenge_code)
}
}
4. Explanation of Protection Logic
-
Request Counting triggers a challenge when each IP exceeds 100 requests within 60 seconds.
-
Dynamic Cookie Generation generates a unique cookie value using MD5 hash and timestamp to ensure unpredictability.
-
Client Verification forces the client to request the challenge interface and set the cookie via JavaScript; automated tools usually cannot execute this process.
-
Automatic Reset clears counts and challenge status after successful verification to avoid misblocking legitimate users.
5. Optimization Directions
-
Refined Statistics combines URI path, User-Agent, and other dimensions to count request frequency, improving accuracy.
-
Enhanced Browser Fingerprinting integrates JavaScript to calculate Canvas fingerprints, intercepting headless browsers.
-
IP Reputation Database connects to threat intelligence APIs to intercept high-risk IPs in real-time.
-
Sliding Window Algorithm uses a more flexible sliding window instead of a fixed time window to avoid missing judgments during threshold breaches.
6. Conclusion
By using dynamic cookie challenges and request frequency limits, this scheme can effectively mitigate HTTP flood attacks, forcing attackers to incur higher costs (requiring JavaScript execution and maintaining cookie state). When deploying in practice, it is necessary to adjust thresholds based on business characteristics and continuously optimize protection strategies through log monitoring.