@abtnode/router-provider 1.16.38-beta-20250116-083413-dbd33222 → 1.16.38-beta-20250118-033334-2da05ae8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/lib/nginx/includes/security/crs4/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf.example +200 -0
  2. package/lib/nginx/includes/security/crs4/rules/REQUEST-901-INITIALIZATION.conf +470 -0
  3. package/lib/nginx/includes/security/crs4/rules/REQUEST-905-COMMON-EXCEPTIONS.conf +57 -0
  4. package/lib/nginx/includes/security/crs4/rules/REQUEST-911-METHOD-ENFORCEMENT.conf +76 -0
  5. package/lib/nginx/includes/security/crs4/rules/REQUEST-913-SCANNER-DETECTION.conf +86 -0
  6. package/lib/nginx/includes/security/crs4/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf +1915 -0
  7. package/lib/nginx/includes/security/crs4/rules/REQUEST-921-PROTOCOL-ATTACK.conf +558 -0
  8. package/lib/nginx/includes/security/crs4/rules/REQUEST-922-MULTIPART-ATTACK.conf +120 -0
  9. package/lib/nginx/includes/security/crs4/rules/REQUEST-930-APPLICATION-ATTACK-LFI.conf +203 -0
  10. package/lib/nginx/includes/security/crs4/rules/REQUEST-931-APPLICATION-ATTACK-RFI.conf +189 -0
  11. package/lib/nginx/includes/security/crs4/rules/REQUEST-932-APPLICATION-ATTACK-RCE.conf +1875 -0
  12. package/lib/nginx/includes/security/crs4/rules/REQUEST-933-APPLICATION-ATTACK-PHP.conf +774 -0
  13. package/lib/nginx/includes/security/crs4/rules/REQUEST-934-APPLICATION-ATTACK-GENERIC.conf +366 -0
  14. package/lib/nginx/includes/security/crs4/rules/REQUEST-941-APPLICATION-ATTACK-XSS.conf +1071 -0
  15. package/lib/nginx/includes/security/crs4/rules/REQUEST-942-APPLICATION-ATTACK-SQLI.conf +1978 -0
  16. package/lib/nginx/includes/security/crs4/rules/REQUEST-943-APPLICATION-ATTACK-SESSION-FIXATION.conf +132 -0
  17. package/lib/nginx/includes/security/crs4/rules/REQUEST-944-APPLICATION-ATTACK-JAVA.conf +463 -0
  18. package/lib/nginx/includes/security/crs4/rules/REQUEST-949-BLOCKING-EVALUATION.conf +270 -0
  19. package/lib/nginx/includes/security/crs4/rules/RESPONSE-950-DATA-LEAKAGES.conf +156 -0
  20. package/lib/nginx/includes/security/crs4/rules/RESPONSE-951-DATA-LEAKAGES-SQL.conf +417 -0
  21. package/lib/nginx/includes/security/crs4/rules/RESPONSE-952-DATA-LEAKAGES-JAVA.conf +108 -0
  22. package/lib/nginx/includes/security/crs4/rules/RESPONSE-953-DATA-LEAKAGES-PHP.conf +158 -0
  23. package/lib/nginx/includes/security/crs4/rules/RESPONSE-954-DATA-LEAKAGES-IIS.conf +152 -0
  24. package/lib/nginx/includes/security/crs4/rules/RESPONSE-955-WEB-SHELLS.conf +558 -0
  25. package/lib/nginx/includes/security/crs4/rules/RESPONSE-959-BLOCKING-EVALUATION.conf +280 -0
  26. package/lib/nginx/includes/security/crs4/rules/RESPONSE-980-CORRELATION.conf +138 -0
  27. package/lib/nginx/includes/security/crs4/rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf.example +76 -0
  28. package/lib/nginx/includes/security/crs4/rules/iis-errors.data +59 -0
  29. package/lib/nginx/includes/security/crs4/rules/java-classes.data +64 -0
  30. package/lib/nginx/includes/security/crs4/rules/java-code-leakages.data +17 -0
  31. package/lib/nginx/includes/security/crs4/rules/java-errors.data +10 -0
  32. package/lib/nginx/includes/security/crs4/rules/lfi-os-files.data +722 -0
  33. package/lib/nginx/includes/security/crs4/rules/php-config-directives.data +571 -0
  34. package/lib/nginx/includes/security/crs4/rules/php-errors-pl2.data +7 -0
  35. package/lib/nginx/includes/security/crs4/rules/php-errors.data +2147 -0
  36. package/lib/nginx/includes/security/crs4/rules/php-function-names-933150.data +245 -0
  37. package/lib/nginx/includes/security/crs4/rules/php-function-names-933151.data +2201 -0
  38. package/lib/nginx/includes/security/crs4/rules/php-variables.data +30 -0
  39. package/lib/nginx/includes/security/crs4/rules/restricted-files.data +284 -0
  40. package/lib/nginx/includes/security/crs4/rules/restricted-upload.data +177 -0
  41. package/lib/nginx/includes/security/crs4/rules/scanners-user-agents.data +119 -0
  42. package/lib/nginx/includes/security/crs4/rules/sql-errors.data +172 -0
  43. package/lib/nginx/includes/security/crs4/rules/ssrf.data +177 -0
  44. package/lib/nginx/includes/security/crs4/rules/unix-shell.data +670 -0
  45. package/lib/nginx/includes/security/crs4/rules/web-shells-php.data +167 -0
  46. package/lib/nginx/includes/security/crs4/rules/windows-powershell-commands.data +425 -0
  47. package/lib/nginx/includes/security/unicode.mapping +96 -0
  48. package/lib/nginx/index.js +50 -3
  49. package/lib/nginx/templates/security/crs4/crs-setup.conf.js +857 -0
  50. package/lib/nginx/templates/security/modsecurity.conf.js +244 -0
  51. package/package.json +7 -6
@@ -0,0 +1,1915 @@
1
+ # ------------------------------------------------------------------------
2
+ # OWASP CRS ver.4.9.0
3
+ # Copyright (c) 2006-2020 Trustwave and contributors. All rights reserved.
4
+ # Copyright (c) 2021-2024 CRS project. All rights reserved.
5
+ #
6
+ # The OWASP CRS is distributed under
7
+ # Apache Software License (ASL) version 2
8
+ # Please see the enclosed LICENSE file for full details.
9
+ # ------------------------------------------------------------------------
10
+
11
+ #
12
+ # Some protocol violations are common in application layer attacks.
13
+ # Validating HTTP requests eliminates a large number of application layer attacks.
14
+ #
15
+ # The purpose of this rules file is to enforce HTTP RFC requirements that state how
16
+ # the client is supposed to interact with the server.
17
+ # https://www.rfc-editor.org/rfc/rfc9110.html
18
+
19
+
20
+
21
+ #
22
+ # -= Paranoia Level 0 (empty) =- (apply unconditionally)
23
+ #
24
+
25
+
26
+ SecRule TX:DETECTION_PARANOIA_LEVEL "@lt 1" "id:920011,phase:1,pass,nolog,tag:'OWASP_CRS',ver:'OWASP_CRS/4.9.0',skipAfter:END-REQUEST-920-PROTOCOL-ENFORCEMENT"
27
+ SecRule TX:DETECTION_PARANOIA_LEVEL "@lt 1" "id:920012,phase:2,pass,nolog,tag:'OWASP_CRS',ver:'OWASP_CRS/4.9.0',skipAfter:END-REQUEST-920-PROTOCOL-ENFORCEMENT"
28
+ #
29
+ # -= Paranoia Level 1 (default) =- (apply only when tx.detection_paranoia_level is sufficiently high: 1 or higher)
30
+ #
31
+
32
+ #
33
+ # Validate request line against the format specified in the HTTP RFC
34
+ #
35
+ # -=[ Rule Logic ]=-
36
+ #
37
+ # Uses rule negation against the regex for positive security. The regex specifies the proper
38
+ # construction of URI request lines such as:
39
+ #
40
+ # "http" "://" authority path-abempty [ "?" query ]
41
+ #
42
+ # It also outlines proper construction for CONNECT, OPTIONS and GET requests.
43
+ #
44
+ # Regular expression generated from regex-assembly/920100.ra.
45
+ # To update the regular expression run the following shell script
46
+ # (consult https://coreruleset.org/docs/development/regex_assembly/ for details):
47
+ # crs-toolchain regex update 920100
48
+ #
49
+ # -=[ References ]=-
50
+ # https://www.rfc-editor.org/rfc/rfc9110.html#section-4.2.1
51
+ # http://capec.mitre.org/data/definitions/272.html
52
+ #
53
+ SecRule REQUEST_LINE "!@rx (?i)^(?:get /[^#\?]*(?:\?[^\s\x0b#]*)?(?:#[^\s\x0b]*)?|(?:connect (?:(?:[0-9]{1,3}\.){3}[0-9]{1,3}\.?(?::[0-9]+)?|[\--9A-Z_a-z]+:[0-9]+)|options \*|[a-z]{3,10}[\s\x0b]+(?:[0-9A-Z_a-z]{3,7}?://[\--9A-Z_a-z]*(?::[0-9]+)?)?/[^#\?]*(?:\?[^\s\x0b#]*)?(?:#[^\s\x0b]*)?)[\s\x0b]+[\.-9A-Z_a-z]+)$" \
54
+ "id:920100,\
55
+ phase:1,\
56
+ block,\
57
+ t:none,\
58
+ msg:'Invalid HTTP Request Line',\
59
+ logdata:'%{request_line}',\
60
+ tag:'application-multi',\
61
+ tag:'language-multi',\
62
+ tag:'platform-multi',\
63
+ tag:'attack-protocol',\
64
+ tag:'paranoia-level/1',\
65
+ tag:'OWASP_CRS',\
66
+ tag:'capec/1000/210/272',\
67
+ ver:'OWASP_CRS/4.9.0',\
68
+ severity:'WARNING',\
69
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.warning_anomaly_score}'"
70
+
71
+
72
+ #
73
+ # Identify multipart/form-data name evasion attempts
74
+ #
75
+ # There are possible impedance mismatches between how
76
+ # ModSecurity interprets multipart file names and how
77
+ # a destination app server such as PHP might parse the
78
+ # Content-Disposition data:
79
+ #
80
+ # filename-parm := "filename" "=" value
81
+ #
82
+ # -=[ Rule Logic ]=-
83
+ # These rules check for the existence of the ' " ; = meta-characters in
84
+ # either the "name" (FILES) and "filename" (FILES_NAMES) variables.
85
+ # HTML entities may lead to false positives, which is why
86
+ # frequently used ones, such as "ä", are allowed at PL1.
87
+ #
88
+ # -=[ Targets, characters and html entities ]=-
89
+ #
90
+ # 920120: PL1 : FILES_NAMES, FILES
91
+ # Disallow ['\";=\\], except for frequently used HTML entities (see 920120.ra).
92
+ #
93
+ # 920121: PL2 : FILES_NAMES, FILES
94
+ # Disallow ['\";=\\]
95
+ #
96
+ # -=[ References ]=-
97
+ # http://www.ietf.org/rfc/rfc2183.txt
98
+ #
99
+ # This rule used to use negative look-behind.
100
+ # See https://github.com/coreruleset/coreruleset/wiki/Technical-Decisions-and-Best-Practices#avoiding-negative-look-behind-in-regular-expressions
101
+ # for an explanation of why it now uses `!@rx` instead to avoid look-around.
102
+ #
103
+ # Regular expression generated from regex-assembly/920120.ra.
104
+ # To update the regular expression run the following shell script
105
+ # (consult https://coreruleset.org/docs/development/regex_assembly/ for details):
106
+ # crs-toolchain regex update 920120
107
+ #
108
+ SecRule FILES|FILES_NAMES "!@rx (?i)^(?:&(?:(?:[acegilnorsuz]acut|[aeiou]grav|[aino]tild)e|[c-elnr-tz]caron|(?:[cgklnr-t]cedi|[aeiouy]um)l|[aceg-josuwy]circ|[au]ring|a(?:mp|pos)|nbsp|oslash);|[^\"';=\x5c])*$" \
109
+ "id:920120,\
110
+ phase:2,\
111
+ block,\
112
+ t:none,t:urlDecodeUni,\
113
+ msg:'Attempted multipart/form-data bypass',\
114
+ logdata:'%{MATCHED_VAR}',\
115
+ tag:'application-multi',\
116
+ tag:'language-multi',\
117
+ tag:'platform-multi',\
118
+ tag:'attack-protocol',\
119
+ tag:'paranoia-level/1',\
120
+ tag:'OWASP_CRS',\
121
+ tag:'capec/1000/210/272',\
122
+ ver:'OWASP_CRS/4.9.0',\
123
+ severity:'CRITICAL',\
124
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
125
+
126
+
127
+ #
128
+ # Accept only digits in content length
129
+ #
130
+ # -=[ Rule Logic ]=-
131
+ # This rule uses ModSecurity's rule negation against the regex meaning if the Content-Length header
132
+ # is NOT all digits, then it will match.
133
+ #
134
+ # -=[ References ]=-
135
+ # https://www.rfc-editor.org/rfc/rfc9110.html#section-8.6
136
+ #
137
+ SecRule REQUEST_HEADERS:Content-Length "!@rx ^\d+$" \
138
+ "id:920160,\
139
+ phase:1,\
140
+ block,\
141
+ t:none,\
142
+ msg:'Content-Length HTTP header is not numeric',\
143
+ logdata:'%{MATCHED_VAR}',\
144
+ tag:'application-multi',\
145
+ tag:'language-multi',\
146
+ tag:'platform-multi',\
147
+ tag:'attack-protocol',\
148
+ tag:'paranoia-level/1',\
149
+ tag:'OWASP_CRS',\
150
+ tag:'capec/1000/210/272',\
151
+ ver:'OWASP_CRS/4.9.0',\
152
+ severity:'CRITICAL',\
153
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
154
+
155
+
156
+ #
157
+ # Do not accept GET or HEAD requests with bodies
158
+ # In RCF-9110, "A client SHOULD NOT generate content in a HEAD/GET request
159
+ # unless it is made directly to an origin server that has previously indicated"
160
+ #
161
+ # -=[ Rule Logic ]=-
162
+ # The chained rule matches when:
163
+ # 1) If the request method is GET or HEAD
164
+ # AND
165
+ # 2) Header: Content-Length exists and non-zero
166
+ #
167
+ # -=[ References ]=-
168
+ # https://www.rfc-editor.org/rfc/rfc9110.html#section-9.3.1
169
+ # https://www.rfc-editor.org/rfc/rfc9110.html#section-9.3.2
170
+ #
171
+ SecRule REQUEST_METHOD "@rx ^(?:GET|HEAD)$" \
172
+ "id:920170,\
173
+ phase:1,\
174
+ block,\
175
+ t:none,\
176
+ msg:'GET or HEAD Request with Body Content',\
177
+ logdata:'%{MATCHED_VAR}',\
178
+ tag:'application-multi',\
179
+ tag:'language-multi',\
180
+ tag:'platform-multi',\
181
+ tag:'attack-protocol',\
182
+ tag:'paranoia-level/1',\
183
+ tag:'OWASP_CRS',\
184
+ tag:'capec/1000/210/272',\
185
+ ver:'OWASP_CRS/4.9.0',\
186
+ severity:'CRITICAL',\
187
+ chain"
188
+ SecRule REQUEST_HEADERS:Content-Length "!@rx ^0?$" \
189
+ "t:none,\
190
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
191
+
192
+
193
+ #
194
+ # This is a sibling of rule 920170
195
+ #
196
+ SecRule REQUEST_METHOD "@rx ^(?:GET|HEAD)$" \
197
+ "id:920171,\
198
+ phase:1,\
199
+ block,\
200
+ t:none,\
201
+ msg:'GET or HEAD Request with Transfer-Encoding',\
202
+ logdata:'%{MATCHED_VAR}',\
203
+ tag:'application-multi',\
204
+ tag:'language-multi',\
205
+ tag:'platform-multi',\
206
+ tag:'attack-protocol',\
207
+ tag:'paranoia-level/1',\
208
+ tag:'OWASP_CRS',\
209
+ tag:'capec/1000/210/272',\
210
+ ver:'OWASP_CRS/4.9.0',\
211
+ severity:'CRITICAL',\
212
+ chain"
213
+ SecRule &REQUEST_HEADERS:Transfer-Encoding "!@eq 0" \
214
+ "t:none,\
215
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
216
+
217
+
218
+ #
219
+ # Require Content-Length or Transfer-Encoding to be provided with
220
+ # every POST request if the protocol version is not HTTP/2 or HTTP/3.
221
+ #
222
+ # In case of HTTP/2, see the RFC7540 8.1 p52:
223
+ # HTTP/2 does not use the Transfer-Encoding: chunked anymore, because
224
+ # the underlying transport protocol is already using data frames with
225
+ # known length.
226
+ #
227
+ # In case of HTTP/3, see the RFC9114 4.1:
228
+ # Transfer codings (see Section 7 of [HTTP/1.1]) are not defined for
229
+ # HTTP/3; the Transfer-Encoding header field MUST NOT be used.
230
+ #
231
+ # -=[ Rule Logic ]=-
232
+ # This chained rule checks if the protocol is not HTTP/2 or HTTP/3,
233
+ # then checks request method is POST, if so, it checks that a
234
+ # Content-Length or Transfer-Encoding headers are also present.
235
+ #
236
+ SecRule REQUEST_PROTOCOL "!@within HTTP/2 HTTP/2.0 HTTP/3 HTTP/3.0" \
237
+ "id:920180,\
238
+ phase:1,\
239
+ block,\
240
+ t:none,\
241
+ msg:'POST without Content-Length or Transfer-Encoding headers',\
242
+ logdata:'%{MATCHED_VAR}',\
243
+ tag:'application-multi',\
244
+ tag:'language-multi',\
245
+ tag:'platform-multi',\
246
+ tag:'attack-protocol',\
247
+ tag:'paranoia-level/1',\
248
+ tag:'OWASP_CRS',\
249
+ tag:'capec/1000/210/272',\
250
+ ver:'OWASP_CRS/4.9.0',\
251
+ severity:'WARNING',\
252
+ chain"
253
+ SecRule REQUEST_METHOD "@streq POST" \
254
+ "chain"
255
+ SecRule &REQUEST_HEADERS:Content-Length "@eq 0" \
256
+ "chain"
257
+ SecRule &REQUEST_HEADERS:Transfer-Encoding "@eq 0" \
258
+ "setvar:'tx.inbound_anomaly_score_pl1=+%{tx.warning_anomaly_score}'"
259
+
260
+ #
261
+ # As per RFC7230 3.3.2: A sender MUST NOT send a Content-Length
262
+ # header field in any message that contains a Transfer-Encoding header
263
+ # field.
264
+ #
265
+ # Related to 920170, 920171 and 920180.
266
+ #
267
+ SecRule &REQUEST_HEADERS:Transfer-Encoding "!@eq 0" \
268
+ "id:920181,\
269
+ phase:1,\
270
+ block,\
271
+ t:none,\
272
+ msg:'Content-Length and Transfer-Encoding headers present',\
273
+ tag:'application-multi',\
274
+ tag:'language-multi',\
275
+ tag:'platform-multi',\
276
+ tag:'attack-protocol',\
277
+ tag:'paranoia-level/1',\
278
+ tag:'OWASP_CRS',\
279
+ tag:'capec/1000/210/272',\
280
+ ver:'OWASP_CRS/4.9.0',\
281
+ severity:'WARNING',\
282
+ chain"
283
+ SecRule &REQUEST_HEADERS:Content-Length "!@eq 0" \
284
+ "t:none,\
285
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.warning_anomaly_score}'"
286
+
287
+
288
+ #
289
+ # Range Header Check
290
+ #
291
+ # RFC7233 2.1 p6:
292
+ # "A byte-range-spec is invalid if the last-byte-pos value is present
293
+ # and less than the first-byte-pos."
294
+ #
295
+ # -=[ Rule Logic ]=-
296
+ # This rule compares the first and second byte ranges and flags
297
+ # when the first value is greater than the second.
298
+ #
299
+ # -=[ References ]=-
300
+ # https://datatracker.ietf.org/doc/html/rfc7233
301
+ # https://seclists.org/fulldisclosure/2011/Aug/175
302
+ #
303
+ SecRule REQUEST_HEADERS:Range|REQUEST_HEADERS:Request-Range "@rx (\d+)-(\d+)" \
304
+ "id:920190,\
305
+ phase:1,\
306
+ block,\
307
+ capture,\
308
+ t:none,\
309
+ msg:'Range: Invalid Last Byte Value',\
310
+ logdata:'%{MATCHED_VAR}',\
311
+ tag:'application-multi',\
312
+ tag:'language-multi',\
313
+ tag:'platform-multi',\
314
+ tag:'attack-protocol',\
315
+ tag:'paranoia-level/1',\
316
+ tag:'OWASP_CRS',\
317
+ tag:'capec/1000/210/272',\
318
+ ver:'OWASP_CRS/4.9.0',\
319
+ severity:'WARNING',\
320
+ chain"
321
+ SecRule TX:2 "@lt %{tx.1}" \
322
+ "setvar:'tx.inbound_anomaly_score_pl1=+%{tx.warning_anomaly_score}'"
323
+
324
+
325
+ #
326
+ # Broken/Malicious clients often have duplicate or conflicting headers
327
+ # Automated programs and bots often do not obey the HTTP RFC
328
+ #
329
+ # -=[ Rule Logic ]=-
330
+ # This rule inspects the Connection header and looks for duplicates of the
331
+ # keep-alive and close options.
332
+ #
333
+ # -=[ References ]=-
334
+ # https://datatracker.ietf.org/doc/html/rfc7233
335
+ #
336
+ SecRule REQUEST_HEADERS:Connection "@rx \b(?:keep-alive|close),\s?(?:keep-alive|close)\b" \
337
+ "id:920210,\
338
+ phase:1,\
339
+ block,\
340
+ t:none,\
341
+ msg:'Multiple/Conflicting Connection Header Data Found',\
342
+ logdata:'%{MATCHED_VAR}',\
343
+ tag:'application-multi',\
344
+ tag:'language-multi',\
345
+ tag:'platform-multi',\
346
+ tag:'attack-protocol',\
347
+ tag:'paranoia-level/1',\
348
+ tag:'OWASP_CRS',\
349
+ tag:'capec/1000/210/272',\
350
+ ver:'OWASP_CRS/4.9.0',\
351
+ severity:'WARNING',\
352
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.warning_anomaly_score}'"
353
+
354
+ #
355
+ # Check URL encodings
356
+ #
357
+ # -=[ Rule Logic ]=-
358
+ # There are two different chained rules. We need to separate them as we are inspecting two
359
+ # different variables - REQUEST_URI_RAW and REQUEST_BODY. For REQUEST_BODY, we only want to
360
+ # run the @validateUrlEncoding operator if the content-type is application/x-www-form-urlencoding.
361
+ #
362
+ # We exclude the last path segment from validation because it could be a file name, which could
363
+ # easily contain a '%' character that is not part of a URI encoded sequence.
364
+ #
365
+ # -=[ References ]=-
366
+ # http://www.ietf.org/rfc/rfc1738.txt
367
+ #
368
+ # -=[ Example payload ]=-
369
+ # http://localhost/?s=a%20b%20c%'/
370
+ # reason: %'/ is not a valid url encoding
371
+ #
372
+ # Regular expression generated from regex-assembly/920220-chain1.ra.
373
+ # To update the regular expression run the following shell script
374
+ # (consult https://coreruleset.org/docs/development/regex_assembly/ for details):
375
+ # crs-toolchain regex update 920220-chain1
376
+ #
377
+ SecRule REQUEST_URI_RAW "@rx \x25" \
378
+ "id:920220,\
379
+ phase:1,\
380
+ block,\
381
+ t:none,t:urlDecodeUni,\
382
+ msg:'URL Encoding Abuse Attack Attempt',\
383
+ logdata:'%{REQUEST_URI_RAW}',\
384
+ tag:'application-multi',\
385
+ tag:'language-multi',\
386
+ tag:'platform-multi',\
387
+ tag:'attack-protocol',\
388
+ tag:'paranoia-level/1',\
389
+ tag:'OWASP_CRS',\
390
+ tag:'capec/1000/255/153/267/72',\
391
+ ver:'OWASP_CRS/4.9.0',\
392
+ severity:'CRITICAL',\
393
+ chain"
394
+ SecRule REQUEST_URI_RAW "@rx ^(.*)/(?:[^\?]+)?(\?.*)?$" \
395
+ "capture,\
396
+ chain"
397
+ SecRule TX:1|TX:2 "@validateUrlEncoding" \
398
+ "t:none,t:urlDecodeUni,\
399
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
400
+
401
+
402
+ # Validate URI encoding of the last path segment, only if it does not look like a file name.
403
+ # A file name could easily contain a '%' character that is not part of a URI encoded sequence.
404
+ #
405
+ # Regular expression generated from regex-assembly/920221.ra.
406
+ # To update the regular expression run the following shell script
407
+ # (consult https://coreruleset.org/docs/development/regex_assembly/ for details):
408
+ # crs-toolchain regex update 920221
409
+ #
410
+ SecRule REQUEST_BASENAME "!@rx ^.*%.*\.[^\s\x0b\.]+$" \
411
+ "id:920221,\
412
+ phase:1,\
413
+ block,\
414
+ capture,\
415
+ t:none,t:urlDecodeUni,\
416
+ msg:'URL Encoding Abuse Attack Attempt',\
417
+ logdata:'%{REQUEST_BASENAME}',\
418
+ tag:'application-multi',\
419
+ tag:'language-multi',\
420
+ tag:'platform-multi',\
421
+ tag:'attack-protocol',\
422
+ tag:'paranoia-level/1',\
423
+ tag:'OWASP_CRS',\
424
+ tag:'capec/1000/255/153/267/72',\
425
+ ver:'OWASP_CRS/4.9.0',\
426
+ severity:'CRITICAL',\
427
+ chain"
428
+ SecRule TX:0 "@validateUrlEncoding" \
429
+ "t:none,t:urlDecodeUni,\
430
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
431
+
432
+
433
+ #
434
+ # Check UTF encoding
435
+ # We only want to apply this check if UTF-8 encoding is actually used by the site, otherwise
436
+ # it will result in false positives.
437
+ #
438
+ # -=[ Rule Logic ]=-
439
+ # This chained rule first checks to see if the admin has set the TX:CRS_VALIDATE_UTF8_ENCODING
440
+ # variable in the crs-setup.conf file.
441
+ #
442
+ SecRule TX:CRS_VALIDATE_UTF8_ENCODING "@eq 1" \
443
+ "id:920250,\
444
+ phase:2,\
445
+ block,\
446
+ t:none,\
447
+ msg:'UTF8 Encoding Abuse Attack Attempt',\
448
+ logdata:'%{MATCHED_VAR}',\
449
+ tag:'application-multi',\
450
+ tag:'language-multi',\
451
+ tag:'platform-multi',\
452
+ tag:'attack-protocol',\
453
+ tag:'paranoia-level/1',\
454
+ tag:'OWASP_CRS',\
455
+ tag:'capec/1000/255/153/267',\
456
+ ver:'OWASP_CRS/4.9.0',\
457
+ severity:'WARNING',\
458
+ chain"
459
+ SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES "@validateUtf8Encoding" \
460
+ "setvar:'tx.inbound_anomaly_score_pl1=+%{tx.warning_anomaly_score}'"
461
+
462
+
463
+ #
464
+ # Disallow use of full-width unicode as decoding evasions may be possible.
465
+ #
466
+ # -=[ Rule Logic ]=-
467
+ # This rule looks for full-width encoding by looking for %u followed by 2 'f'
468
+ # characters and then 2 hex characters. It is a vulnerability that affected
469
+ # IIS circa 2007.
470
+ # The rule will trigger on %uXXXX formatted chars that are full or half
471
+ # width, as explained above. This %uXXXX format is passed as a raw parameter
472
+ # and is (seemingly only) accepted by IIS (5.0, 6.0, 7.0, and 8.0). Other
473
+ # webservers will only process unicode chars presented as hex UTF-8 bytes.
474
+ #
475
+ # -=[ References ]=-
476
+ # http://www.kb.cert.org/vuls/id/739224
477
+ # https://www.checkpoint.com/defense/advisories/public/2007/cpai-2007-201.html
478
+ # https://github.com/SpiderLabs/owasp-modsecurity-crs/issues/719
479
+ #
480
+ # Regular expression generated from regex-assembly/920260.ra.
481
+ # To update the regular expression run the following shell script
482
+ # (consult https://coreruleset.org/docs/development/regex_assembly/ for details):
483
+ # crs-toolchain regex update 920260
484
+ #
485
+ SecRule REQUEST_URI|REQUEST_BODY "@rx (?i)%uff[0-9a-f]{2}" \
486
+ "id:920260,\
487
+ phase:2,\
488
+ block,\
489
+ t:none,\
490
+ msg:'Unicode Full/Half Width Abuse Attack Attempt',\
491
+ logdata:'%{MATCHED_VAR_NAME}=%{MATCHED_VAR}',\
492
+ tag:'application-multi',\
493
+ tag:'language-multi',\
494
+ tag:'platform-iis',\
495
+ tag:'platform-windows',\
496
+ tag:'attack-protocol',\
497
+ tag:'paranoia-level/1',\
498
+ tag:'OWASP_CRS',\
499
+ tag:'capec/1000/255/153/267/72',\
500
+ ver:'OWASP_CRS/4.9.0',\
501
+ severity:'WARNING',\
502
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.warning_anomaly_score}'"
503
+
504
+
505
+ #
506
+ # Restrict type of characters sent
507
+ #
508
+ # This is a rule with multiple stricter siblings that grows more
509
+ # restrictive in higher paranoia levels.
510
+ #
511
+ # -=[ Rule Logic ]=-
512
+ # This rule uses the @validateByteRange operator to restrict the request
513
+ # payloads.
514
+ #
515
+ # -=[ Targets and ASCII Ranges ]=-
516
+ #
517
+ # 920270: PL1 : REQUEST_URI, REQUEST_HEADERS, ARGS and ARGS_NAMES
518
+ # ASCII 1-255 : Full ASCII range without null character
519
+ #
520
+ # 920271: PL2 : REQUEST_URI, REQUEST_HEADERS, ARGS and ARGS_NAMES
521
+ # ASCII 9,10,13,32-126,128-255 : Full visible ASCII range, tab, newline
522
+ #
523
+ # 920272: PL3 : REQUEST_URI, REQUEST_HEADERS, ARGS, ARGS_NAMES and REQUEST_BODY
524
+ # ASCII 32-36,38-126 : Visible lower ASCII range without percent symbol
525
+ #
526
+ # 920273: PL4 : ARGS, ARGS_NAMES and REQUEST_BODY
527
+ # ASCII 38,44-46,48-58,61,65-90,95,97-122
528
+ # A-Z a-z 0-9 = - _ . , : &
529
+ #
530
+ # 920274: PL4 : REQUEST_HEADERS without User-Agent, Referer, Cookie
531
+ # and Structured Header booleans
532
+ # ASCII 32,34,38,42-59,61,65-90,95,97-122
533
+ # A-Z a-z 0-9 = - _ . , : & " * + / SPACE
534
+ #
535
+ # REQUEST_URI and REQUEST_HEADERS User-Agent, Referer and Cookie are very hard
536
+ # to restrict beyond the limits in 920272. Structured Header booleans are
537
+ # validated separately in 920275.
538
+ #
539
+ # 920274 generally has few positives. However, it would detect rare attacks
540
+ # on Accept request headers and friends.
541
+
542
+ SecRule REQUEST_URI|REQUEST_HEADERS|ARGS|ARGS_NAMES "@validateByteRange 1-255" \
543
+ "id:920270,\
544
+ phase:2,\
545
+ block,\
546
+ t:none,t:urlDecodeUni,\
547
+ msg:'Invalid character in request (null character)',\
548
+ logdata:'%{MATCHED_VAR_NAME}=%{MATCHED_VAR}',\
549
+ tag:'application-multi',\
550
+ tag:'language-multi',\
551
+ tag:'platform-multi',\
552
+ tag:'attack-protocol',\
553
+ tag:'paranoia-level/1',\
554
+ tag:'OWASP_CRS',\
555
+ tag:'capec/1000/210/272',\
556
+ ver:'OWASP_CRS/4.9.0',\
557
+ severity:'CRITICAL',\
558
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
559
+
560
+
561
+ #
562
+ # Do not accept requests without common headers.
563
+ # All normal web browsers include Host, User-Agent and Accept headers.
564
+ # Implies either an attacker or a legitimate automation client.
565
+ #
566
+
567
+ #
568
+ # Missing/Empty Host Header
569
+ #
570
+ # -=[ Rule Logic ]=-
571
+ # These rules will first check to see if a Host header is present.
572
+ # The second check is to see if a Host header exists but is empty.
573
+ #
574
+ SecRule &REQUEST_HEADERS:Host "@eq 0" \
575
+ "id:920280,\
576
+ phase:1,\
577
+ pass,\
578
+ t:none,\
579
+ msg:'Request Missing a Host Header',\
580
+ tag:'application-multi',\
581
+ tag:'language-multi',\
582
+ tag:'platform-multi',\
583
+ tag:'attack-protocol',\
584
+ tag:'paranoia-level/1',\
585
+ tag:'OWASP_CRS',\
586
+ tag:'capec/1000/210/272',\
587
+ tag:'PCI/6.5.10',\
588
+ ver:'OWASP_CRS/4.9.0',\
589
+ severity:'WARNING',\
590
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.warning_anomaly_score}',\
591
+ skipAfter:END-HOST-CHECK"
592
+
593
+
594
+ SecRule REQUEST_HEADERS:Host "@rx ^$" \
595
+ "id:920290,\
596
+ phase:1,\
597
+ block,\
598
+ t:none,\
599
+ msg:'Empty Host Header',\
600
+ tag:'application-multi',\
601
+ tag:'language-multi',\
602
+ tag:'platform-multi',\
603
+ tag:'attack-protocol',\
604
+ tag:'paranoia-level/1',\
605
+ tag:'OWASP_CRS',\
606
+ tag:'capec/1000/210/272',\
607
+ ver:'OWASP_CRS/4.9.0',\
608
+ severity:'CRITICAL',\
609
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
610
+
611
+ SecMarker "END-HOST-CHECK"
612
+
613
+
614
+ #
615
+ # Empty Accept Header
616
+ #
617
+ # -=[ Rule Logic ]=-
618
+ # This rule checks if an Accept header exists, but has an empty value.
619
+ # This is only allowed in combination with the OPTIONS method.
620
+ # Additionally, there are some clients sending empty Accept headers.
621
+ # They are covered in another chained rule checking the User-Agent.
622
+ # This technique demands a separate rule to detect an empty
623
+ # Accept header if there is no user agent. This is checked via
624
+ # the separate rule 920311.
625
+ #
626
+ # Exclude some common broken clients sending empty Accept header:
627
+ # "Business/6.6.1.2 CFNetwork/758.5.3 Darwin/15.6.0" (CRS issue #515)
628
+ # "Entreprise/6.5.0.177 CFNetwork/758.4.3 Darwin/15.5.0" (CRS issue #366)
629
+ #
630
+ # -=[ References ]=-
631
+ # https://github.com/SpiderLabs/owasp-modsecurity-crs/issues/366
632
+ #
633
+
634
+ SecRule REQUEST_HEADERS:Accept "@rx ^$" \
635
+ "id:920310,\
636
+ phase:1,\
637
+ pass,\
638
+ t:none,\
639
+ msg:'Request Has an Empty Accept Header',\
640
+ tag:'application-multi',\
641
+ tag:'language-multi',\
642
+ tag:'platform-multi',\
643
+ tag:'attack-protocol',\
644
+ tag:'paranoia-level/1',\
645
+ tag:'OWASP_CRS',\
646
+ tag:'capec/1000/210/272',\
647
+ ver:'OWASP_CRS/4.9.0',\
648
+ severity:'NOTICE',\
649
+ chain"
650
+ SecRule REQUEST_METHOD "!@rx ^OPTIONS$" \
651
+ "chain"
652
+ SecRule REQUEST_HEADERS:User-Agent "!@pm AppleWebKit Android Business Enterprise Entreprise" \
653
+ "t:none,\
654
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.notice_anomaly_score}'"
655
+
656
+ #
657
+ # This rule is a sibling of rule 920310.
658
+ #
659
+ SecRule REQUEST_HEADERS:Accept "@rx ^$" \
660
+ "id:920311,\
661
+ phase:1,\
662
+ pass,\
663
+ t:none,\
664
+ msg:'Request Has an Empty Accept Header',\
665
+ tag:'application-multi',\
666
+ tag:'language-multi',\
667
+ tag:'platform-multi',\
668
+ tag:'attack-protocol',\
669
+ tag:'paranoia-level/1',\
670
+ tag:'OWASP_CRS',\
671
+ tag:'capec/1000/210/272',\
672
+ ver:'OWASP_CRS/4.9.0',\
673
+ severity:'NOTICE',\
674
+ chain"
675
+ SecRule REQUEST_METHOD "!@rx ^OPTIONS$" \
676
+ "chain"
677
+ SecRule &REQUEST_HEADERS:User-Agent "@eq 0" \
678
+ "t:none,\
679
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.notice_anomaly_score}'"
680
+
681
+
682
+ #
683
+ # Empty User-Agent Header
684
+ #
685
+ # -=[ Rule Logic ]=-
686
+ # This rules will check to see if the User-Agent header is empty.
687
+ #
688
+ # Note that there is a second rule, 920320, which will check for
689
+ # the existence of the User-Agent header.
690
+ #
691
+
692
+ SecRule REQUEST_HEADERS:User-Agent "@rx ^$" \
693
+ "id:920330,\
694
+ phase:1,\
695
+ pass,\
696
+ t:none,\
697
+ msg:'Empty User Agent Header',\
698
+ tag:'application-multi',\
699
+ tag:'language-multi',\
700
+ tag:'platform-multi',\
701
+ tag:'attack-protocol',\
702
+ tag:'paranoia-level/1',\
703
+ tag:'OWASP_CRS',\
704
+ tag:'capec/1000/210/272',\
705
+ ver:'OWASP_CRS/4.9.0',\
706
+ severity:'NOTICE',\
707
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.notice_anomaly_score}'"
708
+
709
+ #
710
+ # Missing Content-Type Header with Request Body
711
+ #
712
+ # -=[ Rule Logic ]=-
713
+ # This rule will first check to see if the value of the Content-Length header is
714
+ # non-equal to 0. The chained rule is then checking the existence of the
715
+ # Content-Type header. The RFCs do not state there must be a
716
+ # Content-Type header. However, a request missing a Content-Header is a
717
+ # strong indication of a non-compliant browser.
718
+ #
719
+ # Also, omitting the CT header allows to bypass the Request Body Processor
720
+ # unless you set the optional tx.enforce_bodyproc_urlencoded variable.
721
+ #
722
+ # Note: in default settings, this behavior only provides a NOTICE and will
723
+ # not cause a request to be blocked. However, in paranoia level 2 or
724
+ # higher, we run sibling 920341, which DOES block these requests.
725
+ #
726
+ # -=[ References ]=-
727
+ # http://httpwg.org/specs/rfc7231.html#header.content-type
728
+
729
+ SecRule REQUEST_HEADERS:Content-Length "!@rx ^0$" \
730
+ "id:920340,\
731
+ phase:1,\
732
+ pass,\
733
+ t:none,\
734
+ msg:'Request Containing Content, but Missing Content-Type header',\
735
+ tag:'application-multi',\
736
+ tag:'language-multi',\
737
+ tag:'platform-multi',\
738
+ tag:'attack-protocol',\
739
+ tag:'paranoia-level/1',\
740
+ tag:'OWASP_CRS',\
741
+ tag:'capec/1000/210/272',\
742
+ ver:'OWASP_CRS/4.9.0',\
743
+ severity:'NOTICE',\
744
+ chain"
745
+ SecRule &REQUEST_HEADERS:Content-Type "@eq 0" \
746
+ "t:none,\
747
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.notice_anomaly_score}'"
748
+
749
+ # Check that the host header is not an IP address
750
+ # This is not an HTTP RFC violation but it is indicative of automated client access.
751
+ # Many web-based worms propagate by scanning IP address blocks.
752
+ #
753
+ # -=[ Rule Logic ]=-
754
+ # This rule triggers if the Host header contains an IPv4 or IPv6 address, optionally
755
+ # extended with a port number. In the case of IPv6 we covering the address with square
756
+ # brackets and the address without square brackets.
757
+ #
758
+ # The regex consists of three main parts and said optional group:
759
+ #
760
+ # * IPv4 address
761
+ # * IPv6 address with square brackets
762
+ # * IPv6 address without square brackets
763
+ # * optional colon and port number
764
+ #
765
+ # Please note that the regex does not test the validity of the IP addresses.
766
+ # It just tries to detect a potential IP address.
767
+ #
768
+ # -=[ References ]=-
769
+ # https://technet.microsoft.com/en-us/magazine/2005.01.hackerbasher.aspx
770
+ #
771
+
772
+ SecRule REQUEST_HEADERS:Host "@rx (?:^([\d.]+|\[[\da-f:]+\]|[\da-f:]+)(:[\d]+)?$)" \
773
+ "id:920350,\
774
+ phase:1,\
775
+ block,\
776
+ t:none,\
777
+ msg:'Host header is a numeric IP address',\
778
+ logdata:'%{MATCHED_VAR}',\
779
+ tag:'application-multi',\
780
+ tag:'language-multi',\
781
+ tag:'platform-multi',\
782
+ tag:'attack-protocol',\
783
+ tag:'paranoia-level/1',\
784
+ tag:'OWASP_CRS',\
785
+ tag:'capec/1000/210/272',\
786
+ tag:'PCI/6.5.10',\
787
+ ver:'OWASP_CRS/4.9.0',\
788
+ severity:'WARNING',\
789
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.warning_anomaly_score}'"
790
+
791
+
792
+ # In most cases, you should expect a certain volume of each a request on your
793
+ # website. For example, a request with 400 arguments, can be suspicious.
794
+ # This file creates limitations on the request.
795
+ #
796
+ # TODO Look at the rules in this file, and define the sizes you'd like to enforce.
797
+ # Note that most of the rules are commented out by default.
798
+ # Uncomment the rules you need
799
+ #
800
+
801
+
802
+ #
803
+ # Maximum number of arguments in request limited
804
+ #
805
+ SecRule &TX:MAX_NUM_ARGS "@eq 1" \
806
+ "id:920380,\
807
+ phase:2,\
808
+ block,\
809
+ t:none,\
810
+ msg:'Too many arguments in request',\
811
+ logdata:'%{MATCHED_VAR_NAME}=%{MATCHED_VAR}',\
812
+ tag:'application-multi',\
813
+ tag:'language-multi',\
814
+ tag:'platform-multi',\
815
+ tag:'attack-protocol',\
816
+ tag:'paranoia-level/1',\
817
+ tag:'OWASP_CRS',\
818
+ tag:'capec/1000/210/272',\
819
+ ver:'OWASP_CRS/4.9.0',\
820
+ severity:'CRITICAL',\
821
+ chain"
822
+ SecRule &ARGS "@gt %{tx.max_num_args}" \
823
+ "t:none,\
824
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
825
+
826
+ ## -- Arguments limits --
827
+ #
828
+ # Limit argument name length
829
+ #
830
+ SecRule &TX:ARG_NAME_LENGTH "@eq 1" \
831
+ "id:920360,\
832
+ phase:2,\
833
+ block,\
834
+ t:none,\
835
+ msg:'Argument name too long',\
836
+ logdata:'%{MATCHED_VAR_NAME}=%{MATCHED_VAR}',\
837
+ tag:'application-multi',\
838
+ tag:'language-multi',\
839
+ tag:'platform-multi',\
840
+ tag:'attack-protocol',\
841
+ tag:'paranoia-level/1',\
842
+ tag:'OWASP_CRS',\
843
+ tag:'capec/1000/210/272',\
844
+ ver:'OWASP_CRS/4.9.0',\
845
+ severity:'CRITICAL',\
846
+ chain"
847
+ SecRule ARGS_NAMES "@gt %{tx.arg_name_length}" \
848
+ "t:none,t:length,\
849
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
850
+
851
+ #
852
+ # Limit argument value length
853
+ #
854
+ # This rule is also triggered by an Apache Struts Remote Code Execution exploit:
855
+ # [ Apache Struts vulnerability CVE-2017-9791 - Exploit tested: https://www.exploit-db.com/exploits/42324 ]
856
+ #
857
+ SecRule &TX:ARG_LENGTH "@eq 1" \
858
+ "id:920370,\
859
+ phase:2,\
860
+ block,\
861
+ t:none,\
862
+ msg:'Argument value too long',\
863
+ logdata:'%{MATCHED_VAR_NAME}=%{MATCHED_VAR}',\
864
+ tag:'application-multi',\
865
+ tag:'language-multi',\
866
+ tag:'platform-multi',\
867
+ tag:'attack-protocol',\
868
+ tag:'paranoia-level/1',\
869
+ tag:'OWASP_CRS',\
870
+ tag:'capec/1000/210/272',\
871
+ ver:'OWASP_CRS/4.9.0',\
872
+ severity:'CRITICAL',\
873
+ chain"
874
+ SecRule ARGS "@gt %{tx.arg_length}" \
875
+ "t:none,t:length,\
876
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
877
+
878
+ #
879
+ # Limit arguments total length
880
+ #
881
+ SecRule &TX:TOTAL_ARG_LENGTH "@eq 1" \
882
+ "id:920390,\
883
+ phase:2,\
884
+ block,\
885
+ t:none,\
886
+ msg:'Total arguments size exceeded',\
887
+ logdata:'%{MATCHED_VAR_NAME}=%{MATCHED_VAR}',\
888
+ tag:'application-multi',\
889
+ tag:'language-multi',\
890
+ tag:'platform-multi',\
891
+ tag:'attack-protocol',\
892
+ tag:'paranoia-level/1',\
893
+ tag:'OWASP_CRS',\
894
+ tag:'capec/1000/210/272',\
895
+ ver:'OWASP_CRS/4.9.0',\
896
+ severity:'CRITICAL',\
897
+ chain"
898
+ SecRule ARGS_COMBINED_SIZE "@gt %{tx.total_arg_length}" \
899
+ "t:none,\
900
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
901
+
902
+
903
+ #
904
+ # -- File upload limits --
905
+ #
906
+ # Individual file size is limited
907
+ SecRule &TX:MAX_FILE_SIZE "@eq 1" \
908
+ "id:920400,\
909
+ phase:1,\
910
+ block,\
911
+ t:none,\
912
+ msg:'Uploaded file size too large',\
913
+ tag:'application-multi',\
914
+ tag:'language-multi',\
915
+ tag:'platform-multi',\
916
+ tag:'attack-protocol',\
917
+ tag:'paranoia-level/1',\
918
+ tag:'OWASP_CRS',\
919
+ tag:'capec/1000/210/272',\
920
+ ver:'OWASP_CRS/4.9.0',\
921
+ severity:'CRITICAL',\
922
+ chain"
923
+ SecRule REQUEST_HEADERS:Content-Type "@rx ^(?i)multipart/form-data" \
924
+ "chain"
925
+ SecRule REQUEST_HEADERS:Content-Length "@gt %{tx.max_file_size}" \
926
+ "t:none,\
927
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
928
+
929
+ #
930
+ # Combined file size is limited
931
+ #
932
+ SecRule &TX:COMBINED_FILE_SIZES "@eq 1" \
933
+ "id:920410,\
934
+ phase:2,\
935
+ block,\
936
+ t:none,\
937
+ msg:'Total uploaded files size too large',\
938
+ logdata:'%{MATCHED_VAR_NAME}=%{MATCHED_VAR}',\
939
+ tag:'application-multi',\
940
+ tag:'language-multi',\
941
+ tag:'platform-multi',\
942
+ tag:'attack-protocol',\
943
+ tag:'paranoia-level/1',\
944
+ tag:'OWASP_CRS',\
945
+ tag:'capec/1000/210/272',\
946
+ ver:'OWASP_CRS/4.9.0',\
947
+ severity:'CRITICAL',\
948
+ chain"
949
+ SecRule FILES_COMBINED_SIZE "@gt %{tx.combined_file_sizes}" \
950
+ "t:none,\
951
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
952
+
953
+
954
+
955
+ #
956
+ # Restrict which content-types we accept.
957
+ #
958
+
959
+ # Restrict Content-Type header to established patterns.
960
+ #
961
+ # This provides generic allow list protection against vulnerabilities like
962
+ # Apache Struts Content-Type arbitrary command execution (CVE-2017-5638).
963
+ #
964
+ # Examples of allowed patterns:
965
+ # - text/plain
966
+ # - text/plain; charset="UTF-8"
967
+ # - multipart/form-data; boundary=----WebKitFormBoundary12345
968
+ # - application/soap+xml; charset=utf-8; action="urn:localhost-hwh#getQuestions"
969
+ # - application/*+json
970
+
971
+ SecRule REQUEST_HEADERS:Content-Type "!@rx ^[\w/.+*-]+(?:\s?;\s*(?:action|boundary|charset|component|start(?:-info)?|type|version)\s?=\s?['\"\w.()+,/:=?<>@#*-]+)*$" \
972
+ "id:920470,\
973
+ phase:1,\
974
+ block,\
975
+ t:none,t:lowercase,\
976
+ msg:'Illegal Content-Type header',\
977
+ logdata:'%{MATCHED_VAR}',\
978
+ tag:'application-multi',\
979
+ tag:'language-multi',\
980
+ tag:'platform-multi',\
981
+ tag:'attack-protocol',\
982
+ tag:'paranoia-level/1',\
983
+ tag:'OWASP_CRS',\
984
+ tag:'capec/1000/255/153',\
985
+ tag:'PCI/12.1',\
986
+ ver:'OWASP_CRS/4.9.0',\
987
+ severity:'CRITICAL',\
988
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
989
+
990
+ # In case Content-Type header can be parsed, check the mime-type against
991
+ # the policy defined in the 'allowed_request_content_type' variable.
992
+ # To change your policy, edit crs-setup.conf and activate rule 900220.
993
+ SecRule REQUEST_HEADERS:Content-Type "@rx ^[^;\s]+" \
994
+ "id:920420,\
995
+ phase:1,\
996
+ block,\
997
+ capture,\
998
+ t:none,\
999
+ msg:'Request content type is not allowed by policy',\
1000
+ logdata:'%{MATCHED_VAR}',\
1001
+ tag:'application-multi',\
1002
+ tag:'language-multi',\
1003
+ tag:'platform-multi',\
1004
+ tag:'attack-protocol',\
1005
+ tag:'paranoia-level/1',\
1006
+ tag:'OWASP_CRS',\
1007
+ tag:'capec/1000/255/153',\
1008
+ tag:'PCI/12.1',\
1009
+ ver:'OWASP_CRS/4.9.0',\
1010
+ severity:'CRITICAL',\
1011
+ setvar:'tx.content_type=|%{tx.0}|',\
1012
+ chain"
1013
+ SecRule TX:content_type "!@within %{tx.allowed_request_content_type}" \
1014
+ "t:lowercase,\
1015
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
1016
+
1017
+
1018
+ #
1019
+ # Restrict charset parameter within the content-type header
1020
+ #
1021
+ SecRule REQUEST_HEADERS:Content-Type "@rx charset\s*=\s*[\"']?([^;\"'\s]+)" \
1022
+ "id:920480,\
1023
+ phase:1,\
1024
+ block,\
1025
+ capture,\
1026
+ t:none,\
1027
+ msg:'Request content type charset is not allowed by policy',\
1028
+ logdata:'%{MATCHED_VAR}',\
1029
+ tag:'application-multi',\
1030
+ tag:'language-multi',\
1031
+ tag:'platform-multi',\
1032
+ tag:'attack-protocol',\
1033
+ tag:'paranoia-level/1',\
1034
+ tag:'OWASP_CRS',\
1035
+ tag:'capec/1000/255/153',\
1036
+ tag:'PCI/12.1',\
1037
+ ver:'OWASP_CRS/4.9.0',\
1038
+ severity:'CRITICAL',\
1039
+ setvar:'tx.content_type_charset=|%{tx.1}|',\
1040
+ chain"
1041
+ SecRule TX:content_type_charset "!@within %{tx.allowed_request_content_type_charset}" \
1042
+ "t:lowercase,\
1043
+ ctl:forceRequestBodyVariable=On,\
1044
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
1045
+
1046
+ #
1047
+ # Restrict charset parameter inside content type header to occur max once.
1048
+ #
1049
+ SecRule REQUEST_HEADERS:Content-Type "@rx charset.*?charset" \
1050
+ "id:920530,\
1051
+ phase:1,\
1052
+ block,\
1053
+ t:none,t:lowercase,\
1054
+ msg:'Multiple charsets detected in content type header',\
1055
+ logdata:'%{MATCHED_VAR}',\
1056
+ tag:'application-multi',\
1057
+ tag:'language-multi',\
1058
+ tag:'platform-multi',\
1059
+ tag:'attack-protocol',\
1060
+ tag:'paranoia-level/1',\
1061
+ tag:'OWASP_CRS',\
1062
+ tag:'capec/1000/255/153',\
1063
+ tag:'PCI/12.1',\
1064
+ ver:'OWASP_CRS/4.9.0',\
1065
+ severity:'CRITICAL',\
1066
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
1067
+
1068
+ #
1069
+ # Restrict protocol versions.
1070
+ #
1071
+ SecRule REQUEST_PROTOCOL "!@within %{tx.allowed_http_versions}" \
1072
+ "id:920430,\
1073
+ phase:1,\
1074
+ block,\
1075
+ t:none,\
1076
+ msg:'HTTP protocol version is not allowed by policy',\
1077
+ logdata:'%{MATCHED_VAR}',\
1078
+ tag:'application-multi',\
1079
+ tag:'language-multi',\
1080
+ tag:'platform-multi',\
1081
+ tag:'attack-protocol',\
1082
+ tag:'paranoia-level/1',\
1083
+ tag:'OWASP_CRS',\
1084
+ tag:'capec/1000/210/272',\
1085
+ tag:'PCI/6.5.10',\
1086
+ ver:'OWASP_CRS/4.9.0',\
1087
+ severity:'CRITICAL',\
1088
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
1089
+
1090
+ #
1091
+ # Restrict file extension
1092
+ #
1093
+ SecRule REQUEST_BASENAME "@rx \.([^.]+)$" \
1094
+ "id:920440,\
1095
+ phase:1,\
1096
+ block,\
1097
+ capture,\
1098
+ t:none,t:urlDecodeUni,\
1099
+ msg:'URL file extension is restricted by policy',\
1100
+ logdata:'%{TX.0}',\
1101
+ tag:'application-multi',\
1102
+ tag:'language-multi',\
1103
+ tag:'platform-multi',\
1104
+ tag:'attack-protocol',\
1105
+ tag:'paranoia-level/1',\
1106
+ tag:'OWASP_CRS',\
1107
+ tag:'capec/1000/210/272',\
1108
+ tag:'PCI/6.5.10',\
1109
+ ver:'OWASP_CRS/4.9.0',\
1110
+ severity:'CRITICAL',\
1111
+ setvar:'tx.extension=.%{tx.1}/',\
1112
+ chain"
1113
+ SecRule TX:EXTENSION "@within %{tx.restricted_extensions}" \
1114
+ "t:none,t:lowercase,\
1115
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
1116
+
1117
+ #
1118
+ # Backup or "working" file extension
1119
+ # example: index.php~, /index.php~/foo/
1120
+ #
1121
+ SecRule REQUEST_FILENAME "@rx \.[^.~]+~(?:/.*|)$" \
1122
+ "id:920500,\
1123
+ phase:1,\
1124
+ block,\
1125
+ t:none,t:urlDecodeUni,\
1126
+ msg:'Attempt to access a backup or working file',\
1127
+ logdata:'%{TX.0}',\
1128
+ tag:'application-multi',\
1129
+ tag:'language-multi',\
1130
+ tag:'platform-multi',\
1131
+ tag:'attack-protocol',\
1132
+ tag:'paranoia-level/1',\
1133
+ tag:'OWASP_CRS',\
1134
+ tag:'capec/1000/210/272',\
1135
+ tag:'PCI/6.5.10',\
1136
+ ver:'OWASP_CRS/4.9.0',\
1137
+ severity:'CRITICAL',\
1138
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
1139
+
1140
+ #
1141
+ # Restricted HTTP headers
1142
+ #
1143
+ # -=[ Rule Logic ]=-
1144
+ # The use of certain headers is restricted. They are listed in two variables:
1145
+ # - TX.restricted_headers_basic: Known security risks, always forbidden (rule
1146
+ # 920450)
1147
+ # - TX.restricted_headers_extended: Possible false positives, possible security
1148
+ # risks, may be forbidden (rule 920451)
1149
+ #
1150
+ # The headers are transformed into lowercase before the match. In order to make
1151
+ # sure that only complete header names match, the names in the
1152
+ # TX.restricted_headers_* variables are wrapped in slashes. This guarantees that
1153
+ # the Range header (which becomes /range/) will not match the restricted
1154
+ # /content-range/ header, for example.
1155
+ #
1156
+ # This is a chained rule, where the first rule fills a set of variables of the
1157
+ # form TX.header_name_<RULE_ID>_<HEADER_NAME>. The second rule is then executed
1158
+ # for all variables of the form TX.header_name_<RULE_ID>_<HEADER_NAME>.
1159
+ #
1160
+ # As a consequence of the construction of the rule, the alert message and the
1161
+ # alert data will not display the original header name Content-Range, but
1162
+ # /content-range/ instead.
1163
+ #
1164
+ # This rule has a stricter sibling, 920451, which matches against the variable
1165
+ # TX.restricted_headers_extended. It handles deprecated headers that are still
1166
+ # in use (so false positives are possible, hence unsuitable for blocking in a
1167
+ # default paranoia level 1 installation) and headers with possible security
1168
+ # risks.
1169
+ #
1170
+ # -=[ References ]=-
1171
+ # https://access.redhat.com/security/vulnerabilities/httpoxy (Header Proxy)
1172
+ # https://www.sidechannel.blog/en/http-method-override-what-it-is-and-how-a-pentester-can-use-it
1173
+ #
1174
+ SecRule REQUEST_HEADERS_NAMES "@rx ^.*$" \
1175
+ "id:920450,\
1176
+ phase:1,\
1177
+ block,\
1178
+ capture,\
1179
+ t:none,t:lowercase,\
1180
+ msg:'HTTP header is restricted by policy (%{MATCHED_VAR})',\
1181
+ logdata:'Restricted header detected: %{MATCHED_VAR}',\
1182
+ tag:'application-multi',\
1183
+ tag:'language-multi',\
1184
+ tag:'platform-multi',\
1185
+ tag:'attack-protocol',\
1186
+ tag:'paranoia-level/1',\
1187
+ tag:'OWASP_CRS',\
1188
+ tag:'capec/1000/210/272',\
1189
+ tag:'PCI/12.1',\
1190
+ ver:'OWASP_CRS/4.9.0',\
1191
+ severity:'CRITICAL',\
1192
+ setvar:'tx.header_name_920450_%{tx.0}=/%{tx.0}/',\
1193
+ chain"
1194
+ SecRule TX:/^header_name_920450_/ "@within %{tx.restricted_headers_basic}" \
1195
+ "setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
1196
+
1197
+ #
1198
+ # Rule against CVE-2022-21907
1199
+ # This rule blocks Accept-Encoding headers longer than 100 characters.
1200
+ # The length of 100 is a heuristic based on the length of values from
1201
+ # the RFC (https://datatracker.ietf.org/doc/rfc9110/)
1202
+ # and the respective values assigned by IANA
1203
+ # (https://www.iana.org/assignments/http-parameters/http-parameters.xml#content-coding).
1204
+ # Concatenating all valid values for Accept-Encoding (without q=0.5) resulted in a value of 93:
1205
+ # aes128gcm, br, compress, deflate, exi, gzip, identity, pack200-gzip, x-compress, x-gzip, zstd
1206
+ #
1207
+ # This rule has a stricter sibling: 920521
1208
+ #
1209
+ SecRule REQUEST_HEADERS:Accept-Encoding "@gt 100" \
1210
+ "id:920520,\
1211
+ phase:1,\
1212
+ block,\
1213
+ t:none,t:lowercase,t:length,\
1214
+ msg:'Accept-Encoding header exceeded sensible length',\
1215
+ logdata:'%{MATCHED_VAR}',\
1216
+ tag:'application-multi',\
1217
+ tag:'language-multi',\
1218
+ tag:'platform-multi',\
1219
+ tag:'attack-protocol',\
1220
+ tag:'paranoia-level/1',\
1221
+ tag:'OWASP_CRS',\
1222
+ tag:'capec/1000/255/153',\
1223
+ tag:'PCI/12.1',\
1224
+ ver:'OWASP_CRS/4.9.0',\
1225
+ severity:'CRITICAL',\
1226
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
1227
+
1228
+ #
1229
+ # Restrict response charsets that we allow.
1230
+ # The following rules make sure that the response will be in an ASCII-compatible charset that
1231
+ # phase 4 rules can properly understand and block.
1232
+ #
1233
+
1234
+ #
1235
+ # Some servers rely on the request Accept header to determine what charset to respond with.
1236
+ # This rule restricts these to familiar charsets.
1237
+ #
1238
+ # Regular expression generated from regex-assembly/920600.ra.
1239
+ # To update the regular expression run the following shell script
1240
+ # (consult https://coreruleset.org/docs/development/regex_assembly/ for details):
1241
+ # crs-toolchain regex update 920600
1242
+ #
1243
+ SecRule REQUEST_HEADERS:Accept "!@rx ^(?:(?:\*|[^!\"\(\),/:-\?\[-\]\{\}]+)/(?:\*|[^!\"\(\),/:-\?\[-\]\{\}]+)|\*)(?:[\s\x0b]*;[\s\x0b]*(?:charset[\s\x0b]*=[\s\x0b]*\"?(?:iso-8859-15?|utf-8|windows-1252)\b\"?|(?:[^\s\x0b-\"\(\),/:-\?\[-\]c\{\}]|c(?:[^!\"\(\),/:-\?\[-\]h\{\}]|h(?:[^!\"\(\),/:-\?\[-\]a\{\}]|a(?:[^!\"\(\),/:-\?\[-\]r\{\}]|r(?:[^!\"\(\),/:-\?\[-\]s\{\}]|s(?:[^!\"\(\),/:-\?\[-\]e\{\}]|e[^!\"\(\),/:-\?\[-\]t\{\}]))))))[^!\"\(\),/:-\?\[-\]\{\}]*[\s\x0b]*=[\s\x0b]*[^!\(\),/:-\?\[-\]\{\}]+);?)*(?:[\s\x0b]*,[\s\x0b]*(?:(?:\*|[^!\"\(\),/:-\?\[-\]\{\}]+)/(?:\*|[^!\"\(\),/:-\?\[-\]\{\}]+)|\*)(?:[\s\x0b]*;[\s\x0b]*(?:charset[\s\x0b]*=[\s\x0b]*\"?(?:iso-8859-15?|utf-8|windows-1252)\b\"?|(?:[^\s\x0b-\"\(\),/:-\?\[-\]c\{\}]|c(?:[^!\"\(\),/:-\?\[-\]h\{\}]|h(?:[^!\"\(\),/:-\?\[-\]a\{\}]|a(?:[^!\"\(\),/:-\?\[-\]r\{\}]|r(?:[^!\"\(\),/:-\?\[-\]s\{\}]|s(?:[^!\"\(\),/:-\?\[-\]e\{\}]|e[^!\"\(\),/:-\?\[-\]t\{\}]))))))[^!\"\(\),/:-\?\[-\]\{\}]*[\s\x0b]*=[\s\x0b]*[^!\(\),/:-\?\[-\]\{\}]+);?)*)*$" \
1244
+ "id:920600,\
1245
+ phase:1,\
1246
+ block,\
1247
+ t:none,t:lowercase,\
1248
+ msg:'Illegal Accept header: charset parameter',\
1249
+ logdata:'%{MATCHED_VAR}',\
1250
+ tag:'application-multi',\
1251
+ tag:'language-multi',\
1252
+ tag:'platform-multi',\
1253
+ tag:'attack-protocol',\
1254
+ tag:'paranoia-level/1',\
1255
+ tag:'OWASP_CRS',\
1256
+ ver:'OWASP_CRS/4.9.0',\
1257
+ severity:'CRITICAL',\
1258
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
1259
+
1260
+ #
1261
+ # Unicode character bypass check for non JSON requests
1262
+ # See reported bypass in issue:
1263
+ # https://github.com/coreruleset/coreruleset/issues/2512
1264
+ #
1265
+ SecRule REQBODY_PROCESSOR "!@streq JSON" \
1266
+ "id:920540,\
1267
+ phase:2,\
1268
+ block,\
1269
+ t:none,\
1270
+ msg:'Possible Unicode character bypass detected',\
1271
+ logdata:'%{MATCHED_VAR_NAME}=%{MATCHED_VAR}',\
1272
+ tag:'application-multi',\
1273
+ tag:'language-multi',\
1274
+ tag:'platform-multi',\
1275
+ tag:'attack-protocol',\
1276
+ tag:'paranoia-level/1',\
1277
+ tag:'OWASP_CRS',\
1278
+ tag:'capec/1000/255/153/267/72',\
1279
+ ver:'OWASP_CRS/4.9.0',\
1280
+ severity:'CRITICAL',\
1281
+ chain"
1282
+ SecRule REQUEST_URI|REQUEST_HEADERS|ARGS|ARGS_NAMES "@rx (?i)\x5cu[0-9a-f]{4}" \
1283
+ "setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
1284
+
1285
+ #
1286
+ # Disallow any raw URL fragments. The '#' character should be omitted or URL-encoded.
1287
+ # CRS rules generally do not check REQUEST_URI_RAW, but some servers accept the fragment as part of the URL path/query.
1288
+ # This creates false negative evasions.
1289
+ #
1290
+ SecRule REQUEST_URI_RAW "@contains #" \
1291
+ "id:920610,\
1292
+ phase:1,\
1293
+ block,\
1294
+ t:none,\
1295
+ msg:'Raw (unencoded) fragment in request URI',\
1296
+ logdata:'%{MATCHED_VAR}',\
1297
+ tag:'application-multi',\
1298
+ tag:'language-multi',\
1299
+ tag:'platform-multi',\
1300
+ tag:'attack-protocol',\
1301
+ tag:'paranoia-level/1',\
1302
+ tag:'OWASP_CRS',\
1303
+ ver:'OWASP_CRS/4.9.0',\
1304
+ severity:'CRITICAL',\
1305
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
1306
+
1307
+ #
1308
+ # The following rule (920620) checks for the presence of 2 or more request Content-Type headers.
1309
+ # Content-Type confusion poses a significant security risk to a web application. It occurs when
1310
+ # the server and client have different interpretations of the Content-Type header, leading to
1311
+ # miscommunication, potential exploitation and WAF bypass.
1312
+ #
1313
+ # Using Apache, when multiple Content-Type request headers are received, the server combines them
1314
+ # into a single header with the values separated by commas. For example, if a client sends multiple
1315
+ # Content-Type headers with values "application/json" and "text/plain", Apache will combine them
1316
+ # into a single header like this: "Content-Type: application/json, text/plain".
1317
+ #
1318
+ # On the other hand, Nginx handles multiple Content-Type headers differently. It preserves each
1319
+ # header as a separate entity without combining them. So, if a client sends multiple Content-Type
1320
+ # headers, Nginx will keep them separate, maintaining the original values.
1321
+ #
1322
+ SecRule &REQUEST_HEADERS:Content-Type "@gt 1" \
1323
+ "id:920620,\
1324
+ phase:1,\
1325
+ block,\
1326
+ t:none,\
1327
+ msg:'Multiple Content-Type Request Headers',\
1328
+ logdata:'%{MATCHED_VAR}',\
1329
+ tag:'application-multi',\
1330
+ tag:'language-multi',\
1331
+ tag:'platform-multi',\
1332
+ tag:'attack-protocol',\
1333
+ tag:'paranoia-level/1',\
1334
+ tag:'OWASP_CRS',\
1335
+ ver:'OWASP_CRS/4.9.0',\
1336
+ severity:'CRITICAL',\
1337
+ setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'"
1338
+
1339
+
1340
+ SecRule TX:DETECTION_PARANOIA_LEVEL "@lt 2" "id:920013,phase:1,pass,nolog,tag:'OWASP_CRS',ver:'OWASP_CRS/4.9.0',skipAfter:END-REQUEST-920-PROTOCOL-ENFORCEMENT"
1341
+ SecRule TX:DETECTION_PARANOIA_LEVEL "@lt 2" "id:920014,phase:2,pass,nolog,tag:'OWASP_CRS',ver:'OWASP_CRS/4.9.0',skipAfter:END-REQUEST-920-PROTOCOL-ENFORCEMENT"
1342
+ #
1343
+ # -= Paranoia Level 2 =- (apply only when tx.detection_paranoia_level is sufficiently high: 2 or higher)
1344
+ #
1345
+
1346
+ #
1347
+ # -=[ Rule Logic ]=-
1348
+ #
1349
+ # Check the number of range fields in the Range request header.
1350
+ #
1351
+ # An excessive number of Range request headers can be used to DoS a server.
1352
+ # The original CVE proposed an arbitrary upper limit of 5 range fields.
1353
+ #
1354
+ # Several clients are known to request PDF fields with up to 62 range
1355
+ # fields. Therefore the standard rule does not cover PDF files. This is
1356
+ # performed in two separate (stricter) siblings of this rule.
1357
+ #
1358
+ # 920200: PL2: Limit of 5 range header fields for all filenames outside of PDFs
1359
+ # 920201: PL2: Limit of 62 range header fields for PDFs
1360
+ # 920202: PL4: Limit of 5 range header fields for PDFs
1361
+ #
1362
+ # -=[ References ]=-
1363
+ # https://httpd.apache.org/security/CVE-2011-3192.txt
1364
+
1365
+
1366
+ SecRule REQUEST_HEADERS:Range|REQUEST_HEADERS:Request-Range "@rx ^bytes=(?:(?:\d+)?-(?:\d+)?\s*,?\s*){6}" \
1367
+ "id:920200,\
1368
+ phase:1,\
1369
+ block,\
1370
+ t:none,\
1371
+ msg:'Range: Too many fields (6 or more)',\
1372
+ logdata:'%{MATCHED_VAR}',\
1373
+ tag:'application-multi',\
1374
+ tag:'language-multi',\
1375
+ tag:'platform-multi',\
1376
+ tag:'attack-protocol',\
1377
+ tag:'paranoia-level/2',\
1378
+ tag:'OWASP_CRS',\
1379
+ tag:'capec/1000/210/272',\
1380
+ ver:'OWASP_CRS/4.9.0',\
1381
+ severity:'WARNING',\
1382
+ chain"
1383
+ SecRule REQUEST_BASENAME "!@endsWith .pdf" \
1384
+ "setvar:'tx.inbound_anomaly_score_pl2=+%{tx.warning_anomaly_score}'"
1385
+
1386
+ #
1387
+ # This is a sibling of rule 920200
1388
+ #
1389
+
1390
+ SecRule REQUEST_BASENAME "@endsWith .pdf" \
1391
+ "id:920201,\
1392
+ phase:1,\
1393
+ block,\
1394
+ t:none,t:urlDecodeUni,\
1395
+ msg:'Range: Too many fields for pdf request (63 or more)',\
1396
+ logdata:'%{MATCHED_VAR}',\
1397
+ tag:'application-multi',\
1398
+ tag:'language-multi',\
1399
+ tag:'platform-multi',\
1400
+ tag:'attack-protocol',\
1401
+ tag:'paranoia-level/2',\
1402
+ tag:'OWASP_CRS',\
1403
+ tag:'capec/1000/210/272',\
1404
+ ver:'OWASP_CRS/4.9.0',\
1405
+ severity:'WARNING',\
1406
+ chain"
1407
+ SecRule REQUEST_HEADERS:Range|REQUEST_HEADERS:Request-Range "@rx ^bytes=(?:(?:\d+)?-(?:\d+)?\s*,?\s*){63}" \
1408
+ "setvar:'tx.inbound_anomaly_score_pl2=+%{tx.warning_anomaly_score}'"
1409
+
1410
+
1411
+ SecRule ARGS "@rx %[0-9a-fA-F]{2}" \
1412
+ "id:920230,\
1413
+ phase:2,\
1414
+ block,\
1415
+ t:none,\
1416
+ msg:'Multiple URL Encoding Detected',\
1417
+ logdata:'%{MATCHED_VAR}',\
1418
+ tag:'application-multi',\
1419
+ tag:'language-multi',\
1420
+ tag:'platform-multi',\
1421
+ tag:'attack-protocol',\
1422
+ tag:'paranoia-level/2',\
1423
+ tag:'OWASP_CRS',\
1424
+ tag:'capec/1000/255/153/267/120',\
1425
+ ver:'OWASP_CRS/4.9.0',\
1426
+ severity:'WARNING',\
1427
+ setvar:'tx.inbound_anomaly_score_pl2=+%{tx.warning_anomaly_score}'"
1428
+
1429
+
1430
+ #
1431
+ # PL2: This is a stricter sibling of 920270.
1432
+ #
1433
+ SecRule REQUEST_URI|REQUEST_HEADERS|ARGS|ARGS_NAMES "@validateByteRange 9,10,13,32-126,128-255" \
1434
+ "id:920271,\
1435
+ phase:2,\
1436
+ block,\
1437
+ t:none,t:urlDecodeUni,\
1438
+ msg:'Invalid character in request (non printable characters)',\
1439
+ logdata:'%{MATCHED_VAR_NAME}=%{MATCHED_VAR}',\
1440
+ tag:'application-multi',\
1441
+ tag:'language-multi',\
1442
+ tag:'platform-multi',\
1443
+ tag:'attack-protocol',\
1444
+ tag:'paranoia-level/2',\
1445
+ tag:'OWASP_CRS',\
1446
+ tag:'capec/1000/210/272',\
1447
+ ver:'OWASP_CRS/4.9.0',\
1448
+ severity:'CRITICAL',\
1449
+ setvar:'tx.inbound_anomaly_score_pl2=+%{tx.critical_anomaly_score}'"
1450
+
1451
+
1452
+
1453
+ #
1454
+ # Missing User-Agent Header
1455
+ #
1456
+ # -=[ Rule Logic ]=-
1457
+ # This rules will check to see if there is a User-Agent header or not.
1458
+ #
1459
+
1460
+ SecRule &REQUEST_HEADERS:User-Agent "@eq 0" \
1461
+ "id:920320,\
1462
+ phase:1,\
1463
+ pass,\
1464
+ t:none,\
1465
+ msg:'Missing User Agent Header',\
1466
+ tag:'application-multi',\
1467
+ tag:'language-multi',\
1468
+ tag:'platform-multi',\
1469
+ tag:'attack-protocol',\
1470
+ tag:'paranoia-level/2',\
1471
+ tag:'OWASP_CRS',\
1472
+ tag:'capec/1000/210/272',\
1473
+ tag:'PCI/6.5.10',\
1474
+ ver:'OWASP_CRS/4.9.0',\
1475
+ severity:'NOTICE',\
1476
+ setvar:'tx.inbound_anomaly_score_pl2=+%{tx.notice_anomaly_score}'"
1477
+
1478
+
1479
+ #
1480
+ # PL2: This is a stricter sibling of 920120.
1481
+ #
1482
+ SecRule FILES_NAMES|FILES "@rx ['\";=\x5c]" \
1483
+ "id:920121,\
1484
+ phase:2,\
1485
+ block,\
1486
+ t:none,t:urlDecodeUni,\
1487
+ msg:'Attempted multipart/form-data bypass',\
1488
+ logdata:'%{MATCHED_VAR}',\
1489
+ tag:'application-multi',\
1490
+ tag:'language-multi',\
1491
+ tag:'platform-multi',\
1492
+ tag:'attack-protocol',\
1493
+ tag:'paranoia-level/2',\
1494
+ tag:'OWASP_CRS',\
1495
+ tag:'capec/1000/210/272',\
1496
+ ver:'OWASP_CRS/4.9.0',\
1497
+ severity:'CRITICAL',\
1498
+ setvar:'tx.inbound_anomaly_score_pl2=+%{tx.critical_anomaly_score}'"
1499
+
1500
+
1501
+ #
1502
+ # PL2: Block on Missing Content-Type Header with Request Body
1503
+ # This is a stricter sibling of rule 920340.
1504
+ #
1505
+ # -=[ References ]=-
1506
+ # http://httpwg.org/specs/rfc7231.html#header.content-type
1507
+
1508
+ SecRule REQUEST_HEADERS:Content-Length "!@rx ^0$" \
1509
+ "id:920341,\
1510
+ phase:1,\
1511
+ block,\
1512
+ t:none,\
1513
+ msg:'Request Containing Content Requires Content-Type header',\
1514
+ tag:'application-multi',\
1515
+ tag:'language-multi',\
1516
+ tag:'platform-multi',\
1517
+ tag:'attack-protocol',\
1518
+ tag:'paranoia-level/2',\
1519
+ tag:'OWASP_CRS',\
1520
+ tag:'capec/1000/210/272',\
1521
+ ver:'OWASP_CRS/4.9.0',\
1522
+ severity:'CRITICAL',\
1523
+ chain"
1524
+ SecRule &REQUEST_HEADERS:Content-Type "@eq 0" \
1525
+ "t:none,\
1526
+ setvar:'tx.inbound_anomaly_score_pl2=+%{tx.critical_anomaly_score}'"
1527
+
1528
+
1529
+ #
1530
+ # PL2: This is a stricter sibling of 920450.
1531
+ #
1532
+ SecRule REQUEST_HEADERS_NAMES "@rx ^.*$" \
1533
+ "id:920451,\
1534
+ phase:1,\
1535
+ block,\
1536
+ capture,\
1537
+ t:none,t:lowercase,\
1538
+ msg:'HTTP header is restricted by policy (%{MATCHED_VAR})',\
1539
+ logdata:'Restricted header detected: %{MATCHED_VAR}',\
1540
+ tag:'application-multi',\
1541
+ tag:'language-multi',\
1542
+ tag:'platform-multi',\
1543
+ tag:'attack-protocol',\
1544
+ tag:'paranoia-level/2',\
1545
+ tag:'OWASP_CRS',\
1546
+ tag:'capec/1000/210/272',\
1547
+ tag:'PCI/12.1',\
1548
+ ver:'OWASP_CRS/4.9.0',\
1549
+ severity:'CRITICAL',\
1550
+ setvar:'tx.header_name_920451_%{tx.0}=/%{tx.0}/',\
1551
+ chain"
1552
+ SecRule TX:/^header_name_920451_/ "@within %{tx.restricted_headers_extended}" \
1553
+ "setvar:'tx.inbound_anomaly_score_pl2=+%{tx.critical_anomaly_score}'"
1554
+
1555
+
1556
+ #
1557
+ # Check URL encodings
1558
+ #
1559
+ # See comment on rule 920220.
1560
+ #
1561
+ SecRule REQUEST_HEADERS:Content-Type "@rx ^(?i)application/x-www-form-urlencoded" \
1562
+ "id:920240,\
1563
+ phase:2,\
1564
+ block,\
1565
+ t:none,\
1566
+ msg:'URL Encoding Abuse Attack Attempt',\
1567
+ logdata:'%{MATCHED_VAR}',\
1568
+ tag:'application-multi',\
1569
+ tag:'language-multi',\
1570
+ tag:'platform-multi',\
1571
+ tag:'attack-protocol',\
1572
+ tag:'paranoia-level/2',\
1573
+ tag:'OWASP_CRS',\
1574
+ tag:'capec/1000/255/153/267/72',\
1575
+ ver:'OWASP_CRS/4.9.0',\
1576
+ severity:'WARNING',\
1577
+ chain"
1578
+ SecRule REQUEST_BODY "@rx \x25" \
1579
+ "chain"
1580
+ SecRule REQUEST_BODY "@validateUrlEncoding" \
1581
+ "setvar:'tx.inbound_anomaly_score_pl2=+%{tx.warning_anomaly_score}'"
1582
+
1583
+ SecRule TX:DETECTION_PARANOIA_LEVEL "@lt 3" "id:920015,phase:1,pass,nolog,tag:'OWASP_CRS',ver:'OWASP_CRS/4.9.0',skipAfter:END-REQUEST-920-PROTOCOL-ENFORCEMENT"
1584
+ SecRule TX:DETECTION_PARANOIA_LEVEL "@lt 3" "id:920016,phase:2,pass,nolog,tag:'OWASP_CRS',ver:'OWASP_CRS/4.9.0',skipAfter:END-REQUEST-920-PROTOCOL-ENFORCEMENT"
1585
+ #
1586
+ # -= Paranoia Level 3 =- (apply only when tx.detection_paranoia_level is sufficiently high: 3 or higher)
1587
+ #
1588
+
1589
+ #
1590
+ # PL 3: This is a stricter sibling of 920270. Ascii range: Printable characters in the low range
1591
+ #
1592
+ # This rule is also triggered by the following exploit(s):
1593
+ # [ SAP CRM Java vulnerability CVE-2018-2380 - Exploit tested: https://www.exploit-db.com/exploits/44292 ]
1594
+ #
1595
+ SecRule REQUEST_URI|REQUEST_HEADERS|ARGS|ARGS_NAMES|REQUEST_BODY "@validateByteRange 32-36,38-126" \
1596
+ "id:920272,\
1597
+ phase:2,\
1598
+ block,\
1599
+ t:none,t:urlDecodeUni,\
1600
+ msg:'Invalid character in request (outside of printable chars below ascii 127)',\
1601
+ logdata:'%{MATCHED_VAR_NAME}=%{MATCHED_VAR}',\
1602
+ tag:'application-multi',\
1603
+ tag:'language-multi',\
1604
+ tag:'platform-multi',\
1605
+ tag:'attack-protocol',\
1606
+ tag:'paranoia-level/3',\
1607
+ tag:'OWASP_CRS',\
1608
+ tag:'capec/1000/210/272',\
1609
+ ver:'OWASP_CRS/4.9.0',\
1610
+ severity:'CRITICAL',\
1611
+ setvar:'tx.inbound_anomaly_score_pl3=+%{tx.critical_anomaly_score}'"
1612
+
1613
+ #
1614
+ # Missing Accept Header
1615
+ #
1616
+ # This rule has been moved to PL3
1617
+ #
1618
+ # -=[ Rule Logic ]=-
1619
+ # This rule generates a notice if the Accept header is missing.
1620
+ # RFC 7231 does not enforce the use of the Accept header.
1621
+ # It is just typical browser behavior to send and it can indicate a malicious client.
1622
+ #
1623
+ # Notice: The rule tries to avoid known false positives by ignoring
1624
+ # OPTIONS requests, CONNECT requests, and requests coming from known
1625
+ # offending User-Agents via two chained rules.
1626
+ # As ModSecurity only reports the match of the last matching rule,
1627
+ # the alert is misleading.
1628
+ #
1629
+ SecRule &REQUEST_HEADERS:Accept "@eq 0" \
1630
+ "id:920300,\
1631
+ phase:1,\
1632
+ pass,\
1633
+ t:none,\
1634
+ msg:'Request Missing an Accept Header',\
1635
+ tag:'application-multi',\
1636
+ tag:'language-multi',\
1637
+ tag:'platform-multi',\
1638
+ tag:'attack-protocol',\
1639
+ tag:'paranoia-level/3',\
1640
+ tag:'OWASP_CRS',\
1641
+ tag:'capec/1000/210/272',\
1642
+ tag:'PCI/6.5.10',\
1643
+ ver:'OWASP_CRS/4.9.0',\
1644
+ severity:'NOTICE',\
1645
+ chain"
1646
+ SecRule REQUEST_METHOD "!@rx ^(?:OPTIONS|CONNECT)$" \
1647
+ "chain"
1648
+ SecRule REQUEST_HEADERS:User-Agent "!@pm AppleWebKit Android" \
1649
+ "t:none,\
1650
+ setvar:'tx.inbound_anomaly_score_pl3=+%{tx.notice_anomaly_score}'"
1651
+
1652
+
1653
+ #
1654
+ # PL3: The little known x-up-devcap-post-charset request header can be used to submit
1655
+ # a request with a different encoding as an alternative to the charset parameter in
1656
+ # the Content-Type header. This can be used to circumvent charset restrictions on
1657
+ # the Content-Type header in ASP.NET.
1658
+ # Note that this only works in combination with a User-Agent prefix.
1659
+ #
1660
+ # This rule is based on a blog post by Soroush Dalili at
1661
+ # https://soroush.me/blog/2019/05/x-up-devcap-post-charset-header-in-aspnet-to-bypass-wafs-again/
1662
+ #
1663
+ SecRule &REQUEST_HEADERS:x-up-devcap-post-charset "@ge 1" \
1664
+ "id:920490,\
1665
+ phase:1,\
1666
+ block,\
1667
+ t:none,\
1668
+ msg:'Request header x-up-devcap-post-charset detected in combination with prefix \'UP\' to User-Agent',\
1669
+ logdata:'%{MATCHED_VAR_NAME}=%{MATCHED_VAR}',\
1670
+ tag:'language-aspnet',\
1671
+ tag:'platform-windows',\
1672
+ tag:'attack-protocol',\
1673
+ tag:'paranoia-level/3',\
1674
+ tag:'OWASP_CRS',\
1675
+ tag:'capec/1000/210/272',\
1676
+ ver:'OWASP_CRS/4.9.0',\
1677
+ severity:'CRITICAL',\
1678
+ chain"
1679
+ SecRule REQUEST_HEADERS:User-Agent "@rx ^(?i)up" \
1680
+ "t:none,\
1681
+ setvar:'tx.inbound_anomaly_score_pl3=+%{tx.critical_anomaly_score}'"
1682
+
1683
+
1684
+ #
1685
+ # Cache-Control Request Header allow list
1686
+ #
1687
+ # -=[ Rule Logic ]=-
1688
+ # This rule aims to strictly allow list the Cache-Control request header
1689
+ # values and to blocks all violations. This should be useful to intercept
1690
+ # "bad bot" and tools that impersonate a real browser but with wrong request
1691
+ # header setup.
1692
+ #
1693
+ # The regular expression used on this rule tries to match multiple directives
1694
+ # in a single value, for example: "max-stale=1, max-age=2". This leads us to
1695
+ # use a regular expression that accepts a trailing comma to keep compatibility
1696
+ # with all regex engines and not PCRE only. For example: "max-stale=1, max-age=2, "
1697
+ #
1698
+ # Moreover, this regular expression allows duplicate directives sequence like:
1699
+ # "max-stale, max-stale=1, no-cache, no-cache".
1700
+ #
1701
+ # Standard Cache-Control directives that can be used by the client:
1702
+ # - max-age=<seconds>
1703
+ # - max-stale[=<seconds>]
1704
+ # - min-fresh=<seconds>
1705
+ # - no-cache
1706
+ # - no-store
1707
+ # - no-transform
1708
+ # - only-if-cached
1709
+ #
1710
+ # References:
1711
+ # - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
1712
+ # - https://regex101.com/r/CZ0Hxu/22
1713
+ #
1714
+ SecRule &REQUEST_HEADERS:Cache-Control "@gt 0" \
1715
+ "id:920510,\
1716
+ phase:1,\
1717
+ block,\
1718
+ t:none,\
1719
+ msg:'Invalid Cache-Control request header',\
1720
+ logdata:'Invalid Cache-Control value in request found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\
1721
+ tag:'application-multi',\
1722
+ tag:'language-multi',\
1723
+ tag:'platform-multi',\
1724
+ tag:'attack-protocol',\
1725
+ tag:'header-allowlist',\
1726
+ tag:'paranoia-level/3',\
1727
+ tag:'OWASP_CRS',\
1728
+ tag:'capec/1000/210/272',\
1729
+ ver:'OWASP_CRS/4.9.0',\
1730
+ severity:'CRITICAL',\
1731
+ chain"
1732
+ SecRule REQUEST_HEADERS:Cache-Control "!@rx ^(?:(?:max-age=[0-9]+|min-fresh=[0-9]+|no-cache|no-store|no-transform|only-if-cached|max-stale(?:=[0-9]+)?)(?:\s*\,\s*|$)){1,7}$" \
1733
+ "setvar:'tx.inbound_anomaly_score_pl3=+%{tx.critical_anomaly_score}'"
1734
+
1735
+ #
1736
+ # This rule checks for valid Accept-Encoding headers
1737
+ #
1738
+ # This rule has a less strict sibling: 920520
1739
+ #
1740
+ # Regular expression generated from regex-assembly/920521.ra.
1741
+ # To update the regular expression run the following shell script
1742
+ # (consult https://coreruleset.org/docs/development/regex_assembly/ for details):
1743
+ # crs-toolchain regex update 920521
1744
+ #
1745
+ SecRule REQUEST_HEADERS:Accept-Encoding "!@rx br|compress|deflate|(?:pack200-)?gzip|identity|\*|^$|aes128gcm|exi|zstd|x-(?:compress|gzip)" \
1746
+ "id:920521,\
1747
+ phase:1,\
1748
+ block,\
1749
+ t:none,t:lowercase,\
1750
+ msg:'Illegal Accept-Encoding header',\
1751
+ logdata:'%{MATCHED_VAR}',\
1752
+ tag:'application-multi',\
1753
+ tag:'language-multi',\
1754
+ tag:'platform-multi',\
1755
+ tag:'attack-protocol',\
1756
+ tag:'paranoia-level/3',\
1757
+ tag:'OWASP_CRS',\
1758
+ tag:'capec/1000/255/153',\
1759
+ tag:'PCI/12.1',\
1760
+ ver:'OWASP_CRS/4.9.0',\
1761
+ severity:'CRITICAL',\
1762
+ setvar:'tx.inbound_anomaly_score_pl3=+%{tx.critical_anomaly_score}'"
1763
+
1764
+ SecRule TX:DETECTION_PARANOIA_LEVEL "@lt 4" "id:920017,phase:1,pass,nolog,tag:'OWASP_CRS',ver:'OWASP_CRS/4.9.0',skipAfter:END-REQUEST-920-PROTOCOL-ENFORCEMENT"
1765
+ SecRule TX:DETECTION_PARANOIA_LEVEL "@lt 4" "id:920018,phase:2,pass,nolog,tag:'OWASP_CRS',ver:'OWASP_CRS/4.9.0',skipAfter:END-REQUEST-920-PROTOCOL-ENFORCEMENT"
1766
+ #
1767
+ # -= Paranoia Level 4 =- (apply only when tx.detection_paranoia_level is sufficiently high: 4 or higher)
1768
+ #
1769
+
1770
+ #
1771
+ # This is a stricter sibling of rule 920200
1772
+ #
1773
+
1774
+ SecRule REQUEST_BASENAME "@endsWith .pdf" \
1775
+ "id:920202,\
1776
+ phase:1,\
1777
+ block,\
1778
+ t:none,t:urlDecodeUni,\
1779
+ msg:'Range: Too many fields for pdf request (6 or more)',\
1780
+ logdata:'%{MATCHED_VAR}',\
1781
+ tag:'application-multi',\
1782
+ tag:'language-multi',\
1783
+ tag:'platform-multi',\
1784
+ tag:'attack-protocol',\
1785
+ tag:'paranoia-level/4',\
1786
+ tag:'OWASP_CRS',\
1787
+ tag:'capec/1000/210/272',\
1788
+ ver:'OWASP_CRS/4.9.0',\
1789
+ severity:'WARNING',\
1790
+ chain"
1791
+ SecRule REQUEST_HEADERS:Range|REQUEST_HEADERS:Request-Range "@rx ^bytes=(?:(?:\d+)?-(?:\d+)?\s*,?\s*){6}" \
1792
+ "setvar:'tx.inbound_anomaly_score_pl4=+%{tx.warning_anomaly_score}'"
1793
+
1794
+
1795
+ #
1796
+ # This is a stricter sibling of 920270.
1797
+ #
1798
+ # This rule is also triggered by the following exploit(s):
1799
+ # [ SAP CRM Java vulnerability CVE-2018-2380 - Exploit tested: https://www.exploit-db.com/exploits/44292 ]
1800
+ #
1801
+ SecRule ARGS|ARGS_NAMES|REQUEST_BODY "@validateByteRange 38,44-46,48-58,61,65-90,95,97-122" \
1802
+ "id:920273,\
1803
+ phase:2,\
1804
+ block,\
1805
+ t:none,t:urlDecodeUni,\
1806
+ msg:'Invalid character in request (outside of very strict set)',\
1807
+ logdata:'%{MATCHED_VAR_NAME}=%{MATCHED_VAR}',\
1808
+ tag:'application-multi',\
1809
+ tag:'language-multi',\
1810
+ tag:'platform-multi',\
1811
+ tag:'attack-protocol',\
1812
+ tag:'paranoia-level/4',\
1813
+ tag:'OWASP_CRS',\
1814
+ tag:'capec/1000/210/272',\
1815
+ ver:'OWASP_CRS/4.9.0',\
1816
+ severity:'CRITICAL',\
1817
+ setvar:'tx.inbound_anomaly_score_pl4=+%{tx.critical_anomaly_score}'"
1818
+
1819
+ #
1820
+ # This is a stricter sibling of 920270.
1821
+ #
1822
+ SecRule REQUEST_HEADERS|!REQUEST_HEADERS:User-Agent|!REQUEST_HEADERS:Referer|!REQUEST_HEADERS:Cookie|!REQUEST_HEADERS:Sec-Fetch-User|!REQUEST_HEADERS:Sec-CH-UA|!REQUEST_HEADERS:Sec-CH-UA-Mobile "@validateByteRange 32,34,38,42-59,61,65-90,95,97-122" \
1823
+ "id:920274,\
1824
+ phase:1,\
1825
+ block,\
1826
+ t:none,t:urlDecodeUni,\
1827
+ msg:'Invalid character in request headers (outside of very strict set)',\
1828
+ logdata:'%{MATCHED_VAR_NAME}=%{MATCHED_VAR}',\
1829
+ tag:'application-multi',\
1830
+ tag:'language-multi',\
1831
+ tag:'platform-multi',\
1832
+ tag:'attack-protocol',\
1833
+ tag:'paranoia-level/4',\
1834
+ tag:'OWASP_CRS',\
1835
+ tag:'capec/1000/210/272',\
1836
+ ver:'OWASP_CRS/4.9.0',\
1837
+ severity:'CRITICAL',\
1838
+ setvar:'tx.inbound_anomaly_score_pl4=+%{tx.critical_anomaly_score}'"
1839
+
1840
+ #
1841
+ # This is a stricter sibling of 920270.
1842
+ # The headers of this rule are Structured Header booleans, for which only `?0`,
1843
+ # and `?1` are inconspicuous.
1844
+ # Structured Header boolean: https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-header-structure-19#section-3.3.6
1845
+ # Sec-Fetch-User: https://www.w3.org/TR/fetch-metadata/#http-headerdef-sec-fetch-user
1846
+ # Sec-CH-UA-Mobile: https://wicg.github.io/ua-client-hints/#sec-ch-ua-mobile
1847
+ #
1848
+ SecRule REQUEST_HEADERS:Sec-Fetch-User|REQUEST_HEADERS:Sec-CH-UA-Mobile "!@rx ^(?:\?[01])?$" \
1849
+ "id:920275,\
1850
+ phase:1,\
1851
+ block,\
1852
+ t:none,t:urlDecodeUni,\
1853
+ msg:'Invalid character in request headers (outside of very strict set)',\
1854
+ logdata:'%{MATCHED_VAR_NAME}=%{MATCHED_VAR}',\
1855
+ tag:'application-multi',\
1856
+ tag:'language-multi',\
1857
+ tag:'platform-multi',\
1858
+ tag:'attack-protocol',\
1859
+ tag:'paranoia-level/4',\
1860
+ tag:'OWASP_CRS',\
1861
+ tag:'capec/1000/210/272',\
1862
+ ver:'OWASP_CRS/4.9.0',\
1863
+ severity:'CRITICAL',\
1864
+ setvar:'tx.inbound_anomaly_score_pl4=+%{tx.critical_anomaly_score}'"
1865
+
1866
+ # -=[ Abnormal Character Escapes ]=-
1867
+ #
1868
+ # [ Rule Logic ]
1869
+ # Consider the following payload: arg=cat+/e\tc/pa\ssw\d
1870
+ # Here, \s and \d were only used to obfuscate the string passwd and a lot of
1871
+ # parsers will silently ignore the non-necessary escapes. The case with \t is
1872
+ # a bit different though, as \t is a natural escape for the TAB character,
1873
+ # so we will avoid this (and \n, \r, etc.).
1874
+ #
1875
+ # This rule aims to detect non-necessary, abnormal escapes. You could say it is
1876
+ # a nice way to forbid the backslash character where it is not needed.
1877
+ #
1878
+ # This is a new rule at paranoia level 4. We expect quite a few false positives
1879
+ # for this rule and we will later evaluate if the rule makes any sense at all.
1880
+ # The rule is redundant with 920273 and 920274 in PL4. But if the rule proofs
1881
+ # to be useful and false positives remain at a reasonable level, then it might
1882
+ # be shifted to PL3 in a future release, where it would be the only rule
1883
+ # covering the backslash escape.
1884
+ #
1885
+ # We forbid backslashes followed by a list of basic ascii characters - unless
1886
+ # the backslash is preceded by another backslash.
1887
+ #
1888
+ # This rule is also triggered by the following exploit(s):
1889
+ # [ SAP CRM Java vulnerability CVE-2018-2380 - Exploit tested: https://www.exploit-db.com/exploits/44292 ]
1890
+ #
1891
+ SecRule REQUEST_URI|REQUEST_HEADERS|ARGS|ARGS_NAMES "@rx (?:^|[^\x5c])\x5c[cdeghijklmpqwxyz123456789]" \
1892
+ "id:920460,\
1893
+ phase:2,\
1894
+ block,\
1895
+ capture,\
1896
+ t:none,t:htmlEntityDecode,t:lowercase,\
1897
+ msg:'Abnormal character escapes in request',\
1898
+ logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\
1899
+ tag:'application-multi',\
1900
+ tag:'language-multi',\
1901
+ tag:'platform-multi',\
1902
+ tag:'attack-protocol',\
1903
+ tag:'paranoia-level/4',\
1904
+ tag:'OWASP_CRS',\
1905
+ tag:'capec/1000/153/267',\
1906
+ ver:'OWASP_CRS/4.9.0',\
1907
+ severity:'CRITICAL',\
1908
+ setvar:'tx.http_violation_score=+%{tx.critical_anomaly_score}',\
1909
+ setvar:'tx.inbound_anomaly_score_pl4=+%{tx.critical_anomaly_score}'"
1910
+
1911
+
1912
+ #
1913
+ # -= Paranoia Levels Finished =-
1914
+ #
1915
+ SecMarker "END-REQUEST-920-PROTOCOL-ENFORCEMENT"