136 lines
5.0 KiB
Markdown
136 lines
5.0 KiB
Markdown
# Proof-of-work Verification
|
|
|
|
You can require users to complete a proof-of-work before they can access the
|
|
proxy. This can increase the cost of denial of service attacks and slow down
|
|
automated abuse.
|
|
|
|
When configured, users access the challenge UI and request a token. The server
|
|
sends a challenge to the client, which asks the user's browser to find a
|
|
solution to the challenge that meets a certain constraint (the difficulty
|
|
level). Once the user has found a solution, they can submit it to the server
|
|
and get a user token valid for a period you specify.
|
|
|
|
The proof-of-work challenge uses the argon2id hash function.
|
|
|
|
## Configuration
|
|
|
|
To enable proof-of-work verification, set the following environment variables:
|
|
|
|
```
|
|
GATEKEEPER=user_token
|
|
CAPTCHA_MODE=proof_of_work
|
|
# Validity of the token in hours
|
|
POW_TOKEN_HOURS=24
|
|
# Max number of IPs that can use a user_token issued via proof-of-work
|
|
POW_TOKEN_MAX_IPS=2
|
|
# The difficulty level of the proof-of-work challenge. You can use one of the
|
|
# predefined levels specified below, or you can specify a custom number of
|
|
# expected hash iterations.
|
|
POW_DIFFICULTY_LEVEL=low
|
|
# The time limit for solving the challenge, in minutes
|
|
POW_CHALLENGE_TIMEOUT=30
|
|
```
|
|
|
|
## Difficulty Levels
|
|
|
|
The difficulty level controls how long, on average, it will take for a user to
|
|
solve the proof-of-work challenge. Due to randomness, the actual time can very
|
|
significantly; lucky users may solve the challenge in a fraction of the average
|
|
time, while unlucky users may take much longer.
|
|
|
|
The difficulty level doesn't affect the speed of the hash function itself, only
|
|
the number of hashes that will need to be computed. Therefore, the time required
|
|
to complete the challenge scales linearly with the difficulty level's iteration
|
|
count.
|
|
|
|
You can adjust the difficulty level while the proxy is running from the admin
|
|
interface.
|
|
|
|
Be aware that there is a time limit for solving the challenge, by default set to
|
|
30 minutes. Above 'high' difficulty, you will probably need to increase the time
|
|
limit or it will be very hard for users with slow devices to find a solution
|
|
within the time limit.
|
|
|
|
### Low
|
|
|
|
- Average of 200 iterations required
|
|
- Default setting.
|
|
|
|
### Medium
|
|
|
|
- Average of 900 iterations required
|
|
|
|
### High
|
|
|
|
- Average of 1900 iterations required
|
|
|
|
### Extreme
|
|
|
|
- Average of 4000 iterations required
|
|
- Not recommended unless you are expecting very high levels of abuse
|
|
- May require increasing `POW_CHALLENGE_TIMEOUT`
|
|
|
|
### Custom
|
|
|
|
Setting `POW_DIFFICULTY_LEVEL` to an integer will use that number of iterations
|
|
as the difficulty level.
|
|
|
|
## Other challenge settings
|
|
|
|
- `POW_CHALLENGE_TIMEOUT`: The time limit for solving the challenge, in minutes.
|
|
Default is 30.
|
|
- `POW_TOKEN_HOURS`: The period of time for which a user token issued via proof-
|
|
of-work can be used. Default is 24 hours. Starts when the challenge is solved.
|
|
- `POW_TOKEN_MAX_IPS`: The maximum number of unique IPs that can use a single
|
|
user token issued via proof-of-work. Default is 2.
|
|
- `POW_TOKEN_PURGE_HOURS`: The period of time after which an expired user token
|
|
issued via proof-of-work will be removed from the database. Until it is
|
|
purged, users can refresh expired tokens by completing a half-difficulty
|
|
challenge. Default is 48 hours.
|
|
- `POW_MAX_TOKENS_PER_IP`: The maximum number of active user tokens that can
|
|
be associated with a single IP address. After this limit is reached, the
|
|
oldest token will be forcibly expired when a new token is issued. Set to 0
|
|
to disable this feature. Default is 0.
|
|
|
|
## Custom argon2id parameters
|
|
|
|
You can set custom argon2id parameters for the proof-of-work challenge.
|
|
Generally, you should not need to change these unless you have a specific
|
|
reason to do so.
|
|
|
|
The listed values are the defaults.
|
|
|
|
```
|
|
ARGON2_TIME_COST=8
|
|
ARGON2_MEMORY_KB=65536
|
|
ARGON2_PARALLELISM=1
|
|
ARGON2_HASH_LENGTH=32
|
|
```
|
|
|
|
Increasing parallelism will not do much except increase memory consumption for
|
|
both the client and server, because browser proof-of-work implementations are
|
|
single-threaded. It's better to increase the time cost if you want to increase
|
|
the difficulty.
|
|
|
|
Increasing memory too much may cause memory exhaustion on some mobile devices,
|
|
particularly on iOS due to the way Safari handles WebAssembly memory allocation.
|
|
|
|
## Tested hash rates
|
|
|
|
These were measured with the default argon2id parameters listed above. These
|
|
tests were not at all scientific so take them with a grain of salt.
|
|
|
|
Safari does not like large WASM memory usage, so concurrency is limited to 4 to
|
|
avoid overallocating memory on mobile WebKit browsers. Thermal throttling can
|
|
also significantly reduce hash rates on mobile devices.
|
|
|
|
- Intel Core i9-13900K (Chrome): 33-35 H/s
|
|
- Intel Core i9-13900K (Firefox): 29-32 H/s
|
|
- Intel Core i9-13900K (Chrome, in VM limited to 4 cores): 12.2 - 13.0 H/s
|
|
- iPad Pro (M2) (Safari, 6 workers): 8.0 - 10 H/s
|
|
- Thermal throttles early. 8 cores is normal concurrency, but unstable.
|
|
- iPhone 15 Pro Max (Safari): 4.0 - 4.6 H/s
|
|
- Samsung Galaxy S10e (Chrome): 3.6 - 3.8 H/s
|
|
- This is a 2019 phone almost matching an iPhone five years newer because of
|
|
bad Safari performance.
|