Layered abuse protection
Layered abuse protection limits authentication and recovery attacks across several dimensions instead of relying only on a counter stored on one user. It complements the existing permanent lock, temporary lock, progressive throttling, and CAPTCHA controls.
Why account lockout is not enough
A per-account lock catches repeated guesses against one known account, but it does not reliably stop:
- password spraying across many usernames;
- attempts against unknown identifiers;
- one network attacking many users;
- one network exhausting a tenant or service;
- attempts distributed across multiple ProAuth nodes;
- high-volume password-reset requests.
Layered mode records bounded, expiring counters in the configured ReaFx state store. Values are keyed with cryptographic digests of canonical identifiers and network addresses; raw identifiers are not placed in state-store keys.
Modes
AbusePolicyMode | Behavior |
|---|---|
Legacy | Default for existing instances. The layered evaluator allows requests and the established permanent lock, temporary lock, throttling, and CAPTCHA settings remain authoritative. |
Layered | Evaluates the distributed dimensions below for password login, passkey login, and password-recovery requests. Legacy account lock and CAPTCHA controls continue to operate. |
Do not set this option directly during an existing-instance upgrade. The hardening activation workflow sets it to Layered after the inventory and all-nodes-current checks pass.
How decisions compose
For each operation, ProAuth evaluates all applicable dimensions and applies the strongest result:
Allow < Delay < Challenge < BlockAllowcontinues normally.Delayapplies an exponential server-side delay, capped byAbuseMaximumDelayMilliseconds.Challengerequires CAPTCHA for password login. Passkey and recovery requests fail safely when an interactive challenge is not available in that operation.Blockrejects the operation and returns aRetry-Aftervalue where applicable.
If several dimensions return the same action, the longest retry interval wins. Sustained compare-and-swap contention fails closed with a short block because ProAuth cannot safely establish the authoritative count.
Complete option reference
All options are scoped to the UserStore IDP instance.
Mode and delay
| Option | Valid values | Default | Guidance |
|---|---|---|---|
AbusePolicyMode | Legacy, Layered | Legacy | Existing instances remain Legacy until explicit hardening activation. |
AbuseMaximumDelayMilliseconds | 100–120000 | 30000 | Caps the exponential delay produced by any Delay action. |
Account dimension
This dimension is available when the submitted identifier resolves to a UserStore user. It is separated by operation, so password login and recovery requests do not share one undifferentiated counter.
| Option | Valid values | Default |
|---|---|---|
AbuseAccountCapacity | 0–1000000; 0 disables | 10 |
AbuseAccountWindowSeconds | 1–86400 | 900 |
AbuseAccountAction | Allow, Delay, Challenge, Block | Delay |
The account counter resets after a successful authentication operation.
Canonical identifier dimension
This dimension also applies to unknown login names, which makes enumeration-safe abuse handling possible.
| Option | Valid values | Default |
|---|---|---|
AbuseIdentifierCapacity | 0–1000000; 0 disables | 25 |
AbuseIdentifierWindowSeconds | 1–86400 | 900 |
AbuseIdentifierAction | Allow, Delay, Challenge, Block | Delay |
The identifier counter resets after successful authentication when the operation has a resolved identifier.
Network and account dimension
| Option | Valid values | Default |
|---|---|---|
AbuseIpAccountCapacity | 0–1000000; 0 disables | 20 |
AbuseIpAccountWindowSeconds | 1–86400 | 900 |
AbuseIpAccountAction | Allow, Delay, Challenge, Block | Challenge |
This counter resets after successful authentication. It helps distinguish an attack against one account from legitimate traffic behind a shared network.
Network and tenant dimension
| Option | Valid values | Default |
|---|---|---|
AbuseIpTenantCapacity | 0–1000000; 0 disables | 300 |
AbuseIpTenantWindowSeconds | 1–86400 | 300 |
AbuseIpTenantAction | Allow, Delay, Challenge, Block | Delay |
This dimension does not reset when one user succeeds because it represents aggregate tenant traffic from that network.
System dimension
| Option | Valid values | Default |
|---|---|---|
AbuseSystemCapacity | 0–1000000; 0 disables | 5000 |
AbuseSystemWindowSeconds | 1–86400 | 300 |
AbuseSystemAction | Allow, Delay, Challenge, Block | Block |
The system dimension is per UserStore IDP instance and operation. It protects the authentication service when an attack is spread across identifiers, tenants, and network addresses.
Disabling dimensions
0 is useful only when an equivalent upstream control is measured and enforced. Do not disable the identifier or system dimension merely because permanent account locking is enabled; they address different attacks.
Recommended configurations
Consumer and internet-facing applications
Use the layered defaults. Keep AbuseIpAccountAction=Challenge, configure a supported CAPTCHA provider, set InformAboutLockAfterSuccessfulLogin=false, and add WAF or reverse-proxy protection for connection-level floods.
Workforce behind shared networks
Start with the defaults, then observe the IP-and-tenant dimension before enforcing a stricter value. Large office NATs, VPN concentrators, and mobile gateways can place many legitimate users behind one address. Prefer account and identifier controls over aggressive network blocking.
Regulated or privileged access
Use Block for the system dimension, alert on every protective-mode activation, and retain explicit permanent lock or administrator block for confirmed compromise. A hard administrative block is lifecycle state; it is not replaced by an expiring abuse counter.
Relationship to legacy controls
Layered mode does not remove these options:
| Legacy option | Purpose |
|---|---|
AttemptsBeforeUserLocked | Permanent account lock after consecutive password failures; 0 disables. |
TemporaryLockEnabled | Enables an automatically expiring account lock. |
TemporaryLockThreshold | Consecutive failures before temporary lock. |
TemporaryLockDurationSeconds | Temporary lock duration. |
ThrottlingEnabled | Enables the established per-account progressive delay. |
ThrottlingBaseDelayMs | Initial legacy delay. |
ThrottlingMaxDelayMs | Legacy delay cap. |
InformAboutLockAfterSuccessfulLogin | Controls whether a correct password reveals the account lock state. |
CaptchaActivationMode | Controls when CAPTCHA is required. |
CaptchaFailureThreshold | Failure threshold for conditional CAPTCHA modes. |
CaptchaProvider, CaptchaSiteKey, CaptchaSecretKey | CAPTCHA integration settings. |
The legacy failed-login counter still drives temporary and permanent account lock. The distributed layered counters protect broader dimensions and are concurrency-safe across serving nodes.
See Brute force protection for legacy lock behavior and UserStore migration and activation for the transition to layered mode.
State-store and operational requirements
- Use a distributed state store for multi-instance deployments. In-memory state is supported only for a single serving instance.
- The state store must provide equivalent compare-and-swap, ETag, and TTL behavior across supported providers.
- Preserve the originating client network address through a trusted proxy configuration. Do not trust arbitrary forwarded headers.
- Monitor decisions by operation, dimension, and action; never put raw identifiers or proof values in metrics.
- Alert on system blocks, sustained CAS contention, sudden identifier-cardinality growth, and recovery-request spikes.
- Capacity planning must include the PBKDF2 cost and the maximum number of delayed requests held concurrently.