Can I look for and block specific content in the request body (JSON / XML / form)?
Short answer
Yes. On an HTTP vService, the HTTP Request Body condition searches for text or Regex in the first Body Size to Parse(Bytes) bytes of the body (default 1024, at most 16384); the condition is bound to the Block action. The search is on raw bytes: JSON and XML are not parsed, and form values are searched in their URL-encoded form. If WAF is enabled, a custom rule in Signature & Rule Library with Form, JSON, XML or Raw selected in the Inspection Scopes field searches the parsed body; Value Pattern in the page types and allowed key fields such as Allowed JSON Keys, on the other hand, count values outside the expected format as violations.
Problem: Unwanted Content Arrives in the Request Body
Bodies that contain privilege escalation fields, forbidden keywords or known attack patterns can be sent to APIs or forms. Requests that carry this content are wanted to be stopped before they reach the Backend Service.
Solution: Four Methods
Method 1 works without WAF; Methods 2 and 3 work with WAF and can be used together; Method 4 is the command-line equivalent of Method 1. No rule is written for known attacks such as SQL injection and XSS: if WAF is on and in Blocking mode, the built-in signatures already scan the body (what is WAF).
| Your situation | Suitable method |
|---|---|
| Searching for text or a pattern in the first 16 KB of the body, without WAF | Method 1: HTTP Request Body + Block |
| I have WAF; searching for a pattern in parsed form, JSON or XML values | Method 2: WAF custom rule (Signature & Rule Library) |
| I have WAF; rejecting anything outside the expected value format or the allowed field names | Method 3: WAF value pattern and allowed keys |
| Setting up Method 1 from the command line | Method 4: WEB-CLI |
Method 1: HTTP Request Body + Block Recommended
- How it works The condition searches for the pattern as raw text in the first Body Size to Parse(Bytes) bytes of the body. On a vService where a body condition is used, requests are buffered up to this amount; if there are multiple body conditions, the largest value is applied to all requests.
- Where it is openedLoad Balancer → Conditions → HTTP Request Body · Load Balancer → Actions → Block
- Requirement None
- vService type HTTP
Step-by-Step Configuration
The condition form is opened with Load Balancer → Conditions → Add (how to add).
Condition Name = govde-rol and Criteria = HTTP Request Body are selected; in the matching list, Regex (Includes for plain text) is selected. The pattern (e.g. "role"\s*:\s*"admin") is written in the Query field, Case Insensitive is checked if needed, and Body Size to Parse(Bytes) = 4096 is entered. This condition has no Is present option. The example pattern catches the {"role":"admin"} and {"role" : "admin"} bodies and does not catch the {"role":"user"} body.
The condition is saved with Add.
The action form is opened with Load Balancer → Actions → Add.
Action Name = govde-engelle and Action Type = Block are selected; Execution Level is left at the default On request, Deny Type at the default Standard and Status Code at the default 403.
govde-rol is selected in the Conditions field. If the search is to be applied only to an API path, a Path condition is added in the same group with and; this way, the bodies of other requests are not scanned.
The action is saved with Add.
On the Load Balancer → Load Balancer vService List screen, the HTTP vService is selected and the edit form is opened with Edit.
govde-engelle is selected in the Details → Actions field. The action does not work unless it is added to the vService.
The form is saved with Save. In a cluster, the change is transferred to the peer device automatically by default; if Manual Sync Mode is on, it is sent with Synchronize.
Verification
Command: curl -s -o /dev/null -w '%{http_code}' -X POST -H 'Content-Type: application/json' -d '{"role":"admin"}' https://www.example.com/api
403The same command is run with -d '{"role":"user"}'.
The normal response of the application (e.g. 200)Method 2: WAF → Custom Rule (Signature & Rule Library)
- How it works The custom rule searches for the pattern in the selected scopes (parsed form fields, JSON and XML values, or the raw body) and, on a match, contributes to the risk score of the request by Score; when the total score reaches the threshold of the protection level on the vService, the request is blocked.
- Where it is opened Configuration Menu → WAF → Signature & Rule Library → Add (all vServices) · the OWASP Rules screen of the vService (only that vService)
- Requirement WAF license; a WAF-enabled HTTP vService; full permission in the WAF area (to write to the library)
- vService type HTTP
Step-by-Step Configuration
If WAF is not on in the vService, the HTTP vService is edited, the WAF box under Details is checked, and the form is saved with Save; details: How do I attach WAF, L7 DDoS & Threat Protection and AGS to a vService?
On the Configuration Menu → WAF → Signature & Rule Library screen, the rule add form is opened with Add.
Name is entered; State is left at the default Enabled and Score at the default Medium, or they are changed. In the Inspection Scopes field, the default Path is removed, Form, JSON, XML or Raw is selected, and Pattern (Regex) is entered. The pattern is written with a subset of PCRE; back references and lookahead/lookbehind are not supported, and the length is at most 4096 characters.
The form is saved with Accept; there is no separate deployment step.
In the Left Monitor Panel → WAF-Protected vServices → vService → WAF Management tab, WAF Mode = Blocking Mode is selected with the Edit button of the mode card and saved. WAF starts in Learning mode; in Learning and Monitor modes, the request is not blocked, only recorded.
Verification
A body containing the pattern is sent; the WAF-Protected vServices → vService → Event Logs screen is checked.
The custom rule is triggered; Attack blocked if the threshold is exceededMethod 3: WAF → Value Pattern and Allowed Keys
- How it works The field checks in the page type work with "violation if it does not match this" logic: if the value does not match the Value Pattern or the key is not in the allowed list, the request is counted as a violation.
- Where it is opened Left Monitor Panel → WAF-Protected vServices → vService → WAF Management → Page Types → rule → JSON / XML / Form tab
- Requirement WAF license; a WAF-enabled HTTP vService
- vService type HTTP
Step-by-Step Configuration
If WAF is not on in the vService, step 1 of Method 2 is applied.
In the WAF Management tab, the rule of the related path is opened from the Page Types list; the JSON, XML or Form tab is selected according to the body type.
In the common rule form or the rule form specific to a single field, the expected value format is defined with JSON Value Pattern, XML Value Pattern or Form Value Pattern, and the allowed key list with Allowed JSON Keys, Allowed XML Keys or Allowed Form Fields. If the body type is not expected at all on this path, options such as Block All JSON Contents are used.
The form is saved with Add.
Step 5 of Method 2 is applied.
Verification
A value that does not match the pattern is sent; the WAF Event Logs screen is checked.
Value pattern violation, Attack blockedMethod 4: WEB-CLI
- How it works The HTTP Request Body condition and the Block action in Method 1 are created with
lb condition/lb action, and the action is added to the vService withlb service. - Where it is opened TR7 WEB-CLI →
lb condition·lb action·lb service - Requirement WEB-CLI access
- vService type HTTP
Step-by-Step Configuration
WEB-CLI runs each line as a separate command; commands are written on a single line. The pattern is written inside single quotes; since the | character splits the command even inside quotes, patterns containing | are entered from the interface (Method 1).
req_body = HTTP Request Body; --bodySize = Body Size to Parse(Bytes) (criteria that match content).
lb condition add criteria req_body query '"role"\s*:\s*"admin"' --content_placement regex --caseInsensitive true --bodySize 4096 --name govde-rolThe --cond field of the action requires the ID of the condition, not its name. lb condition add gives no output when it succeeds; the ID is seen in the id column of the list below (it starts with lbConditions-).
lb condition listIf the status code is not specified, it is 403 (blocking actions).
lb action add type deny name govde-engelle --cond <body-role-id>The rules.0, rules.1… lines show the actions bound to the vService.
lb service show <vService>The new action is written to the first empty index, that is, to the number of existing actions. In the example, since the vService has two actions (rules.0, rules.1), --rules.2 is used; writing to a filled index replaces the action there.
lb service update id <vService> --rules.2 govde-engelleVerification
The curl test in Method 1 is repeated.
403Common Mistakes
- Searching for a body in GET requests. On requests without a body, the HTTP Request Body condition does not match.
- The pattern being located after the Body size to parse limit. The condition sees only the first N bytes; at most 16384 bytes are scanned.
- Not taking JSON whitespace differences into account.
"role":"admin"and"role" : "admin"are different texts;\s*is used in Regex. - Searching for plain text in a URL-encoded form or a compressed body. The condition sees the raw bytes; form values are searched in their encoded form.
- Writing the condition name in the
--condfield. In WEB-CLI,--condexpects the condition ID; if the name is written, the action is bound to a condition that does not exist.
How it is done in the documentation
