Scoring and modes
See how WAF scores a request per threat family, what Logging and Blocking do with a match, and how exceptions and tuning narrow a rule set.
A web application firewall decides on accumulated evidence rather than on one suspicious pattern. Each attack pattern a request matches adds to a score, and a mode decides what happens once a score reaches its threshold. For where WAF acts in a firewall’s request path, refer to How Firewall works.
The sections cover scoring and sensitivity, modes, request body parsing, exceptions, tuning, and where a match is reported.
Scoring and sensitivity
WAF does not decide on one rule match. Each internal rule that matches a request adds to the score of the threat family that rule belongs to, so one weak signal scores low and several score high. A request is blocked when a family’s score reaches that family’s threshold.
The scores are kept per family, and each one is compared with its own threshold. For example, the query string 1' OR '1'='1 can match internal rules of two families on the same argument, and it then carries one score for SQL injection and another for cross-site scripting.
You never write a threshold as a number. You choose a sensitivity level for each family, and the level fixes the score at which that family blocks. Every family starts at medium, and the scale runs against the word: a higher sensitivity is a lower threshold. At highest a score of 4 blocks, so less evidence refuses more requests, while at lowest a request needs a score of 40. For the five levels and their scores, refer to WAF rule sets.
Sensitivity cuts both ways. Raising it catches attacks that carry less evidence. It also blocks legitimate requests that carry a little of the same evidence, such as an apostrophe in a search term. Lowering it keeps that traffic moving and lets through any attack whose score stays under the threshold. The level is set per family, so you can raise the families your application has no reason to resemble and leave the others.
Modes
The mode belongs to the rule’s Set WAF behavior, not to the rule set. In Logging, a request that reaches a threshold is scored and recorded, and the application receives it as though nothing had matched. In Blocking, that request is refused before it reaches the application. The API takes the mode as logging or blocking, and it is required: a Set WAF behavior without one is refused with 10059.
A blocked request receives 400 and Azion’s default error page, headed Bad Request. Nothing in the response names WAF, the rule, or the score: no header carries them, and the page has no message of its own. The page’s Status Code row reads 0, the status of an origin the request never reached.
Each mode trades one risk for another. Logging records everything that would have been blocked without refusing a legitimate request, and it protects nothing while it runs. Blocking protects, and every false positive becomes a 400 that a user sees, with nothing in it to explain why.
One internal rule is not fully held back by the mode. Rule 13, invalid POST format, blocks some requests even when the rule set runs in Logging. For what each internal rule matches, refer to WAF rule sets.
Other Azion surfaces call the Logging mode learning. Real-Time Events reports it in the wafLearning field, the Data Stream payload carries waf_learning, and azion.config.js sets it as wafMode. The API itself refuses learning as a mode, with 10039.
Request body parsing
WAF reads a request body only in the formats it can take apart. On a POST, it parses the body when Content-Type is application/x-www-form-urlencoded, multipart/form-data, application/json, application/vnd.api+json, or application/csp-report. Parsing lets a rule address one field of the body, and it lets an exception name one field to leave alone.
A body in any other format does not pass unexamined. An unknown or missing Content-Type on a POST is a finding in its own right for the protocol-compliance rules. A rule set can therefore refuse that request with the same 400, even when its body is benign. Internal rule 11 makes that refusal, recorded as wafMatch 0:11:BODY:- with wafAttackFamily $OTHERS. Rule 15 refuses an application/json body that does not parse, such as AAAA, so the client receives a 400 from the firewall rather than a parse error from the application.
Parsing also stops at a size. A body larger than 131,072 bytes, which is 128 KiB, is refused rather than passed through uninspected. For that bound, refer to Firewall limits.
Reading only these formats keeps the inspection precise on what applications post. It costs coverage of the rest. A format WAF does not parse is never searched field by field, and the rule that catches it reads the Content-Type rather than the content.
Exceptions
Some applications legitimately send what an internal rule was written to catch. A search box accepts an apostrophe, a field carries a pipe character, or an API posts a fragment of markup. Each one reaches a threshold with nothing wrong. An exception takes one such case out of scoring without lowering the sensitivity for every other request.
An exception names a part of the request and the internal rule to exempt it from. The part is a condition on a match zone, such as a query string value or a specific header name. The operator, contains or regex, sets how the value is compared, and the rule ID defaults to 0, which means every rule. Azion Console calls an exception an allowed rule and keeps it on the rule set’s Allowed Rules tab.
An exception is a hole in the rule set, as large as you make it. Scoped to one rule, one path, and one named field, it removes one false positive. With the default rule ID and a generic match zone, no family scores anything in that zone, for every request the rule set sees. unwanted_access then stops scoring attempts to reach vulnerable or administrative pages and the use of security scanning bots and tools. identified_attack stops scoring known attacks against applications and servers.
Write the exception for the false positive you have, and remove it once the application stops sending that request. For every field and match zone an exception carries, refer to WAF exceptions.
Tuning
Logging and exceptions work as one loop, and the rule set’s Tuning tab sits in the middle of it. The rule set runs in Logging first, so every request it would block is recorded and none is refused. Tuning lists those records, grouped by the internal rule that matched, over a window of up to the last 3 days. A query needs a domain and narrows by time range, Network List, IP address, and country, and the details of one rule narrow further by path.
Each record is evidence or a false positive. A real attack shows the rule set doing its job. A legitimate request is a false positive. Tuning turns selected records into allowed rules in bulk, so the exception comes from the request that produced it rather than from a guess. When the records stop carrying false positives, the rule moves to Blocking.
The loop costs time twice. The window holds 3 days, so evidence nobody reads in time is gone, and a pattern that appears once a month never shows up in it. Bulk conversion is quick because it narrows nothing. It creates a separate rule for each possible attack on each URI it receives, which is wider than an exception written by hand. For the procedure, refer to Tune a WAF rule set, and for the screen, refer to WAF exceptions.
Where a match is reported
A WAF match leaves nothing in the response, so every question about one is answered from a reporting surface. Real-Time Metrics answers how many, in requests processed and requests blocked over time. Real-Time Events answers which request, one row at a time, with the internal rules that matched and the score each family reached. Data Stream answers where else, by sending those events to a system outside Azion, and the GraphQL API queries the same data.
A blocked request is found from the request rather than from the response. It is a 400 whose upstream status is 0, and its x-azion-request-id header finds its row. That lookup is the price of keeping the decision out of the response. A blocked user can report only a Bad Request page, and the rule and the score are looked up afterward. For the query, refer to Find the WAF score of a blocked request.