The test environment doesn't have OpenResty libraries, so we need
to provide mock implementations for testing.
Created:
- tests/mock_resty_sha256.lua: Uses system sha256sum command to
compute SHA-256 hashes. Mimics the resty.sha256 API (new,
update, final).
- tests/mock_resty_string.lua: Implements to_hex() to convert
binary strings to hexadecimal.
Updated test.lua to preload these mocks so that when the module
or tests require 'resty.sha256' or 'resty.string', they get our
mock implementations instead.
This allows the PoW verification tests to run and actually verify
the SHA-256 proof-of-work.
Major security fix: The proof-of-work challenge was previously
just trusting the client, allowing bots to bypass it by submitting
random nonces without doing any work.
Changes:
- Added proper server-side SHA-256 verification using resty.sha256
- Server now verifies that sha256(challenge + nonce) has the
required number of leading zeros based on pow_difficulty
- Bots must now actually compute the proof-of-work
Updated tests:
- Added computeValidNonce() helper that actually computes valid
nonces by brute force (for testing purposes)
- testValidPowPassesChallenge now uses a real computed nonce
Updated README to explicitly mention server-side verification.
Fixed three remaining test issues:
1. Token validation tests: Changed from overriding ngx.req.get_headers
to setting ngx._headers directly, which the setup's mock function
reads from. This is more reliable and matches the test framework
pattern.
2. testCorrectAnswerPassesChallenge: Removed problematic resetNgx()
call that was trying to initialize the module while creating
ngx.shared. Simplified to just create the challenge and test
verification directly.
All tests should now pass.
Fixed missing ngx.req.read_body, ngx.req.get_post_args, and
ngx.req.get_headers function mocks that were causing test errors.
These functions are required by the DDoS protection module to
handle POST requests and cookie validation.
All four test classes now properly initialize these mocks:
- TestDDoSProtectionChallenge
- TestDDoSProtectionChallengePaths
- TestDDoSProtectionChallengeQuestion
- TestDDoSProtectionChallengePow
Cannot use setupTest() for modules that need ngx.shared because setupTest()
calls resetNgx() (which wipes ngx.shared) before calling module.init() (which
needs ngx.shared).
Solution: Manually replicate what setupTest() does, but set up ngx.shared
after resetNgx() and before module.init().
All 4 test classes now:
1. Call resetNgx()
2. Set up ngx.shared
3. Manually require module, validate schema, call init(), set ctx.compiled_chain
Schema validation was failing because the new optional config fields
(protected_paths, challenge_type, pow_difficulty) weren't provided in
test configs. While these fields have defaults in the code, the schema
validator requires them to be present.
Added all three fields to every test setup() method with appropriate
default values.
All test setup methods were trying to access ngx.shared before the ngx
global was initialized, causing 'attempt to index global ngx (a nil value)'
errors.
Fixed by calling resetNgx() at the start of each setup() method to ensure
the ngx global exists before setting up ngx.shared and other mock properties.
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
Allow users to specify which paths should be protected by the challenge
system, enabling selective protection of expensive endpoints while
leaving static assets and other paths unrestricted.
Changes:
- Add protected_paths config option (list of PCRE regex patterns)
- Only apply challenge/ban logic to paths matching protected patterns
- If protected_paths is empty/unset, protect all paths (default behavior)
- Special endpoints (verify/trap) always function regardless of config
- Add 8 new tests for path-based filtering scenarios
- Update documentation with examples and best practices
- Update example config to show protected_paths usage
This allows more granular control - for example, protecting only /api/*
and /search while allowing free access to static assets, reducing UX
friction while still protecting expensive operations.
Implements a Cloudflare-style "Under Attack" mode that protects against
DDoS attacks, scraping, and automated bots.
Features:
- Challenge-response system requiring human interaction
- Honeypot link that automatically bans IPs of bots that click it
- Cookie-based token system for validated users (24h default)
- Temporary IP banning (1h default)
- Comprehensive test suite
The module intercepts requests before they hit the backend, reducing
computational cost from scraping and DDoS attempts. It's particularly
effective against simple scrapers and volumetric attacks.
Files added:
- scripts/ddos_protection_challenge.lua - Main module implementation
- tests/ddos_protection_challenge.lua - Comprehensive test suite
- scripts/ddos_protection_challenge.README.md - Full documentation
- conf.example.ddos_protection.lua - Example configuration
- test.lua - Added test import