Edgeweir
Guides

Challenges and CC mitigation

Make visitors pass a challenge before they reach a site: through rules, for the whole site (Under Attack), or automatically, level by level, when a node sees too many requests (tiered CC mitigation). Visitors who pass get a pass and are not challenged again until it expires.

Concepts

TermDefinition
ChallengeA verification page the node returns instead of the origin; passing it returns to the original URL.
LevelStrength of a challenge, from low to high: cookie redirect (1), JavaScript (2), proof of work (3), image captcha (4). A pass of level L satisfies every requirement up to L.
PassSigned cookie issued after a challenge, bound to the site, the level, the client network and the User-Agent.
Under AttackEvery GET/HEAD request without a valid pass is challenged first. It can be turned on per site, or for every site (global Under Attack).
CC mitigationPer-site policy that escalates automatically: a trigger that holds raises the level by one step, and the level falls one step after a cool-down.
JA4TLS client fingerprint, usable in rules and rate limits and recordable in access logs.

Challenge types

TypeLevelHow it is passed
Cookie redirect (cookie302)1302 back to the original URL with the pass; any client that keeps cookies passes
JavaScript (js)2The page script computes one SHA-256 and submits it
Proof of work (pow)3The browser finds, in a background worker, an answer with enough leading zero bits; 16 by default, 8–24
Image captcha (captcha)4Type the 5 characters of the image; the form works without scripts. The page offers a computed alternative: a high-difficulty proof of work (20 bits by default, 8–26, at least the normal difficulty) that also earns a level 4 pass

Challenge pages reference no external address, carry a strict Content-Security-Policy, are shown in Chinese or English per Accept-Language, and play no animation when the system asks for reduced motion. They answer with status 403, X-Edgeweir-Challenge set to the challenge type, and Cache-Control: no-store, private.

RequestWhen a challenge is needed and there is no valid pass
GET, HEADThe challenge page; HEAD gets the headers only
Other methods (POST, PUT…)403 with X-Edgeweir-Challenge: required, no challenge page
The node has no pass keys yet503 with X-Edgeweir-Error: challenge-unavailable

Reserved paths

Nodes handle paths under /.edgeweir/ themselves once the site is known and never forward them to the origin:

PathPurpose
POST /.edgeweir/challenge/verifySubmits an answer; on success 303 back to the URL of the challenge (same-site paths only)
GET /.edgeweir/challenge/worker.jsBackground script of the proof of work
Anything else404, X-Edgeweir-Error: not-found

Origins cannot serve content under this prefix.

Passes

ItemBehavior
Cookie__ew_pass, Path=/; HttpOnly; SameSite=Lax, plus Secure over HTTPS
BindingSite, level passed, client network (IPv4 /24, IPv6 /64), hash of the User-Agent; another network or browser is challenged again
Lifetime30 minutes by default; per site 5 minutes to 24 hours (300–86400 seconds)
Cluster-wideSigning keys are per cluster, so every node of the cluster accepts the pass; forged or altered passes are refused
Key rotationThe console rotates the keys once a day; passes issued before a rotation stay valid until they expire
ReplayEach challenge can be redeemed once; challenge parameters expire after 5 minutes

Turn on Under Attack

  1. Open Sites → (site) → Security.

  2. Pick the Challenge type (JavaScript by default).

  3. Turn on the Under Attack switch and confirm. Nodes apply it once the configuration is published.

  4. Verify:

    curl -sI -H 'Host: www.example.com' http://<node IP>/

    The answer is 403 with X-Edgeweir-Challenge: js. In a browser, the site opens normally after the challenge.

To turn it off, click the switch again and confirm.

For every site: in Protection settings → Protection, pick the Challenge type, turn on Global Under Attack, and confirm; every cluster gets a new configuration. The Security tab of each site then shows "Global Under Attack is on for every site". See Protection.

Without leaving the page: press ⌘K / Ctrl+K, type a site's name or domain, pick Under Attack: (site) and confirm; the switch turns the other way. Global Under Attack turns the global switch the same way.

These requests are never challenged by Under Attack or CC mitigation:

RequestNote
ACME HTTP-01 validationHandled before the site is resolved
Addresses on an Allow IP listApplies to every site, see IP lists
Requests that match an allow ruleA challenge rule that matched before the allow still applies

The level required is the highest of: global Under Attack, the site's Under Attack, matching challenge rules, the site's current CC level, and the path's CC level. Rules of the configuration phase can turn the site's Under Attack on or off, turn CC mitigation off, or set CC highest level per request; global Under Attack is unaffected, see Override settings.

Challenge settings

Security → Challenges: Preset picks Loose, Standard (the default), or Strict and fills in the first three fields below; pick Custom to set each one. Saved values that match no preset show as Custom.

FieldValuesDefault
Pass lifetime (seconds)300–864001800
Proof-of-work difficulty8–2416
High proof-of-work difficulty8–26, at least the proof-of-work difficulty20
Record JA4 in access logsOn / offOff
PresetPass lifetimeProof-of-work difficultyHigh proof-of-work difficulty
Loose36001418
Standard18001620
Strict9001822

Each extra step of difficulty doubles the work a browser does on average.

Challenge rules

In Rules → Custom WAF, pick the action Challenge and a challenge type, for example to challenge the login page only, or given JA4 fingerprints:

http.request.uri.path eq "/login"
tls.ja4 in {"t13d1516h2_8daaf6152771_02713d6af862"}

A request with a pass of a sufficient level continues with the following rules; otherwise it is challenged as above. Fields and syntax: Rules.

CC mitigation

CC mitigation is set per site and off by default. Security → CC mitigation:

  1. Turn on Enabled.
  2. Keep Follow the default template to use the default thresholds (Protection settings → CC template), or turn it off and pick Loose, Standard, or Strict under Preset, or Custom to set each threshold. Saved thresholds that match no preset show as Custom.
  3. Click Save.
FieldValuesTemplate default
Highest levelCookie redirect / JavaScript / Proof of work / Image captchaImage captcha
High proof of work instead of the captchaOn / offOff
Window (seconds)5–6010
Site QPS0–10000001000
Per-URL QPS0–1000000200
Per-IP QPS0–100000050
IP ban duration (seconds)60–86400600
Origin error rate (%)0–10050
Minimum origin requests0–1000000100
Escalate after (seconds)1–360010
Step down after (seconds)1–8640060

A threshold of 0 turns its trigger off. Sites that follow the template use its new thresholds as soon as it changes.

PresetHighest levelSite / per-URL / per-IP QPSIP ban durationOrigin error rate / minimum origin requestsEscalate after / step down after
LooseProof of work3000 / 600 / 15030070 / 20020 / 60
Standard (template default)Image captcha1000 / 200 / 5060050 / 10010 / 60
StrictImage captcha300 / 60 / 20360030 / 505 / 300

Every preset uses a 10-second window and keeps the captcha level as a captcha.

TriggerBehavior
Site QPSThe site's request rate is over the threshold: the whole site escalates
Per-URL QPSA path's rate is over the threshold: only that path escalates (exact path match); other paths are unaffected
Per-IP QPSA client's rate is over the threshold (IPv4 per address, IPv6 per /64): it is banned automatically for the ban duration, see Automatic bans
Origin error rateWith at least the minimum number of origin requests in the window, the share of errors (5xx and failed connections) is over the threshold: the whole site escalates
EscalationA trigger that holds for Escalate after raises the level by one step, up to Highest level
Stepping downWithout triggers (below 80% of the thresholds) for Step down after, the level falls by one step

Each node counts and escalates on its own, so thresholds apply per node. When an attack spreads over several nodes, a single node may stay under the thresholds; scale the thresholds by the number of nodes.

ItemBehavior
CountingSliding windows (two adjacent windows weighted); paths are tracked with a bounded top-K of 64 candidates per site, at most 64 escalated paths
Captcha as the highest levelWith High proof of work instead of the captcha, that level uses the high-difficulty proof of work
ReportingLevel changes, escalated paths and automatic bans are reported every 5 seconds, with the heaviest addresses and paths of the moment (up to 10 each, approximate)

State and events

The top of the Security tab shows in one line what is in effect: Under Attack (the site's or global), CC (the preset, Custom, Template or Off), the CRS mode and preset, the challenge preset and, when an online node is above normal, Nodes: (highest level). Click a part to jump to its card.

Lower on the Security tab:

SectionContent
Current level per nodeThe site's level, online state and escalated paths on every active node of the cluster (refreshed every 15 seconds)
Top addresses and pathsHeaviest addresses and paths in the events of the last hour, 24 hours or 7 days (approximate); ⋯ at the end of a row offers Ban IP (the dialog has the site and address filled in) or Purge URL (the path expands to each of the site's domains that is not a wildcard; submitted after a confirmation)
EventsTimeline of level changes, escalated paths and automatic bans: node and trigger (observed / threshold), filterable by type; on an automatic ban, ⋯ offers Ban on all sites (the ban dialog with the global scope) or Unban (lifts the site's bans of exactly that address; a range that covers it stays)

Events are kept for 30 days by default, adjustable to 7–365 days with Security event retention (days) in Protection settings → Protection. A site leaving the normal level raises the CC mitigation raised alert (cc_mitigation), at most once per site in 15 minutes (a raise held back fires once they are over if the site has not recovered), see Alerts.

JA4

JA4 is a TLS client fingerprint (format a_b_c, e.g. t13d1516h2_8daaf6152771_02713d6af862) computed during the TLS handshake and shared by the requests of a connection.

PartContent
aProtocol (t for TCP, q for HTTP/3), TLS version, SNI present (d / i), number of cipher suites, number of extensions, first and last character of the first ALPN value
bFirst 12 hex characters of the SHA-256 of the sorted cipher suites
cFirst 12 hex characters of the SHA-256 of the sorted extensions and the signature algorithms
UseNote
Rule fieldtls.ja4 (string, empty over plain HTTP) in custom WAF, challenge and rate limit rules
Rate limit keyA rate limit rule can count by tls.ja4, so one fingerprint shares a counter
Access logsWith Record JA4 in access logs, sampled logs carry a JA4 column, see Access logs

The TLS version is the highest version of the client's supported_versions extension; clients that do not send it get the version negotiated in the handshake. For such older clients, the version of the fingerprint is an approximation.

Only JA4 (the TLS client fingerprint) is implemented; JA4S, JA4H and the other methods are not.

Permissions

Changes need a console session or a read-write AccessKey; read-only AccessKeys can only read; service accounts cannot call these procedures (SERVICE_ACCOUNT_FORBIDDEN). Every change is audited: site.protection_update, system.protection_update, system.cc_template_update.

Node capabilities

FeatureCapability
Under Attack, CC mitigation, challenge ruleschallenge-v1
tls.ja4 field, JA4 rate limit key, JA4 loggingja4-v1

When an active node of the cluster lacks a capability, the change is still saved and published; nodes without the capability keep their previous configuration and show Upgrade required in Clusters & nodes, see Node upgrades. Service accounts and background jobs that publish such a configuration get 409 NODE_CAPABILITY_REQUIRED ("Some nodes don't support … yet: {nodes}") and the settings stay as they were. Clusters that use none of these features keep their configuration unchanged.

API

ProcedureEndpoint
protection.getGET /sites/{id}/protection
protection.updatePATCH /sites/{id}/protection
security.stateGET /sites/{id}/security?hours=24
security.eventsGET /sites/{id}/security/events
settings.protection, settings.setProtectionGET, PUT /settings/protection (global Under Attack, event retention)
settings.ccTemplate, settings.setCcTemplateGET, PUT /settings/cc-template

Fields and examples: API and endpoints.

Troubleshooting

SymptomCauseFix
"The high proof-of-work difficulty must be at least N"The high difficulty is below the proof-of-work difficultyRaise the high difficulty or lower the normal one
A node shows Upgrade requiredThe node is too old and lacks challenge-v1 or ja4-v1Upgrade the node
"Some nodes don't support Challenges yet: {nodes}"A service account or background job published a configuration that needs a capability the cluster's nodes lackUpgrade the node
503, X-Edgeweir-Error: challenge-unavailableThe node has not fetched the pass keys yetCheck the node's connection to the console
Forms or API calls get 403 with X-Edgeweir-Challenge: requiredNon-GET/HEAD requests without a valid passPass the challenge in a browser first; let machine-to-machine endpoints through with an allow rule
Challenged again after passingThe pass expired; the client changed network or User-Agent; the required level is above the pass levelLengthen the lifetime; check whether a proxy's exit address keeps changing
CC mitigation does not escalateTraffic spreads over several nodes and no single node reaches the thresholdsLower the thresholds by the number of nodes
Edit on GitHub

On this page