Allow users to experiment with different DDoS mitigation strategies by choosing between three challenge types: 1. Button Challenge (default): Simple click-to-verify, best UX 2. Question Challenge: Multiple-choice questions, better bot filtering 3. Proof-of-Work Challenge: SHA-256 computation, strongest protection Features: - Three distinct challenge page generators with unique HTML/CSS/JS - Question pool with 7 simple multiple-choice questions - JavaScript-based PoW using Web Crypto API (SHA-256) - Configurable PoW difficulty (3-6 leading zeros) - Verification logic for each challenge type - Automatic challenge cleanup after verification - 10 new comprehensive tests covering all challenge types Configuration: - challenge_type: 'button' (default), 'question', or 'pow' - pow_difficulty: 3=fast, 4=moderate (default), 5=slow, 6=very slow The PoW challenge creates real computational cost for attackers. With difficulty 4, each request requires ~65,000 hash computations (~1-3s). This makes volumetric attacks expensive while remaining transparent to legitimate users. Files modified: - scripts/ddos_protection_challenge.lua: +346 lines (challenge generators, verification) - tests/ddos_protection_challenge.lua: +198 lines (10 new tests) - scripts/ddos_protection_challenge.README.md: +93 lines (detailed docs) - conf.example.ddos_protection.lua: Updated with challenge_type option - conf.example.ddos_protection_challenge_types.lua: New file with 4 config examples
67 lines
2.8 KiB
Lua
67 lines
2.8 KiB
Lua
-- Example configuration for DDoS Protection Challenge module
|
|
--
|
|
-- IMPORTANT: This module requires nginx shared dictionaries to be configured.
|
|
-- Add these lines to your nginx http block (or openresty config):
|
|
--
|
|
-- lua_shared_dict aproxy_bans 10m;
|
|
-- lua_shared_dict aproxy_tokens 10m;
|
|
--
|
|
-- The shared dictionaries store:
|
|
-- - aproxy_bans: Banned IP addresses with expiry times
|
|
-- - aproxy_tokens: Valid challenge tokens with expiry times
|
|
--
|
|
-- You can adjust the size (10m = 10 megabytes) based on your needs.
|
|
|
|
return {
|
|
version = 1,
|
|
wantedScripts = {
|
|
['ddos_protection_challenge'] = {
|
|
-- How long to ban IPs that trigger the honeypot (in seconds)
|
|
-- Default: 3600 (1 hour)
|
|
ban_duration = 3600,
|
|
|
|
-- How long tokens remain valid after passing the challenge (in seconds)
|
|
-- Default: 86400 (24 hours)
|
|
-- Users won't see the challenge again during this period
|
|
token_duration = 86400,
|
|
|
|
-- Name of the cookie used to store the validation token
|
|
-- Default: 'aproxy_token'
|
|
cookie_name = 'aproxy_token',
|
|
|
|
-- Name of the nginx shared dictionary for storing banned IPs
|
|
-- Must match the lua_shared_dict directive in nginx config
|
|
-- Default: 'aproxy_bans'
|
|
shared_dict_bans = 'aproxy_bans',
|
|
|
|
-- Name of the nginx shared dictionary for storing valid tokens
|
|
-- Must match the lua_shared_dict directive in nginx config
|
|
-- Default: 'aproxy_tokens'
|
|
shared_dict_tokens = 'aproxy_tokens',
|
|
|
|
-- List of path patterns to protect (PCRE regex)
|
|
-- If not specified or empty, ALL paths are protected
|
|
-- Examples:
|
|
-- - {'/api/.*'} - Protect all API endpoints
|
|
-- - {'/search', '/api/v2/search'} - Protect specific endpoints
|
|
-- - {'/api/.*', '/.well-known/webfinger'} - Protect multiple patterns
|
|
-- Leave empty or comment out to protect ALL paths (default behavior)
|
|
protected_paths = {
|
|
'/api/.*', -- All API endpoints
|
|
'/search', -- Search endpoint
|
|
'/.well-known/.*' -- Well-known endpoints
|
|
},
|
|
|
|
-- Alternative: Protect everything (same as leaving protected_paths empty)
|
|
-- protected_paths = {},
|
|
|
|
-- Challenge type: button (default), question, or pow
|
|
-- See conf.example.ddos_protection_challenge_types.lua for detailed examples
|
|
challenge_type = 'button', -- Options: 'button', 'question', 'pow'
|
|
|
|
-- Proof-of-work difficulty (only used if challenge_type = 'pow')
|
|
-- Higher = more protection but slower user experience
|
|
-- pow_difficulty = 4, -- 3=fast, 4=moderate, 5=slow, 6=very slow
|
|
}
|
|
}
|
|
}
|