GUI editor to tame mod_security rules

โŒˆโŒ‹ โŽ‡ branch:  modseccfg


Check-in [8e624a20d3]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Type and description changes in crsoptions. Release as 0.3.0
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk | 0.3.0
Files: files | file ages | folders
SHA3-256: 8e624a20d346ccdea2374388ed92238096f147b19aca90a9c8455fc33a14269c
User & Date: mario 2020-11-20 14:28:48
Context
2020-11-21
22:02
Fix missing lookahead for rx.end (closing VHost section got stripped after all) check-in: efee51370c user: mario tags: trunk
2020-11-20
14:28
Type and description changes in crsoptions. Release as 0.3.0 check-in: 8e624a20d3 user: mario tags: trunk, 0.3.0
2020-11-19
15:49
Prepare rules_in_between() lookup function. check-in: a1b61ab41b user: mario tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to FAQ.md.

78
79
80
81
82
83
84
85


86
87
88
89
90
91

92
93
94
95
96
97
98
99
100
101


102
103
104
105
106
107
108

#### Are there sshfs options to be set?

Secret config option is `sshfs_o`.

#### Other secret options

`editor_font` can't be edited from the config window




### Can this use other log scanners?

If there's a command line tool to scan audit logs for problems,
then yes, an option could be added.



### Why doesn't this provide for editing of VirtualHost sections?

That would be more work. And less intuitive for the majority,
and those that have properly separated vhosts into distinct
config files.

There's a few python packages for Apache config parsing that would
allow so, but none that are overly convenient to build upon.



#### It always writes to the first VirtualHost in a file

Yes.

All SecRule* flags are appended, or injected before any first
closing `</VirtualHost>`







|
>
>





|
>









|
>
>







78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113

#### Are there sshfs options to be set?

Secret config option is `sshfs_o`.

#### Other secret options

`editor_font` can't be edited from the config window, due to being
a list. The config definition allows to add a third font
property `["โ€ฆ", "โ€ฆ", "bold"]` however.


### Can this use other log scanners?

If there's a command line tool to scan audit logs for problems,
then yes, an option could be added. (In fact, it's planned to
bundle a bin/ folder and according menu for Log analyzers.)


### Why doesn't this provide for editing of VirtualHost sections?

That would be more work. And less intuitive for the majority,
and those that have properly separated vhosts into distinct
config files.

There's a few python packages for Apache config parsing that would
allow so, but none that are overly convenient to build upon. (Not
to mention support for non-destructive file updating.)


#### It always writes to the first VirtualHost in a file

Yes.

All SecRule* flags are appended, or injected before any first
closing `</VirtualHost>`

Changes to Makefile.

5
6
7
8
9
10
11

	pandoc README.md -o README.rst
	version --read modseccfg/__init__.py --write modseccfg/mainwindow.py
	python3 setup.py bdist_wheel
	rm -r modseccfg.egg-info

upload: setup
	python3 setup.py bdist_wheel upload








>
5
6
7
8
9
10
11
12
	pandoc README.md -o README.rst
	version --read modseccfg/__init__.py --write modseccfg/mainwindow.py
	python3 setup.py bdist_wheel
	rm -r modseccfg.egg-info

upload: setup
	python3 setup.py bdist_wheel upload
	rm -r modseccfg.egg-info

Changes to NEWS.






1
2
3
4
5
6
7





0.2.0 (2020-11-17)
 * Added an [info] dialog for rule inspection.
 * Implemented [enable] to undo SecRemoveRemoveRuleById directives.
 * Keyboard bindings in main window, hourglass mouse pointer for
   updates, and uses appdirs now instead of a fixed CONFIG_HOME path.
 * Multiple dialogs (main, editor, window) can now run in parallel.
 * Config dictionary has been merged into appsettings.
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
0.3.0 (2020-11-20)
 * Introduced editor for SecOption directives.
 * And an options dialog for CoreRuleSet variables.
 * Minor adaptions to pluginconf.gui, and decorators for mainwindow features.

0.2.0 (2020-11-17)
 * Added an [info] dialog for rule inspection.
 * Implemented [enable] to undo SecRemoveRemoveRuleById directives.
 * Keyboard bindings in main window, hourglass mouse pointer for
   updates, and uses appdirs now instead of a fixed CONFIG_HOME path.
 * Multiple dialogs (main, editor, window) can now run in parallel.
 * Config dictionary has been merged into appsettings.

Changes to README.md.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
..
75
76
77
78
79
80
81
82
83
84
85
86
87
88
> *WARNING: THIS IS ALPHA STAGE QUALITY AND WILL MOST CERTAINLY DELETE YOUR APACHE CONFIGURATION*  
> - It doesn't, but: no warranty and such. - Also, hasn't many features yet.

## modseccfg

 * Simple GUI editor for SecRuleRemoveById settings
 * Tries to suggest false positives from error and audit logs
 * (And a few options to configure mod_security and CRS variables.)
 * Runs locally, via `ssh -X` forwarding, or per `modseccfg vps5:/`
   automount.

![](https://fossil.include-once.org/modseccfg/raw/59f5daf65f51?m=image/gif)

## Installation

................................................................................
   multiple `<VirtualHost>` in one `*.conf` (else only the first section
   will be augmented).

### Missing features

 * File permission check on remote host is non-functional still.
 * Doesn't process any audit.log yet.
 * Can't classify wrapped (`<Location>` or other directives) rules yet.
 * ~~No rule information dialog.~~
 * No SecOption editor yet.
 * No CRS settings (setvar:crsโ€ฆ) editor yet.
 * Recipes are not worth using yet.
 * No sudo usage.








|







 







|

|
|



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
..
75
76
77
78
79
80
81
82
83
84
85
86
87
88
> *WARNING: THIS IS ALPHA STAGE QUALITY AND WILL MOST CERTAINLY DELETE YOUR APACHE CONFIGURATION*  
> - It doesn't, but: no warranty and such. - Also, hasn't many features yet.

## modseccfg

 * Simple GUI editor for SecRuleRemoveById settings
 * Tries to suggest false positives from error and audit logs
 * And configure mod_security and CoreRuleSet variables.
 * Runs locally, via `ssh -X` forwarding, or per `modseccfg vps5:/`
   automount.

![](https://fossil.include-once.org/modseccfg/raw/59f5daf65f51?m=image/gif)

## Installation

................................................................................
   multiple `<VirtualHost>` in one `*.conf` (else only the first section
   will be augmented).

### Missing features

 * File permission check on remote host is non-functional still.
 * Doesn't process any audit.log yet.
 * Can't classify wrapped (`<Location>`/`<FilesMatch>`) rules yet.
 * ~~No rule information dialog.~~
 * ~~No SecOption editor yet.~~
 * ~~No CRS settings (setvar:crsโ€ฆ) editor yet.~~
 * Recipes are not worth using yet.
 * No sudo usage.

Changes to dev/crsvars.conf.

37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
..
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
...
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
...
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
...
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
...
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
...
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
...
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
...
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
...
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
...
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
...
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
...
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
...
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
...
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
...
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
...
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
#
# The OWASP ModSecurity Core Rule Set is distributed under
# Apache Software License (ASL) version 2
# Please see the enclosed LICENSE file for full details.
# ------------------------------------------------------------------------


#
# -- [[ Introduction ]] --------------------------------------------------------
#
# The OWASP ModSecurity Core Rule Set (CRS) is a set of generic attack
# detection rules that provide a base level of protection for any web
# application. They are written for the open source, cross-platform
# ModSecurity Web Application Firewall.
#
# See also:
# https://coreruleset.org/
# https://github.com/SpiderLabs/owasp-modsecurity-crs
# https://www.owasp.org/index.php/Category:OWASP_ModSecurity_Core_Rule_Set_Project
#


#
# -- [[ System Requirements ]] -------------------------------------------------
#
# CRS requires ModSecurity version 2.8.0 or above.
# We recommend to always use the newest ModSecurity version.
#
# The configuration directives/settings in this file are used to control
# the OWASP ModSecurity CRS. These settings do **NOT** configure the main
# ModSecurity settings (modsecurity.conf) such as SecRuleEngine,
# SecRequestBodyAccess, SecAuditEngine, SecDebugLog, and XML processing.
................................................................................
# 3. rules/*.conf (the CRS rule files)
#
# Please refer to the INSTALL file for detailed installation instructions.
#


#
# -- [[ Mode of Operation: Anomaly Scoring vs. Self-Contained ]] ---------------
#
# The CRS can run in two modes:
#
# -- [[ Anomaly Scoring Mode (default) ]] --
# In CRS3, anomaly mode is the default and recommended mode, since it gives the
# most accurate log information and offers the most flexibility in setting your
# blocking policies. It is also called "collaborative detection mode".
# In this mode, each matching rule increases an 'anomaly score'.
................................................................................
#   if a Cookie or User-Agent header is blocked, it will also be blocked when
#   the client subsequently tries to access the homepage. You can also redirect
#   to another custom URL.
# SecDefaultAction "phase:1,log,auditlog,redirect:'http://%{request_headers.host}/',tag:'Host: %{request_headers.host}'"
# SecDefaultAction "phase:2,log,auditlog,redirect:'http://%{request_headers.host}/',tag:'Host: %{request_headers.host}'"


#
# -- [[ Paranoia Level Initialization ]] ---------------------------------------
#
# The Paranoia Level (PL) setting allows you to choose the desired level
# of rule checks that will add to your anomaly scores.
#
# With each paranoia level increase, the CRS enables additional rules
# giving you a higher level of security. However, higher paranoia levels
# also increase the possibility of blocking some legitimate traffic due to
# false alarms (also named false positives or FPs). If you use higher
................................................................................
   phase:1,\
   nolog,\
   pass,\
   t:none,\
   setvar:tx.executing_paranoia_level=1"


#
# -- [[ Enforce Body Processor URLENCODED ]] -----------------------------------
#
# ModSecurity selects the body processor based on the Content-Type request
# header. But clients are not always setting the Content-Type header for their
# request body payloads. This will leave ModSecurity with limited vision into
# the payload.  The variable tx.enforce_bodyproc_urlencoded lets you force the
# URLENCODED body processor in these situations. This is off by default, as it
# implies a change of the behaviour of ModSecurity beyond CRS (the body
# processor applies to all rules, not only CRS) and because it may lead to
................................................................................
   phase:1,\
   nolog,\
   pass,\
   t:none,\
   setvar:tx.enforce_bodyproc_urlencoded=1"


#
# -- [[ Anomaly Mode Severity Levels ]] ----------------------------------------
#
# Each rule in the CRS has an associated severity level.
# These are the default scoring points for each severity level.
# These settings will be used to increment the anomaly score if a rule matches.
# You may adjust these points to your liking, but this is usually not needed.
#
# - CRITICAL severity: Anomaly Score of 5.
#       Mostly generated by the application attack rules (93x and 94x files).
................................................................................
  t:none,\
  setvar:tx.critical_anomaly_score=5,\
  setvar:tx.error_anomaly_score=4,\
  setvar:tx.warning_anomaly_score=3,\
  setvar:tx.notice_anomaly_score=2"


#
# -- [[ Anomaly Mode Blocking Threshold Levels ]] ------------------------------
#
# Here, you can specify at which cumulative anomaly score an inbound request,
# or outbound response, gets blocked.
#
# Most detected inbound threats will give a critical score of 5.
# Smaller violations, like violations of protocol/standards, carry lower scores.
#
# [ At default value ]
................................................................................
  phase:1,\
  nolog,\
  pass,\
  t:none,\
  setvar:tx.inbound_anomaly_score_threshold=5,\
  setvar:tx.outbound_anomaly_score_threshold=4"

#
# -- [[ Application Specific Rule Exclusions ]] ----------------------------------------
#
# Some well-known applications may undertake actions that appear to be
# malicious. This includes actions such as allowing HTML or Javascript within
# parameters. In such cases the CRS aims to prevent false positives by allowing
# administrators to enable prebuilt, application specific exclusions on an
# application by application basis.
# These application specific exclusions are distinct from the rules that would
# be placed in the REQUEST-900-EXCLUSION-RULES-BEFORE-CRS configuration file as
................................................................................
  setvar:tx.crs_exclusions_cpanel=1,\
  setvar:tx.crs_exclusions_drupal=1,\
  setvar:tx.crs_exclusions_dokuwiki=1,\
  setvar:tx.crs_exclusions_nextcloud=1,\
  setvar:tx.crs_exclusions_wordpress=1,\
  setvar:tx.crs_exclusions_xenforo=1"

#
# -- [[ HTTP Policy Settings ]] ------------------------------------------------
#
# This section defines your policies for the HTTP protocol, such as:
# - allowed HTTP versions, HTTP methods, allowed request Content-Types
# - forbidden file extensions (e.g. .bak, .sql) and request headers (e.g. Proxy)
#
# These variables are used in the following rule files:
# - REQUEST-911-METHOD-ENFORCEMENT.conf
# - REQUEST-912-DOS-PROTECTION.conf
................................................................................
 "id:900280,\
  phase:1,\
  nolog,\
  pass,\
  t:none,\
  setvar:'tx.allowed_request_content_type_charset=utf-8|iso-8859-1|iso-8859-15|windows-1252'"

#
# -- [[ HTTP Argument/Upload Limits ]] -----------------------------------------
#
# Here you can define optional limits on HTTP get/post parameters and uploads.
# This can help to prevent application specific DoS attacks.
#
# These values are checked in REQUEST-920-PROTOCOL-ENFORCEMENT.conf.
# Beware of blocking legitimate traffic when enabling these limits.
#

................................................................................
  phase:1,\
  nolog,\
  pass,\
  t:none,\
  setvar:tx.combined_file_sizes=1048576"


#
# -- [[ Easing In / Sampling Percentage ]] -------------------------------------
#
# Adding the Core Rule Set to an existing productive site can lead to false
# positives, unexpected performance issues and other undesired side effects.
#
# It can be beneficial to test the water first by enabling the CRS for a
# limited number of requests only and then, when you have solved the issues (if
# any) and you have confidence in the setup, to raise the ratio of requests
# being sent into the ruleset.
................................................................................
SecAction "id:900400,\
  phase:1,\
  pass,\
  nolog,\
  setvar:tx.sampling_percentage=100"


#
# -- [[ Project Honey Pot HTTP Blacklist ]] ------------------------------------
#
# Optionally, you can check the client IP address against the Project Honey Pot
# HTTPBL (dnsbl.httpbl.org). In order to use this, you need to register to get a
# free API key. Set it here with SecHttpBlKey.
#
# Project Honeypot returns multiple different malicious IP types.
# You may specify which you want to block by enabling or disabling them below.
#
................................................................................
  t:none,\
  setvar:tx.block_search_ip=1,\
  setvar:tx.block_suspicious_ip=1,\
  setvar:tx.block_harvester_ip=1,\
  setvar:tx.block_spammer_ip=1"


#
# -- [[ GeoIP Database ]] ------------------------------------------------------
#
# There are some rulesets that inspect geolocation data of the client IP address
# (geoLookup). The CRS uses geoLookup to implement optional country blocking.
#
# To use geolocation, we make use of the MaxMind GeoIP database.
# This database is not included with the CRS and must be downloaded.
# You should also update the database regularly, for instance every month.
# The CRS contains a tool to download it to util/geo-location/GeoIP.dat:
................................................................................
  phase:1,\
  nolog,\
  pass,\
  t:none,\
  setvar:'tx.high_risk_country_codes='"


#
# -- [[ Anti-Automation / DoS Protection ]] ------------------------------------
#
# Optional DoS protection against clients making requests too quickly.
#
# When a client is making more than 100 requests (excluding static files) within
# 60 seconds, this is considered a 'burst'. After two bursts, the client is
# blocked for 600 seconds.
#
# Requests to static files are not counted towards DoS; they are listed in the
................................................................................
  pass,\
  t:none,\
  setvar:'tx.dos_burst_time_slice=60',\
  setvar:'tx.dos_counter_threshold=100',\
  setvar:'tx.dos_block_timeout=600'"


#
# -- [[ Check UTF-8 encoding ]] ------------------------------------------------
#
# The CRS can optionally check request contents for invalid UTF-8 encoding.
# We only want to apply this check if UTF-8 encoding is actually used by the
# site; otherwise it will result in false positives.
#
# Uncomment this rule to use this feature:
#
SecAction \
................................................................................
  phase:1,\
  nolog,\
  pass,\
  t:none,\
  setvar:tx.crs_validate_utf8_encoding=1"


#
# -- [[ Blocking Based on IP Reputation ]] ------------------------------------
#
# Blocking based on reputation is permanent in the CRS. Unlike other rules,
# which look at the indvidual request, the blocking of IPs is based on
# a persistent record in the IP collection, which remains active for a
# certain amount of time.
#
# There are two ways an individual client can become flagged for blocking:
# - External information (RBL, GeoIP, etc.)
................................................................................
  phase:1,\
  nolog,\
  pass,\
  t:none,\
  setvar:tx.reput_block_duration=300"


#
# -- [[ Collection timeout ]] --------------------------------------------------
#
# Set the SecCollectionTimeout directive from the ModSecurity default (1 hour)
# to a lower setting which is appropriate to most sites.
# This increases performance by cleaning out stale collection (block) entries.
#
# This value should be greater than or equal to:
# tx.reput_block_duration (see section "Blocking Based on IP Reputation") and
# tx.dos_block_timeout (see section "Anti-Automation / DoS Protection").
................................................................................
# Ref: https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual#wiki-SecCollectionTimeout

# Please keep this directive uncommented.
# Default: 600 (10 minutes)
SecCollectionTimeout 600


#
# -- [[ End of setup ]] --------------------------------------------------------
#
# The CRS checks the tx.crs_setup_version variable to ensure that the setup
# has been loaded. If you are not planning to use this setup template,
# you must manually set the tx.crs_setup_version variable before including
# the CRS rules/* files.
#
# The variable is a numerical representation of the CRS version number.
# E.g., v3.0.0 is represented as 300.







<
<
<












<
<
<







 







<
<







 







<
<
<







 







<
<
<







 







<
<
<







 







<
<
<







 







<
<
<







 







|
<
<







 







|
<
<







 







<
<
<







 







|
<
<







 







|
<
<







 







<
<
<







 







|
<
<







 







<
<
<







 







|
<
<







 







<
<
<







37
38
39
40
41
42
43



44
45
46
47
48
49
50
51
52
53
54
55



56
57
58
59
60
61
62
..
72
73
74
75
76
77
78


79
80
81
82
83
84
85
...
148
149
150
151
152
153
154



155
156
157
158
159
160
161
...
226
227
228
229
230
231
232



233
234
235
236
237
238
239
...
247
248
249
250
251
252
253



254
255
256
257
258
259
260
...
280
281
282
283
284
285
286



287
288
289
290
291
292
293
...
326
327
328
329
330
331
332



333
334
335
336
337
338
339
...
367
368
369
370
371
372
373
374


375
376
377
378
379
380
381
...
471
472
473
474
475
476
477
478


479
480
481
482
483
484
485
...
552
553
554
555
556
557
558



559
560
561
562
563
564
565
...
586
587
588
589
590
591
592
593


594
595
596
597
598
599
600
...
611
612
613
614
615
616
617
618


619
620
621
622
623
624
625
...
661
662
663
664
665
666
667



668
669
670
671
672
673
674
...
686
687
688
689
690
691
692
693


694
695
696
697
698
699
700
...
702
703
704
705
706
707
708



709
710
711
712
713
714
715
...
749
750
751
752
753
754
755
756


757
758
759
760
761
762
763
...
765
766
767
768
769
770
771



772
773
774
775
776
777
778
#
# The OWASP ModSecurity Core Rule Set is distributed under
# Apache Software License (ASL) version 2
# Please see the enclosed LICENSE file for full details.
# ------------------------------------------------------------------------





# The OWASP ModSecurity Core Rule Set (CRS) is a set of generic attack
# detection rules that provide a base level of protection for any web
# application. They are written for the open source, cross-platform
# ModSecurity Web Application Firewall.
#
# See also:
# https://coreruleset.org/
# https://github.com/SpiderLabs/owasp-modsecurity-crs
# https://www.owasp.org/index.php/Category:OWASP_ModSecurity_Core_Rule_Set_Project
#





# CRS requires ModSecurity version 2.8.0 or above.
# We recommend to always use the newest ModSecurity version.
#
# The configuration directives/settings in this file are used to control
# the OWASP ModSecurity CRS. These settings do **NOT** configure the main
# ModSecurity settings (modsecurity.conf) such as SecRuleEngine,
# SecRequestBodyAccess, SecAuditEngine, SecDebugLog, and XML processing.
................................................................................
# 3. rules/*.conf (the CRS rule files)
#
# Please refer to the INSTALL file for detailed installation instructions.
#


#


# The CRS can run in two modes:
#
# -- [[ Anomaly Scoring Mode (default) ]] --
# In CRS3, anomaly mode is the default and recommended mode, since it gives the
# most accurate log information and offers the most flexibility in setting your
# blocking policies. It is also called "collaborative detection mode".
# In this mode, each matching rule increases an 'anomaly score'.
................................................................................
#   if a Cookie or User-Agent header is blocked, it will also be blocked when
#   the client subsequently tries to access the homepage. You can also redirect
#   to another custom URL.
# SecDefaultAction "phase:1,log,auditlog,redirect:'http://%{request_headers.host}/',tag:'Host: %{request_headers.host}'"
# SecDefaultAction "phase:2,log,auditlog,redirect:'http://%{request_headers.host}/',tag:'Host: %{request_headers.host}'"





# The Paranoia Level (PL) setting allows you to choose the desired level
# of rule checks that will add to your anomaly scores.
#
# With each paranoia level increase, the CRS enables additional rules
# giving you a higher level of security. However, higher paranoia levels
# also increase the possibility of blocking some legitimate traffic due to
# false alarms (also named false positives or FPs). If you use higher
................................................................................
   phase:1,\
   nolog,\
   pass,\
   t:none,\
   setvar:tx.executing_paranoia_level=1"





# ModSecurity selects the body processor based on the Content-Type request
# header. But clients are not always setting the Content-Type header for their
# request body payloads. This will leave ModSecurity with limited vision into
# the payload.  The variable tx.enforce_bodyproc_urlencoded lets you force the
# URLENCODED body processor in these situations. This is off by default, as it
# implies a change of the behaviour of ModSecurity beyond CRS (the body
# processor applies to all rules, not only CRS) and because it may lead to
................................................................................
   phase:1,\
   nolog,\
   pass,\
   t:none,\
   setvar:tx.enforce_bodyproc_urlencoded=1"





# Each rule in the CRS has an associated severity level.
# These are the default scoring points for each severity level.
# These settings will be used to increment the anomaly score if a rule matches.
# You may adjust these points to your liking, but this is usually not needed.
#
# - CRITICAL severity: Anomaly Score of 5.
#       Mostly generated by the application attack rules (93x and 94x files).
................................................................................
  t:none,\
  setvar:tx.critical_anomaly_score=5,\
  setvar:tx.error_anomaly_score=4,\
  setvar:tx.warning_anomaly_score=3,\
  setvar:tx.notice_anomaly_score=2"





# Here, you can specify at which cumulative anomaly score an inbound request,
# or outbound response, gets blocked.
#
# Most detected inbound threats will give a critical score of 5.
# Smaller violations, like violations of protocol/standards, carry lower scores.
#
# [ At default value ]
................................................................................
  phase:1,\
  nolog,\
  pass,\
  t:none,\
  setvar:tx.inbound_anomaly_score_threshold=5,\
  setvar:tx.outbound_anomaly_score_threshold=4"




# Some well-known applications may undertake actions that appear to be
# malicious. This includes actions such as allowing HTML or Javascript within
# parameters. In such cases the CRS aims to prevent false positives by allowing
# administrators to enable prebuilt, application specific exclusions on an
# application by application basis.
# These application specific exclusions are distinct from the rules that would
# be placed in the REQUEST-900-EXCLUSION-RULES-BEFORE-CRS configuration file as
................................................................................
  setvar:tx.crs_exclusions_cpanel=1,\
  setvar:tx.crs_exclusions_drupal=1,\
  setvar:tx.crs_exclusions_dokuwiki=1,\
  setvar:tx.crs_exclusions_nextcloud=1,\
  setvar:tx.crs_exclusions_wordpress=1,\
  setvar:tx.crs_exclusions_xenforo=1"




# This section defines your policies for the HTTP protocol, such as:
# - allowed HTTP versions, HTTP methods, allowed request Content-Types
# - forbidden file extensions (e.g. .bak, .sql) and request headers (e.g. Proxy)
#
# These variables are used in the following rule files:
# - REQUEST-911-METHOD-ENFORCEMENT.conf
# - REQUEST-912-DOS-PROTECTION.conf
................................................................................
 "id:900280,\
  phase:1,\
  nolog,\
  pass,\
  t:none,\
  setvar:'tx.allowed_request_content_type_charset=utf-8|iso-8859-1|iso-8859-15|windows-1252'"




# Here you can define optional limits on HTTP get/post parameters and uploads.
# This can help to prevent application specific DoS attacks.
#
# These values are checked in REQUEST-920-PROTOCOL-ENFORCEMENT.conf.
# Beware of blocking legitimate traffic when enabling these limits.
#

................................................................................
  phase:1,\
  nolog,\
  pass,\
  t:none,\
  setvar:tx.combined_file_sizes=1048576"





# Adding the Core Rule Set to an existing productive site can lead to false
# positives, unexpected performance issues and other undesired side effects.
#
# It can be beneficial to test the water first by enabling the CRS for a
# limited number of requests only and then, when you have solved the issues (if
# any) and you have confidence in the setup, to raise the ratio of requests
# being sent into the ruleset.
................................................................................
SecAction "id:900400,\
  phase:1,\
  pass,\
  nolog,\
  setvar:tx.sampling_percentage=100"





# Optionally, you can check the client IP address against the Project Honey Pot
# HTTPBL (dnsbl.httpbl.org). In order to use this, you need to register to get a
# free API key. Set it here with SecHttpBlKey.
#
# Project Honeypot returns multiple different malicious IP types.
# You may specify which you want to block by enabling or disabling them below.
#
................................................................................
  t:none,\
  setvar:tx.block_search_ip=1,\
  setvar:tx.block_suspicious_ip=1,\
  setvar:tx.block_harvester_ip=1,\
  setvar:tx.block_spammer_ip=1"





# There are some rulesets that inspect geolocation data of the client IP address
# (geoLookup). The CRS uses geoLookup to implement optional country blocking.
#
# To use geolocation, we make use of the MaxMind GeoIP database.
# This database is not included with the CRS and must be downloaded.
# You should also update the database regularly, for instance every month.
# The CRS contains a tool to download it to util/geo-location/GeoIP.dat:
................................................................................
  phase:1,\
  nolog,\
  pass,\
  t:none,\
  setvar:'tx.high_risk_country_codes='"





# Optional DoS protection against clients making requests too quickly.
#
# When a client is making more than 100 requests (excluding static files) within
# 60 seconds, this is considered a 'burst'. After two bursts, the client is
# blocked for 600 seconds.
#
# Requests to static files are not counted towards DoS; they are listed in the
................................................................................
  pass,\
  t:none,\
  setvar:'tx.dos_burst_time_slice=60',\
  setvar:'tx.dos_counter_threshold=100',\
  setvar:'tx.dos_block_timeout=600'"





# The CRS can optionally check request contents for invalid UTF-8 encoding.
# We only want to apply this check if UTF-8 encoding is actually used by the
# site; otherwise it will result in false positives.
#
# Uncomment this rule to use this feature:
#
SecAction \
................................................................................
  phase:1,\
  nolog,\
  pass,\
  t:none,\
  setvar:tx.crs_validate_utf8_encoding=1"





# Blocking based on reputation is permanent in the CRS. Unlike other rules,
# which look at the indvidual request, the blocking of IPs is based on
# a persistent record in the IP collection, which remains active for a
# certain amount of time.
#
# There are two ways an individual client can become flagged for blocking:
# - External information (RBL, GeoIP, etc.)
................................................................................
  phase:1,\
  nolog,\
  pass,\
  t:none,\
  setvar:tx.reput_block_duration=300"





# Set the SecCollectionTimeout directive from the ModSecurity default (1 hour)
# to a lower setting which is appropriate to most sites.
# This increases performance by cleaning out stale collection (block) entries.
#
# This value should be greater than or equal to:
# tx.reput_block_duration (see section "Blocking Based on IP Reputation") and
# tx.dos_block_timeout (see section "Anti-Automation / DoS Protection").
................................................................................
# Ref: https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual#wiki-SecCollectionTimeout

# Please keep this directive uncommented.
# Default: 600 (10 minutes)
SecCollectionTimeout 600





# The CRS checks the tx.crs_setup_version variable to ensure that the setup
# has been loaded. If you are not planning to use this setup template,
# you must manually set the tx.crs_setup_version variable before including
# the CRS rules/* files.
#
# The variable is a numerical representation of the CRS version number.
# E.g., v3.0.0 is represented as 300.

Changes to dev/crsvars2pmd.py.

41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

56
57
58
59
60
61
62
63
64

65
66
67
68
69
70
71
72
73
74
75
76
77
            "type": "str",
            "value": val.strip(","), #  โ† let's keep default values here (might strip it in dialog)
            "help": doc
        }
    
        if re.search("anomaly_score|paranoia_level", var):
            p["type"] = "select"
            p["select"] = "0|1|2|3|4|5"
        if var == "id"
            p["type"] = "select"
            p["select"] = "5999|900999"
        elif re.match("^[01]$", val):
            p["type"] = "bool"
        elif len(p["value"]) >= 50:
            p["type"] = "text"


        pmd1[p["name"]] = p
  


# postprocess
for name,p in pmd1.items():
    if "select" in p:
        k = p["select"].split("|")

        p["select"] = dict(zip(k,k))
    

    
#std
#print(json.dumps(pmd, indent=4))

# write as ordereddict
print("setvar = OrderedDict()")
for k,d in pmd1.items():
    print(f"setvar['{k}'] = " + json.dumps(d, indent=4))

#print(len(pmd2))







|
|

|
|



>








|
>
|












41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
            "type": "str",
            "value": val.strip(","), #  โ† let's keep default values here (might strip it in dialog)
            "help": doc
        }
    
        if re.search("anomaly_score|paranoia_level", var):
            p["type"] = "select"
            p["select"] = "0=0 (off)|1=1 (standard)|2=2 (extended)|3=3 (excessive)|4=4 (banking sector)|5=5 (absurd)"
        if var == "id":
            p["type"] = "select"
            p["select"] = "5999=5999|900999=900999"
        elif re.search("tx\.(block_|crs_excl|enforce_|do_|crs_validate)", var): # re.match("^[01]$", val) or re
            p["type"] = "bool"
        elif len(p["value"]) >= 50:
            p["type"] = "text"
            

        pmd1[p["name"]] = p
  


# postprocess
for name,p in pmd1.items():
    if "select" in p:
        kv = p["select"].split("|")
        kv = [v.split("=", 2) for v in kv]
        p["select"] = dict(kv)
    

    
#std
#print(json.dumps(pmd, indent=4))

# write as ordereddict
print("setvar = OrderedDict()")
for k,d in pmd1.items():
    print(f"setvar['{k}'] = " + json.dumps(d, indent=4))

#print(len(pmd2))

Changes to modseccfg/__init__.py.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# encoding: utf-8
# api: python
# type: init
# title: modseccfg
# description: Editor to tame mod_security rulesets
# version: 0.2.0
# state:   prototype
# support: none
# license: ASL
# depends: python:pysimplegui (>= 3.0), python:pluginconf (>= 0.7.2),
#     python:appdirs (>= 1.3), python (>= 3.6), deb:python3-tk, bin:sshfs
# priority: core
# url: https://fossil.include-once.org/modseccfg/
# faq: https://fossil.include-once.org/modseccfg/doc/trunk/FAQ.md
# category: config
# classifiers: x11, http
#





|



|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# encoding: utf-8
# api: python
# type: init
# title: modseccfg
# description: Editor to tame mod_security rulesets
# version: 0.3.0
# state:   prototype
# support: none
# license: ASL
# depends: python:pysimplegui (>= 3.0), python:pluginconf (>= 0.7.3),
#     python:appdirs (>= 1.3), python (>= 3.6), deb:python3-tk, bin:sshfs
# priority: core
# url: https://fossil.include-once.org/modseccfg/
# faq: https://fossil.include-once.org/modseccfg/doc/trunk/FAQ.md
# category: config
# classifiers: x11, http
#

Changes to modseccfg/crsoptions.py.

4
5
6
7
8
9
10

11
12
13
14
15
16
17
..
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

44
45
46
47
48

49
50
51
52
53
54
55
..
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
...
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
...
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
...
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514

515
516
517
518
519
520
521
522
523
524



525
526
527
528
529
530
531
532
533
# category: config
# title: CRS options
# description: config window for CoreRuleSet setvar flags
# version: 0.1
# depends: pluginconf (>= 0.7.3)
# config:
#    { name: crsopt_defaults, type: bool, value: 0, description: "Use defaults in place of existing *.conf options" }

# license: ASL
# author: OWASP CRS team (options and descriptions)
#
# Basically like SecOptions, but for CRS options (from crs-setup.conf).
# But this module will not replace them, but inject a combined SecAction,
# which overrides all variables in one swoop.
#
................................................................................
import re, json, os, copy
from collections import OrderedDict
import pluginconf.gui
from modseccfg import utils, writer, vhosts, icons
from modseccfg.utils import srvroot


# autoconverted via dev/crsvars2pmd.py
setvar = OrderedDict()
setvar['id'] = {
    "id": "5999",
    "name": "id",
    "description": "Override variables early (5999) or inject after crs-setup (900999)",
    "type": "select",
    "value": "5999",

    "select": {
        "5999": "5999",
        "900999": "900999",
    },
    "help": "Override variables early (5999) or inject after crs-setup (900999)\nYou want to use 9009999 if you update the global crs-setup.conf.\nBut if you need different settings for different vhosts, then\nkeep crs-setup.conf disabled, and create individual setup files.\n(This could probably be automated in the dialog. And ideally, we'd\nuse skipAfter= or something in conjunction for the override scheme.)"

}
setvar['fn'] = {
    "id": "5998",
    "name": "fn",
    "description": "Which *.conf file to write back to.",
    "type": "str",
    "value": "/etc/modsecurty/crs/crs-setup.conf",
................................................................................
}
setvar['tx.paranoia_level'] = {
    "id": "900000",
    "name": "tx.paranoia_level",
    "description": "The Paranoia Level (PL) setting allows you to choose the desired level",
    "type": "select",
    "value": "1",
    "help": "-- [[ Paranoia Level Initialization ]] ---------------------------------------\nThe Paranoia Level (PL) setting allows you to choose the desired level\nof rule checks that will add to your anomaly scores.\nWith each paranoia level increase, the CRS enables additional rules\ngiving you a higher level of security. However, higher paranoia levels\nalso increase the possibility of blocking some legitimate traffic due to\nfalse alarms (also named false positives or FPs). If you use higher\nparanoia levels, it is likely that you will need to add some exclusion\nrules for certain requests and applications receiving complex input.\n- A paranoia level of 1 is default. In this level, most core rules\nare enabled. PL1 is advised for beginners, installations\ncovering many different sites and applications, and for setups\nwith standard security requirements.\nAt PL1 you should face FPs rarely. If you encounter FPs, please\nopen an issue on the CRS GitHub site and don't forget to attach your\ncomplete Audit Log record for the request with the issue.\n- Paranoia level 2 includes many extra rules, for instance enabling\nmany regexp-based SQL and XSS injection protections, and adding\nextra keywords checked for code injections. PL2 is advised\nfor moderate to experienced users desiring more complete coverage\nand for installations with elevated security requirements.\nPL2 comes with some FPs which you need to handle.\n- Paranoia level 3 enables more rules and keyword lists, and tweaks\nlimits on special characters used. PL3 is aimed at users experienced\nat the handling of FPs and at installations with a high security\nrequirement.\n- Paranoia level 4 further restricts special characters.\nThe highest level is advised for experienced users protecting\ninstallations with very high security requirements. Running PL4 will\nlikely produce a very high number of FPs which have to be\ntreated before the site can go productive.\nRules in paranoia level 2 or higher will log their PL to the audit log;\nexample: [tag \"paranoia-level/2\"]. This allows you to deduct from the\naudit log how the WAF behavior is affected by paranoia level.\nIt is important to also look into the variable\ntx.enforce_bodyproc_urlencoded (Enforce Body Processor URLENCODED)\ndefined below. Enabling it closes a possible bypass of CRS.\nUncomment this rule to change the default:",
    "select": {
        "0": "0",
        "1": "1",
        "2": "2",
        "3": "3",
        "4": "4",
        "5": "5"
    }
}
setvar['tx.executing_paranoia_level'] = {
    "id": "900001",
    "name": "tx.executing_paranoia_level",
    "description": "It is possible to execute rules from a higher paranoia level but not include",
    "type": "select",
    "value": "1",
    "help": "It is possible to execute rules from a higher paranoia level but not include\nthem in the anomaly scoring. This allows you to take a well-tuned system on\nparanoia level 1 and add rules from paranoia level 2 without having to fear\nthe new rules would lead to false positives that raise your score above the\nthreshold.\nThis optional feature is enabled by uncommenting the following rule and\nsetting the tx.executing_paranoia_level.\nTechnically, rules up to the level defined in tx.executing_paranoia_level\nwill be executed, but only the rules up to tx.paranoia_level affect the\nanomaly scores.\nBy default, tx.executing_paranoia_level is set to tx.paranoia_level.\ntx.executing_paranoia_level must not be lower than tx.paranoia_level.\nPlease notice that setting tx.executing_paranoia_level to a higher paranoia\nlevel results in a performance impact that is equally high as setting\ntx.paranoia_level to said level.",
    "select": {
        "0": "0",
        "1": "1",
        "2": "2",
        "3": "3",
        "4": "4",
        "5": "5"
    }
}
setvar['tx.enforce_bodyproc_urlencoded'] = {
    "id": "900010",
    "name": "tx.enforce_bodyproc_urlencoded",
    "description": "ModSecurity selects the body processor based on the Content-Type request",
    "type": "bool",
    "value": "1",
    "help": "-- [[ Enforce Body Processor URLENCODED ]] -----------------------------------\nModSecurity selects the body processor based on the Content-Type request\nheader. But clients are not always setting the Content-Type header for their\nrequest body payloads. This will leave ModSecurity with limited vision into\nthe payload.  The variable tx.enforce_bodyproc_urlencoded lets you force the\nURLENCODED body processor in these situations. This is off by default, as it\nimplies a change of the behaviour of ModSecurity beyond CRS (the body\nprocessor applies to all rules, not only CRS) and because it may lead to\nfalse positives already on paranoia level 1. However, enabling this variable\ncloses a possible bypass of CRS so it should be considered.\nUncomment this rule to change the default:"
}
setvar['tx.critical_anomaly_score'] = {
    "id": "900100",
    "name": "tx.critical_anomaly_score",
    "description": "Each rule in the CRS has an associated severity level.",
    "type": "select",
    "value": "5",
    "help": "-- [[ Anomaly Mode Severity Levels ]] ----------------------------------------\nEach rule in the CRS has an associated severity level.\nThese are the default scoring points for each severity level.\nThese settings will be used to increment the anomaly score if a rule matches.\nYou may adjust these points to your liking, but this is usually not needed.\n- CRITICAL severity: Anomaly Score of 5.\nMostly generated by the application attack rules (93x and 94x files).\n- ERROR severity: Anomaly Score of 4.\nGenerated mostly from outbound leakage rules (95x files).\n- WARNING severity: Anomaly Score of 3.\nGenerated mostly by malicious client rules (91x files).\n- NOTICE severity: Anomaly Score of 2.\nGenerated mostly by the protocol rules (92x files).\nIn anomaly mode, these scores are cumulative.\nSo it's possible for a request to hit multiple rules.\n(Note: In this file, we use 'phase:1' to set CRS configuration variables.\nIn general, 'phase:request' is used. However, we want to make absolutely sure\nthat all configuration variables are set before the CRS rules are processed.)",
    "select": {
        "0": "0",
        "1": "1",
        "2": "2",
        "3": "3",
        "4": "4",
        "5": "5"
    }
}
setvar['tx.error_anomaly_score'] = {
    "id": "900100",
    "name": "tx.error_anomaly_score",
    "description": "Each rule in the CRS has an associated severity level.",
    "type": "select",
    "value": "4",
    "help": "-- [[ Anomaly Mode Severity Levels ]] ----------------------------------------\nEach rule in the CRS has an associated severity level.\nThese are the default scoring points for each severity level.\nThese settings will be used to increment the anomaly score if a rule matches.\nYou may adjust these points to your liking, but this is usually not needed.\n- CRITICAL severity: Anomaly Score of 5.\nMostly generated by the application attack rules (93x and 94x files).\n- ERROR severity: Anomaly Score of 4.\nGenerated mostly from outbound leakage rules (95x files).\n- WARNING severity: Anomaly Score of 3.\nGenerated mostly by malicious client rules (91x files).\n- NOTICE severity: Anomaly Score of 2.\nGenerated mostly by the protocol rules (92x files).\nIn anomaly mode, these scores are cumulative.\nSo it's possible for a request to hit multiple rules.\n(Note: In this file, we use 'phase:1' to set CRS configuration variables.\nIn general, 'phase:request' is used. However, we want to make absolutely sure\nthat all configuration variables are set before the CRS rules are processed.)",
    "select": {
        "0": "0",
        "1": "1",
        "2": "2",
        "3": "3",
        "4": "4",
        "5": "5"
    }
}
setvar['tx.warning_anomaly_score'] = {
    "id": "900100",
    "name": "tx.warning_anomaly_score",
    "description": "Each rule in the CRS has an associated severity level.",
    "type": "select",
    "value": "3",
    "help": "-- [[ Anomaly Mode Severity Levels ]] ----------------------------------------\nEach rule in the CRS has an associated severity level.\nThese are the default scoring points for each severity level.\nThese settings will be used to increment the anomaly score if a rule matches.\nYou may adjust these points to your liking, but this is usually not needed.\n- CRITICAL severity: Anomaly Score of 5.\nMostly generated by the application attack rules (93x and 94x files).\n- ERROR severity: Anomaly Score of 4.\nGenerated mostly from outbound leakage rules (95x files).\n- WARNING severity: Anomaly Score of 3.\nGenerated mostly by malicious client rules (91x files).\n- NOTICE severity: Anomaly Score of 2.\nGenerated mostly by the protocol rules (92x files).\nIn anomaly mode, these scores are cumulative.\nSo it's possible for a request to hit multiple rules.\n(Note: In this file, we use 'phase:1' to set CRS configuration variables.\nIn general, 'phase:request' is used. However, we want to make absolutely sure\nthat all configuration variables are set before the CRS rules are processed.)",
    "select": {
        "0": "0",
        "1": "1",
        "2": "2",
        "3": "3",
        "4": "4",
        "5": "5"
    }
}
setvar['tx.notice_anomaly_score'] = {
    "id": "900100",
    "name": "tx.notice_anomaly_score",
    "description": "Each rule in the CRS has an associated severity level.",
    "type": "select",
    "value": "2",
    "help": "-- [[ Anomaly Mode Severity Levels ]] ----------------------------------------\nEach rule in the CRS has an associated severity level.\nThese are the default scoring points for each severity level.\nThese settings will be used to increment the anomaly score if a rule matches.\nYou may adjust these points to your liking, but this is usually not needed.\n- CRITICAL severity: Anomaly Score of 5.\nMostly generated by the application attack rules (93x and 94x files).\n- ERROR severity: Anomaly Score of 4.\nGenerated mostly from outbound leakage rules (95x files).\n- WARNING severity: Anomaly Score of 3.\nGenerated mostly by malicious client rules (91x files).\n- NOTICE severity: Anomaly Score of 2.\nGenerated mostly by the protocol rules (92x files).\nIn anomaly mode, these scores are cumulative.\nSo it's possible for a request to hit multiple rules.\n(Note: In this file, we use 'phase:1' to set CRS configuration variables.\nIn general, 'phase:request' is used. However, we want to make absolutely sure\nthat all configuration variables are set before the CRS rules are processed.)",
    "select": {
        "0": "0",
        "1": "1",
        "2": "2",
        "3": "3",
        "4": "4",
        "5": "5"
    }
}
setvar['tx.inbound_anomaly_score_threshold'] = {
    "id": "900110",
    "name": "tx.inbound_anomaly_score_threshold",
    "description": "Here, you can specify at which cumulative anomaly score an inbound request,",
    "type": "select",
    "value": "5",
    "help": "-- [[ Anomaly Mode Blocking Threshold Levels ]] ------------------------------\nHere, you can specify at which cumulative anomaly score an inbound request,\nor outbound response, gets blocked.\nMost detected inbound threats will give a critical score of 5.\nSmaller violations, like violations of protocol/standards, carry lower scores.\n[ At default value ]\nIf you keep the blocking thresholds at the defaults, the CRS will work\nsimilarly to previous CRS versions: a single critical rule match will cause\nthe request to be blocked and logged.\n[ Using higher values ]\nIf you want to make the CRS less sensitive, you can increase the blocking\nthresholds, for instance to 7 (which would require multiple rule matches\nbefore blocking) or 10 (which would require at least two critical alerts - or\na combination of many lesser alerts), or even higher. However, increasing the\nthresholds might cause some attacks to bypass the CRS rules or your policies.\n[ New deployment strategy: Starting high and decreasing ]\nIt is a common practice to start a fresh CRS installation with elevated\nanomaly scoring thresholds (>100) and then lower the limits as your\nconfidence in the setup grows. You may also look into the Sampling\nPercentage section below for a different strategy to ease into a new\nCRS installation.\n[ Anomaly Threshold / Paranoia Level Quadrant ]\nHigh Anomaly Limit   |   High Anomaly Limit\nLow Paranoia Level   |   High Paranoia Level\n-> Fresh Site        |   -> Experimental Site\n------------------------------------------------------\nLow Anomaly Limit    |   Low Anomaly Limit\nLow Paranoia Level   |   High Paranoia Level\n-> Standard Site     |   -> High Security Site\nUncomment this rule to change the defaults:",
    "select": {
        "0": "0",
        "1": "1",
        "2": "2",
        "3": "3",
        "4": "4",
        "5": "5"
    }
}
setvar['tx.outbound_anomaly_score_threshold'] = {
    "id": "900110",
    "name": "tx.outbound_anomaly_score_threshold",
    "description": "Here, you can specify at which cumulative anomaly score an inbound request,",
    "type": "select",
    "value": "4",
    "help": "-- [[ Anomaly Mode Blocking Threshold Levels ]] ------------------------------\nHere, you can specify at which cumulative anomaly score an inbound request,\nor outbound response, gets blocked.\nMost detected inbound threats will give a critical score of 5.\nSmaller violations, like violations of protocol/standards, carry lower scores.\n[ At default value ]\nIf you keep the blocking thresholds at the defaults, the CRS will work\nsimilarly to previous CRS versions: a single critical rule match will cause\nthe request to be blocked and logged.\n[ Using higher values ]\nIf you want to make the CRS less sensitive, you can increase the blocking\nthresholds, for instance to 7 (which would require multiple rule matches\nbefore blocking) or 10 (which would require at least two critical alerts - or\na combination of many lesser alerts), or even higher. However, increasing the\nthresholds might cause some attacks to bypass the CRS rules or your policies.\n[ New deployment strategy: Starting high and decreasing ]\nIt is a common practice to start a fresh CRS installation with elevated\nanomaly scoring thresholds (>100) and then lower the limits as your\nconfidence in the setup grows. You may also look into the Sampling\nPercentage section below for a different strategy to ease into a new\nCRS installation.\n[ Anomaly Threshold / Paranoia Level Quadrant ]\nHigh Anomaly Limit   |   High Anomaly Limit\nLow Paranoia Level   |   High Paranoia Level\n-> Fresh Site        |   -> Experimental Site\n------------------------------------------------------\nLow Anomaly Limit    |   Low Anomaly Limit\nLow Paranoia Level   |   High Paranoia Level\n-> Standard Site     |   -> High Security Site\nUncomment this rule to change the defaults:",
    "select": {
        "0": "0",
        "1": "1",
        "2": "2",
        "3": "3",
        "4": "4",
        "5": "5"
    }
}
setvar['tx.crs_exclusions_cpanel'] = {
    "id": "900130",
    "name": "tx.crs_exclusions_cpanel",
    "description": "Modify and uncomment this rule to select which application:",
    "type": "str",
    "value": "1",
    "help": "Modify and uncomment this rule to select which application:"
}
setvar['tx.crs_exclusions_drupal'] = {
    "id": "900130",
    "name": "tx.crs_exclusions_drupal",
    "description": "Modify and uncomment this rule to select which application:",
    "type": "str",
    "value": "1",
    "help": "Modify and uncomment this rule to select which application:"
}
setvar['tx.crs_exclusions_dokuwiki'] = {
    "id": "900130",
    "name": "tx.crs_exclusions_dokuwiki",
    "description": "Modify and uncomment this rule to select which application:",
    "type": "str",
    "value": "1",
    "help": "Modify and uncomment this rule to select which application:"
}
setvar['tx.crs_exclusions_nextcloud'] = {
    "id": "900130",
    "name": "tx.crs_exclusions_nextcloud",
    "description": "Modify and uncomment this rule to select which application:",
    "type": "str",
    "value": "1",
    "help": "Modify and uncomment this rule to select which application:"
}
setvar['tx.crs_exclusions_wordpress'] = {
    "id": "900130",
    "name": "tx.crs_exclusions_wordpress",
    "description": "Modify and uncomment this rule to select which application:",
    "type": "str",
    "value": "1",
    "help": "Modify and uncomment this rule to select which application:"
}
setvar['tx.crs_exclusions_xenforo'] = {
    "id": "900130",
    "name": "tx.crs_exclusions_xenforo",
    "description": "Modify and uncomment this rule to select which application:",
................................................................................
}
setvar['tx.sampling_percentage'] = {
    "id": "900400",
    "name": "tx.sampling_percentage",
    "description": "Adding the Core Rule Set to an existing productive site can lead to false",
    "type": "str",
    "value": "100",
    "help": "-- [[ Easing In / Sampling Percentage ]] -------------------------------------\nAdding the Core Rule Set to an existing productive site can lead to false\npositives, unexpected performance issues and other undesired side effects.\nIt can be beneficial to test the water first by enabling the CRS for a\nlimited number of requests only and then, when you have solved the issues (if\nany) and you have confidence in the setup, to raise the ratio of requests\nbeing sent into the ruleset.\nAdjust the percentage of requests that are funnelled into the Core Rules by\nsetting TX.sampling_percentage below. The default is 100, meaning that every\nrequest gets checked by the CRS.  The selection of requests, which are going\nto be checked, is based on a pseudo random number generated by ModSecurity.\nIf a request is allowed to pass without being checked by the CRS, there is no\nentry in the audit log (for performance reasons), but an error log entry is\nwritten.  If you want to disable the error log entry, then issue the\nfollowing directive somewhere after the inclusion of the CRS\n(E.g., RESPONSE-999-EXCEPTIONS.conf).\nSecRuleUpdateActionById 901150 \"nolog\"\nATTENTION: If this TX.sampling_percentage is below 100, then some of the\nrequests will bypass the Core Rules completely and you lose the ability to\nprotect your service with ModSecurity.\nUncomment this rule to enable this feature:"
}
setvar['tx.block_search_ip'] = {
    "id": "900500",
    "name": "tx.block_search_ip",
    "description": "Optionally, you can check the client IP address against the Project Honey Pot",
    "type": "str",
    "value": "1",
    "help": "-- [[ Project Honey Pot HTTP Blacklist ]] ------------------------------------\nOptionally, you can check the client IP address against the Project Honey Pot\nHTTPBL (dnsbl.httpbl.org). In order to use this, you need to register to get a\nfree API key. Set it here with SecHttpBlKey.\nProject Honeypot returns multiple different malicious IP types.\nYou may specify which you want to block by enabling or disabling them below.\nRef: https://www.projecthoneypot.org/httpbl.php\nRef: https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual#wiki-SecHttpBlKey\nUncomment these rules to use this feature:\n#SecHttpBlKey XXXXXXXXXXXXXXXXX"
}
setvar['tx.block_suspicious_ip'] = {
    "id": "900500",
    "name": "tx.block_suspicious_ip",
    "description": "Optionally, you can check the client IP address against the Project Honey Pot",
    "type": "str",
    "value": "1",
    "help": "-- [[ Project Honey Pot HTTP Blacklist ]] ------------------------------------\nOptionally, you can check the client IP address against the Project Honey Pot\nHTTPBL (dnsbl.httpbl.org). In order to use this, you need to register to get a\nfree API key. Set it here with SecHttpBlKey.\nProject Honeypot returns multiple different malicious IP types.\nYou may specify which you want to block by enabling or disabling them below.\nRef: https://www.projecthoneypot.org/httpbl.php\nRef: https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual#wiki-SecHttpBlKey\nUncomment these rules to use this feature:\n#SecHttpBlKey XXXXXXXXXXXXXXXXX"
}
setvar['tx.block_harvester_ip'] = {
    "id": "900500",
    "name": "tx.block_harvester_ip",
    "description": "Optionally, you can check the client IP address against the Project Honey Pot",
    "type": "str",
    "value": "1",
    "help": "-- [[ Project Honey Pot HTTP Blacklist ]] ------------------------------------\nOptionally, you can check the client IP address against the Project Honey Pot\nHTTPBL (dnsbl.httpbl.org). In order to use this, you need to register to get a\nfree API key. Set it here with SecHttpBlKey.\nProject Honeypot returns multiple different malicious IP types.\nYou may specify which you want to block by enabling or disabling them below.\nRef: https://www.projecthoneypot.org/httpbl.php\nRef: https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual#wiki-SecHttpBlKey\nUncomment these rules to use this feature:\n#SecHttpBlKey XXXXXXXXXXXXXXXXX"
}
setvar['tx.block_spammer_ip'] = {
    "id": "900500",
    "name": "tx.block_spammer_ip",
    "description": "Optionally, you can check the client IP address against the Project Honey Pot",
    "type": "bool",
    "value": "1",
    "help": "-- [[ Project Honey Pot HTTP Blacklist ]] ------------------------------------\nOptionally, you can check the client IP address against the Project Honey Pot\nHTTPBL (dnsbl.httpbl.org). In order to use this, you need to register to get a\nfree API key. Set it here with SecHttpBlKey.\nProject Honeypot returns multiple different malicious IP types.\nYou may specify which you want to block by enabling or disabling them below.\nRef: https://www.projecthoneypot.org/httpbl.php\nRef: https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual#wiki-SecHttpBlKey\nUncomment these rules to use this feature:\n#SecHttpBlKey XXXXXXXXXXXXXXXXX"
}
setvar['tx.dos_burst_time_slice'] = {
    "id": "900700",
    "name": "tx.dos_burst_time_slice",
    "description": "Optional DoS protection against clients making requests too quickly.",
    "type": "str",
    "value": "60",
    "help": "-- [[ Anti-Automation / DoS Protection ]] ------------------------------------\nOptional DoS protection against clients making requests too quickly.\nWhen a client is making more than 100 requests (excluding static files) within\n60 seconds, this is considered a 'burst'. After two bursts, the client is\nblocked for 600 seconds.\nRequests to static files are not counted towards DoS; they are listed in the\n'tx.static_extensions' setting, which you can change in this file (see\nsection \"HTTP Policy Settings\").\nFor a detailed description, see rule file REQUEST-912-DOS-PROTECTION.conf.\nUncomment this rule to use this feature:"
}
setvar['tx.dos_counter_threshold'] = {
    "id": "900700",
    "name": "tx.dos_counter_threshold",
    "description": "Optional DoS protection against clients making requests too quickly.",
    "type": "str",
    "value": "100",
    "help": "-- [[ Anti-Automation / DoS Protection ]] ------------------------------------\nOptional DoS protection against clients making requests too quickly.\nWhen a client is making more than 100 requests (excluding static files) within\n60 seconds, this is considered a 'burst'. After two bursts, the client is\nblocked for 600 seconds.\nRequests to static files are not counted towards DoS; they are listed in the\n'tx.static_extensions' setting, which you can change in this file (see\nsection \"HTTP Policy Settings\").\nFor a detailed description, see rule file REQUEST-912-DOS-PROTECTION.conf.\nUncomment this rule to use this feature:"
}
setvar['tx.dos_block_timeout'] = {
    "id": "900700",
    "name": "tx.dos_block_timeout",
    "description": "Optional DoS protection against clients making requests too quickly.",
    "type": "str",
    "value": "600",
    "help": "-- [[ Anti-Automation / DoS Protection ]] ------------------------------------\nOptional DoS protection against clients making requests too quickly.\nWhen a client is making more than 100 requests (excluding static files) within\n60 seconds, this is considered a 'burst'. After two bursts, the client is\nblocked for 600 seconds.\nRequests to static files are not counted towards DoS; they are listed in the\n'tx.static_extensions' setting, which you can change in this file (see\nsection \"HTTP Policy Settings\").\nFor a detailed description, see rule file REQUEST-912-DOS-PROTECTION.conf.\nUncomment this rule to use this feature:"
}
setvar['tx.crs_validate_utf8_encoding'] = {
    "id": "900950",
    "name": "tx.crs_validate_utf8_encoding",
    "description": "The CRS can optionally check request contents for invalid UTF-8 encoding.",
    "type": "bool",
    "value": "1",
    "help": "-- [[ Check UTF-8 encoding ]] ------------------------------------------------\nThe CRS can optionally check request contents for invalid UTF-8 encoding.\nWe only want to apply this check if UTF-8 encoding is actually used by the\nsite; otherwise it will result in false positives.\nUncomment this rule to use this feature:"
}
setvar['tx.do_reput_block'] = {
    "id": "900960",
    "name": "tx.do_reput_block",
    "description": "Blocking based on reputation is permanent in the CRS. Unlike other rules,",
    "type": "bool",
    "value": "1",
    "help": "-- [[ Blocking Based on IP Reputation ]] ------------------------------------\nBlocking based on reputation is permanent in the CRS. Unlike other rules,\nwhich look at the indvidual request, the blocking of IPs is based on\na persistent record in the IP collection, which remains active for a\ncertain amount of time.\nThere are two ways an individual client can become flagged for blocking:\n- External information (RBL, GeoIP, etc.)\n- Internal information (Core Rules)\nThe record in the IP collection carries a flag, which tags requests from\nindividual clients with a flag named IP.reput_block_flag.\nBut the flag alone is not enough to have a client blocked. There is also\na global switch named tx.do_reput_block. This is off by default. If you set\nit to 1 (=On), requests from clients with the IP.reput_block_flag will\nbe blocked for a certain duration.\nVariables\nip.reput_block_flag      Blocking flag for the IP collection record\nip.reput_block_reason    Reason (= rule message) that caused to blocking flag\ntx.do_reput_block        Switch deciding if we really block based on flag\ntx.reput_block_duration  Setting to define the duration of a block\nIt may be important to know, that all the other core rules are skipped for\nrequests, when it is clear that they carry the blocking flag in question.\nUncomment this rule to use this feature:"
}
setvar['tx.reput_block_duration'] = {
    "id": "900970",
    "name": "tx.reput_block_duration",
    "description": "Uncomment this rule to change the blocking time:",
    "type": "str",
    "value": "300",
................................................................................
    plugins = {}
    groups = [
        ["global", "module", "CoreRuleSet variables", "Update CRS setvars in\n", "^id|^fn|tx\.paranoia|executing|sampling|score_threshold"],
        ["allow", "allowdeny", "Allowed/Restricted", "White and blacklist some HTTP parameters", "allowed|restricted|urlencoded|static_ext"],
        ["args", "args", "Arguments", "GET and POST parameter restrictions", "args|arg_|file_size|utf8"],
        ["excl", "exclusion", "Exclusions", "Some rules to skip (this should have been tags, but here we are)", "exclusions"],
        ["class", "classification", "Paranoia level classification", "Assign default levels", "anomaly_score(?!_threshold$)"],
        ["else", "setvar:else", "Other flags", "Less common options", "-"]
    ]
    """
        "name": "tx.block_search_ip",
        "name": "tx.block_suspicious_ip",
        "name": "tx.block_harvester_ip",
        "name": "tx.block_spammer_ip",
        "name": "tx.dos_burst_time_slice",
................................................................................
                conf[k] = ""
    prev = copy.copy(conf)

    # show
    save = pluginconf.gui.window(
        conf, plugin_states, files=[], plugins=plugins,
        title="mod_security option directives", icon=icons.crs,
        opt_label=True, size=(700,800)
    )
    if not save:
        return
        
    # id,fn
    id = conf["id"]
    confn = conf["fn"]
    del conf["id"], conf["fn"]
    
    # combine into SecRule
    act = []

    for k,v in conf.items():
        #print(k, " := ", repr(v), type(v), repr(prev.get(k)), type(prev.get(k)))
        if v in (None, "\n", "", prev.get(k)):
            continue
        elif type(v) is bool:
            v = "1" if v else "0"
        if re.search("^\\w+$", v):
            act.append(f"setvar:{k}={v}")
        else:
            act.append(f"setvar:'{k}={v.strip()}'")



    act = ",".join(act)
    secrule = f"""SecAction "id:{id},pass,nolog,noauditlog,t:none,{act}"\n"""
    print(secrule)
    
    # prepare update
    replace_rx = re.compile(f"""     # just โ†“ in case user picks a different secrule id
        ^[\ \t]*   SecAction   \s+   \"id:({id}|5999|900999),[^"]+\"   .*\\n
    """, re.X|re.M)








>







 







|







>


|
<
<
>







 







|

|
|
|
|
|
|










|
|
|
|
|
|








|







|

|
|
|
|
|
|








|

|
|
|
|
|
|








|

|
|
|
|
|
|








|

|
|
|
|
|
|








|

|
|
|
|
|
|








|

|
|
|
|
|
|






|







|







|







|







|







 







|





|

|





|

|





|

|







|







|







|







|







|







|







 







|







 







|





|





>










>
>
>
|
|







4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
..
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48


49
50
51
52
53
54
55
56
..
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
...
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
...
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
...
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
# category: config
# title: CRS options
# description: config window for CoreRuleSet setvar flags
# version: 0.1
# depends: pluginconf (>= 0.7.3)
# config:
#    { name: crsopt_defaults, type: bool, value: 0, description: "Use defaults in place of existing *.conf options" }
#    { name: crsopt_undefine, type: bool, value: 1, description: "Undefine previous config rules per setvar" }
# license: ASL
# author: OWASP CRS team (options and descriptions)
#
# Basically like SecOptions, but for CRS options (from crs-setup.conf).
# But this module will not replace them, but inject a combined SecAction,
# which overrides all variables in one swoop.
#
................................................................................
import re, json, os, copy
from collections import OrderedDict
import pluginconf.gui
from modseccfg import utils, writer, vhosts, icons
from modseccfg.utils import srvroot


# autoconverted via `dev/crsvars2pmd.py`
setvar = OrderedDict()
setvar['id'] = {
    "id": "5999",
    "name": "id",
    "description": "Override variables early (5999) or inject after crs-setup (900999)",
    "type": "select",
    "value": "5999",
    "help": "Override variables early (5999) or inject after crs-setup (900999)\nYou want to use 9009999 if you update the global crs-setup.conf.\nBut if you need different settings for different vhosts, then\nkeep crs-setup.conf disabled, and create individual setup files.\n(This could probably be automated in the dialog. And ideally, we'd\nuse skipAfter= or something in conjunction for the override scheme.)",
    "select": {
        "5999": "5999",
        "900999": "900999"


    }
}
setvar['fn'] = {
    "id": "5998",
    "name": "fn",
    "description": "Which *.conf file to write back to.",
    "type": "str",
    "value": "/etc/modsecurty/crs/crs-setup.conf",
................................................................................
}
setvar['tx.paranoia_level'] = {
    "id": "900000",
    "name": "tx.paranoia_level",
    "description": "The Paranoia Level (PL) setting allows you to choose the desired level",
    "type": "select",
    "value": "1",
    "help": "The Paranoia Level (PL) setting allows you to choose the desired level\nof rule checks that will add to your anomaly scores.\nWith each paranoia level increase, the CRS enables additional rules\ngiving you a higher level of security. However, higher paranoia levels\nalso increase the possibility of blocking some legitimate traffic due to\nfalse alarms (also named false positives or FPs). If you use higher\nparanoia levels, it is likely that you will need to add some exclusion\nrules for certain requests and applications receiving complex input.\n- A paranoia level of 1 is default. In this level, most core rules\nare enabled. PL1 is advised for beginners, installations\ncovering many different sites and applications, and for setups\nwith standard security requirements.\nAt PL1 you should face FPs rarely. If you encounter FPs, please\nopen an issue on the CRS GitHub site and don't forget to attach your\ncomplete Audit Log record for the request with the issue.\n- Paranoia level 2 includes many extra rules, for instance enabling\nmany regexp-based SQL and XSS injection protections, and adding\nextra keywords checked for code injections. PL2 is advised\nfor moderate to experienced users desiring more complete coverage\nand for installations with elevated security requirements.\nPL2 comes with some FPs which you need to handle.\n- Paranoia level 3 enables more rules and keyword lists, and tweaks\nlimits on special characters used. PL3 is aimed at users experienced\nat the handling of FPs and at installations with a high security\nrequirement.\n- Paranoia level 4 further restricts special characters.\nThe highest level is advised for experienced users protecting\ninstallations with very high security requirements. Running PL4 will\nlikely produce a very high number of FPs which have to be\ntreated before the site can go productive.\nRules in paranoia level 2 or higher will log their PL to the audit log;\nexample: [tag \"paranoia-level/2\"]. This allows you to deduct from the\naudit log how the WAF behavior is affected by paranoia level.\nIt is important to also look into the variable\ntx.enforce_bodyproc_urlencoded (Enforce Body Processor URLENCODED)\ndefined below. Enabling it closes a possible bypass of CRS.\nUncomment this rule to change the default:",
    "select": {
        "0": "0 (off)",
        "1": "1 (standard)",
        "2": "2 (extended)",
        "3": "3 (excessive)",
        "4": "4 (banking sector)",
        "5": "5 (absurd)"
    }
}
setvar['tx.executing_paranoia_level'] = {
    "id": "900001",
    "name": "tx.executing_paranoia_level",
    "description": "It is possible to execute rules from a higher paranoia level but not include",
    "type": "select",
    "value": "1",
    "help": "It is possible to execute rules from a higher paranoia level but not include\nthem in the anomaly scoring. This allows you to take a well-tuned system on\nparanoia level 1 and add rules from paranoia level 2 without having to fear\nthe new rules would lead to false positives that raise your score above the\nthreshold.\nThis optional feature is enabled by uncommenting the following rule and\nsetting the tx.executing_paranoia_level.\nTechnically, rules up to the level defined in tx.executing_paranoia_level\nwill be executed, but only the rules up to tx.paranoia_level affect the\nanomaly scores.\nBy default, tx.executing_paranoia_level is set to tx.paranoia_level.\ntx.executing_paranoia_level must not be lower than tx.paranoia_level.\nPlease notice that setting tx.executing_paranoia_level to a higher paranoia\nlevel results in a performance impact that is equally high as setting\ntx.paranoia_level to said level.",
    "select": {
        "0": "0 (off)",
        "1": "1 (standard)",
        "2": "2 (extended)",
        "3": "3 (excessive)",
        "4": "4 (banking sector)",
        "5": "5 (absurd)"
    }
}
setvar['tx.enforce_bodyproc_urlencoded'] = {
    "id": "900010",
    "name": "tx.enforce_bodyproc_urlencoded",
    "description": "ModSecurity selects the body processor based on the Content-Type request",
    "type": "bool",
    "value": "1",
    "help": "ModSecurity selects the body processor based on the Content-Type request\nheader. But clients are not always setting the Content-Type header for their\nrequest body payloads. This will leave ModSecurity with limited vision into\nthe payload.  The variable tx.enforce_bodyproc_urlencoded lets you force the\nURLENCODED body processor in these situations. This is off by default, as it\nimplies a change of the behaviour of ModSecurity beyond CRS (the body\nprocessor applies to all rules, not only CRS) and because it may lead to\nfalse positives already on paranoia level 1. However, enabling this variable\ncloses a possible bypass of CRS so it should be considered.\nUncomment this rule to change the default:"
}
setvar['tx.critical_anomaly_score'] = {
    "id": "900100",
    "name": "tx.critical_anomaly_score",
    "description": "Each rule in the CRS has an associated severity level.",
    "type": "select",
    "value": "5",
    "help": "Each rule in the CRS has an associated severity level.\nThese are the default scoring points for each severity level.\nThese settings will be used to increment the anomaly score if a rule matches.\nYou may adjust these points to your liking, but this is usually not needed.\n- CRITICAL severity: Anomaly Score of 5.\nMostly generated by the application attack rules (93x and 94x files).\n- ERROR severity: Anomaly Score of 4.\nGenerated mostly from outbound leakage rules (95x files).\n- WARNING severity: Anomaly Score of 3.\nGenerated mostly by malicious client rules (91x files).\n- NOTICE severity: Anomaly Score of 2.\nGenerated mostly by the protocol rules (92x files).\nIn anomaly mode, these scores are cumulative.\nSo it's possible for a request to hit multiple rules.\n(Note: In this file, we use 'phase:1' to set CRS configuration variables.\nIn general, 'phase:request' is used. However, we want to make absolutely sure\nthat all configuration variables are set before the CRS rules are processed.)",
    "select": {
        "0": "0 (off)",
        "1": "1 (standard)",
        "2": "2 (extended)",
        "3": "3 (excessive)",
        "4": "4 (banking sector)",
        "5": "5 (absurd)"
    }
}
setvar['tx.error_anomaly_score'] = {
    "id": "900100",
    "name": "tx.error_anomaly_score",
    "description": "Each rule in the CRS has an associated severity level.",
    "type": "select",
    "value": "4",
    "help": "Each rule in the CRS has an associated severity level.\nThese are the default scoring points for each severity level.\nThese settings will be used to increment the anomaly score if a rule matches.\nYou may adjust these points to your liking, but this is usually not needed.\n- CRITICAL severity: Anomaly Score of 5.\nMostly generated by the application attack rules (93x and 94x files).\n- ERROR severity: Anomaly Score of 4.\nGenerated mostly from outbound leakage rules (95x files).\n- WARNING severity: Anomaly Score of 3.\nGenerated mostly by malicious client rules (91x files).\n- NOTICE severity: Anomaly Score of 2.\nGenerated mostly by the protocol rules (92x files).\nIn anomaly mode, these scores are cumulative.\nSo it's possible for a request to hit multiple rules.\n(Note: In this file, we use 'phase:1' to set CRS configuration variables.\nIn general, 'phase:request' is used. However, we want to make absolutely sure\nthat all configuration variables are set before the CRS rules are processed.)",
    "select": {
        "0": "0 (off)",
        "1": "1 (standard)",
        "2": "2 (extended)",
        "3": "3 (excessive)",
        "4": "4 (banking sector)",
        "5": "5 (absurd)"
    }
}
setvar['tx.warning_anomaly_score'] = {
    "id": "900100",
    "name": "tx.warning_anomaly_score",
    "description": "Each rule in the CRS has an associated severity level.",
    "type": "select",
    "value": "3",
    "help": "Each rule in the CRS has an associated severity level.\nThese are the default scoring points for each severity level.\nThese settings will be used to increment the anomaly score if a rule matches.\nYou may adjust these points to your liking, but this is usually not needed.\n- CRITICAL severity: Anomaly Score of 5.\nMostly generated by the application attack rules (93x and 94x files).\n- ERROR severity: Anomaly Score of 4.\nGenerated mostly from outbound leakage rules (95x files).\n- WARNING severity: Anomaly Score of 3.\nGenerated mostly by malicious client rules (91x files).\n- NOTICE severity: Anomaly Score of 2.\nGenerated mostly by the protocol rules (92x files).\nIn anomaly mode, these scores are cumulative.\nSo it's possible for a request to hit multiple rules.\n(Note: In this file, we use 'phase:1' to set CRS configuration variables.\nIn general, 'phase:request' is used. However, we want to make absolutely sure\nthat all configuration variables are set before the CRS rules are processed.)",
    "select": {
        "0": "0 (off)",
        "1": "1 (standard)",
        "2": "2 (extended)",
        "3": "3 (excessive)",
        "4": "4 (banking sector)",
        "5": "5 (absurd)"
    }
}
setvar['tx.notice_anomaly_score'] = {
    "id": "900100",
    "name": "tx.notice_anomaly_score",
    "description": "Each rule in the CRS has an associated severity level.",
    "type": "select",
    "value": "2",
    "help": "Each rule in the CRS has an associated severity level.\nThese are the default scoring points for each severity level.\nThese settings will be used to increment the anomaly score if a rule matches.\nYou may adjust these points to your liking, but this is usually not needed.\n- CRITICAL severity: Anomaly Score of 5.\nMostly generated by the application attack rules (93x and 94x files).\n- ERROR severity: Anomaly Score of 4.\nGenerated mostly from outbound leakage rules (95x files).\n- WARNING severity: Anomaly Score of 3.\nGenerated mostly by malicious client rules (91x files).\n- NOTICE severity: Anomaly Score of 2.\nGenerated mostly by the protocol rules (92x files).\nIn anomaly mode, these scores are cumulative.\nSo it's possible for a request to hit multiple rules.\n(Note: In this file, we use 'phase:1' to set CRS configuration variables.\nIn general, 'phase:request' is used. However, we want to make absolutely sure\nthat all configuration variables are set before the CRS rules are processed.)",
    "select": {
        "0": "0 (off)",
        "1": "1 (standard)",
        "2": "2 (extended)",
        "3": "3 (excessive)",
        "4": "4 (banking sector)",
        "5": "5 (absurd)"
    }
}
setvar['tx.inbound_anomaly_score_threshold'] = {
    "id": "900110",
    "name": "tx.inbound_anomaly_score_threshold",
    "description": "Here, you can specify at which cumulative anomaly score an inbound request,",
    "type": "select",
    "value": "5",
    "help": "Here, you can specify at which cumulative anomaly score an inbound request,\nor outbound response, gets blocked.\nMost detected inbound threats will give a critical score of 5.\nSmaller violations, like violations of protocol/standards, carry lower scores.\n[ At default value ]\nIf you keep the blocking thresholds at the defaults, the CRS will work\nsimilarly to previous CRS versions: a single critical rule match will cause\nthe request to be blocked and logged.\n[ Using higher values ]\nIf you want to make the CRS less sensitive, you can increase the blocking\nthresholds, for instance to 7 (which would require multiple rule matches\nbefore blocking) or 10 (which would require at least two critical alerts - or\na combination of many lesser alerts), or even higher. However, increasing the\nthresholds might cause some attacks to bypass the CRS rules or your policies.\n[ New deployment strategy: Starting high and decreasing ]\nIt is a common practice to start a fresh CRS installation with elevated\nanomaly scoring thresholds (>100) and then lower the limits as your\nconfidence in the setup grows. You may also look into the Sampling\nPercentage section below for a different strategy to ease into a new\nCRS installation.\n[ Anomaly Threshold / Paranoia Level Quadrant ]\nHigh Anomaly Limit   |   High Anomaly Limit\nLow Paranoia Level   |   High Paranoia Level\n-> Fresh Site        |   -> Experimental Site\n------------------------------------------------------\nLow Anomaly Limit    |   Low Anomaly Limit\nLow Paranoia Level   |   High Paranoia Level\n-> Standard Site     |   -> High Security Site\nUncomment this rule to change the defaults:",
    "select": {
        "0": "0 (off)",
        "1": "1 (standard)",
        "2": "2 (extended)",
        "3": "3 (excessive)",
        "4": "4 (banking sector)",
        "5": "5 (absurd)"
    }
}
setvar['tx.outbound_anomaly_score_threshold'] = {
    "id": "900110",
    "name": "tx.outbound_anomaly_score_threshold",
    "description": "Here, you can specify at which cumulative anomaly score an inbound request,",
    "type": "select",
    "value": "4",
    "help": "Here, you can specify at which cumulative anomaly score an inbound request,\nor outbound response, gets blocked.\nMost detected inbound threats will give a critical score of 5.\nSmaller violations, like violations of protocol/standards, carry lower scores.\n[ At default value ]\nIf you keep the blocking thresholds at the defaults, the CRS will work\nsimilarly to previous CRS versions: a single critical rule match will cause\nthe request to be blocked and logged.\n[ Using higher values ]\nIf you want to make the CRS less sensitive, you can increase the blocking\nthresholds, for instance to 7 (which would require multiple rule matches\nbefore blocking) or 10 (which would require at least two critical alerts - or\na combination of many lesser alerts), or even higher. However, increasing the\nthresholds might cause some attacks to bypass the CRS rules or your policies.\n[ New deployment strategy: Starting high and decreasing ]\nIt is a common practice to start a fresh CRS installation with elevated\nanomaly scoring thresholds (>100) and then lower the limits as your\nconfidence in the setup grows. You may also look into the Sampling\nPercentage section below for a different strategy to ease into a new\nCRS installation.\n[ Anomaly Threshold / Paranoia Level Quadrant ]\nHigh Anomaly Limit   |   High Anomaly Limit\nLow Paranoia Level   |   High Paranoia Level\n-> Fresh Site        |   -> Experimental Site\n------------------------------------------------------\nLow Anomaly Limit    |   Low Anomaly Limit\nLow Paranoia Level   |   High Paranoia Level\n-> Standard Site     |   -> High Security Site\nUncomment this rule to change the defaults:",
    "select": {
        "0": "0 (off)",
        "1": "1 (standard)",
        "2": "2 (extended)",
        "3": "3 (excessive)",
        "4": "4 (banking sector)",
        "5": "5 (absurd)"
    }
}
setvar['tx.crs_exclusions_cpanel'] = {
    "id": "900130",
    "name": "tx.crs_exclusions_cpanel",
    "description": "Modify and uncomment this rule to select which application:",
    "type": "bool",
    "value": "1",
    "help": "Modify and uncomment this rule to select which application:"
}
setvar['tx.crs_exclusions_drupal'] = {
    "id": "900130",
    "name": "tx.crs_exclusions_drupal",
    "description": "Modify and uncomment this rule to select which application:",
    "type": "bool",
    "value": "1",
    "help": "Modify and uncomment this rule to select which application:"
}
setvar['tx.crs_exclusions_dokuwiki'] = {
    "id": "900130",
    "name": "tx.crs_exclusions_dokuwiki",
    "description": "Modify and uncomment this rule to select which application:",
    "type": "bool",
    "value": "1",
    "help": "Modify and uncomment this rule to select which application:"
}
setvar['tx.crs_exclusions_nextcloud'] = {
    "id": "900130",
    "name": "tx.crs_exclusions_nextcloud",
    "description": "Modify and uncomment this rule to select which application:",
    "type": "bool",
    "value": "1",
    "help": "Modify and uncomment this rule to select which application:"
}
setvar['tx.crs_exclusions_wordpress'] = {
    "id": "900130",
    "name": "tx.crs_exclusions_wordpress",
    "description": "Modify and uncomment this rule to select which application:",
    "type": "bool",
    "value": "1",
    "help": "Modify and uncomment this rule to select which application:"
}
setvar['tx.crs_exclusions_xenforo'] = {
    "id": "900130",
    "name": "tx.crs_exclusions_xenforo",
    "description": "Modify and uncomment this rule to select which application:",
................................................................................
}
setvar['tx.sampling_percentage'] = {
    "id": "900400",
    "name": "tx.sampling_percentage",
    "description": "Adding the Core Rule Set to an existing productive site can lead to false",
    "type": "str",
    "value": "100",
    "help": "Adding the Core Rule Set to an existing productive site can lead to false\npositives, unexpected performance issues and other undesired side effects.\nIt can be beneficial to test the water first by enabling the CRS for a\nlimited number of requests only and then, when you have solved the issues (if\nany) and you have confidence in the setup, to raise the ratio of requests\nbeing sent into the ruleset.\nAdjust the percentage of requests that are funnelled into the Core Rules by\nsetting TX.sampling_percentage below. The default is 100, meaning that every\nrequest gets checked by the CRS.  The selection of requests, which are going\nto be checked, is based on a pseudo random number generated by ModSecurity.\nIf a request is allowed to pass without being checked by the CRS, there is no\nentry in the audit log (for performance reasons), but an error log entry is\nwritten.  If you want to disable the error log entry, then issue the\nfollowing directive somewhere after the inclusion of the CRS\n(E.g., RESPONSE-999-EXCEPTIONS.conf).\nSecRuleUpdateActionById 901150 \"nolog\"\nATTENTION: If this TX.sampling_percentage is below 100, then some of the\nrequests will bypass the Core Rules completely and you lose the ability to\nprotect your service with ModSecurity.\nUncomment this rule to enable this feature:"
}
setvar['tx.block_search_ip'] = {
    "id": "900500",
    "name": "tx.block_search_ip",
    "description": "Optionally, you can check the client IP address against the Project Honey Pot",
    "type": "bool",
    "value": "1",
    "help": "Optionally, you can check the client IP address against the Project Honey Pot\nHTTPBL (dnsbl.httpbl.org). In order to use this, you need to register to get a\nfree API key. Set it here with SecHttpBlKey.\nProject Honeypot returns multiple different malicious IP types.\nYou may specify which you want to block by enabling or disabling them below.\nRef: https://www.projecthoneypot.org/httpbl.php\nRef: https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual#wiki-SecHttpBlKey\nUncomment these rules to use this feature:\n#SecHttpBlKey XXXXXXXXXXXXXXXXX"
}
setvar['tx.block_suspicious_ip'] = {
    "id": "900500",
    "name": "tx.block_suspicious_ip",
    "description": "Optionally, you can check the client IP address against the Project Honey Pot",
    "type": "bool",
    "value": "1",
    "help": "Optionally, you can check the client IP address against the Project Honey Pot\nHTTPBL (dnsbl.httpbl.org). In order to use this, you need to register to get a\nfree API key. Set it here with SecHttpBlKey.\nProject Honeypot returns multiple different malicious IP types.\nYou may specify which you want to block by enabling or disabling them below.\nRef: https://www.projecthoneypot.org/httpbl.php\nRef: https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual#wiki-SecHttpBlKey\nUncomment these rules to use this feature:\n#SecHttpBlKey XXXXXXXXXXXXXXXXX"
}
setvar['tx.block_harvester_ip'] = {
    "id": "900500",
    "name": "tx.block_harvester_ip",
    "description": "Optionally, you can check the client IP address against the Project Honey Pot",
    "type": "bool",
    "value": "1",
    "help": "Optionally, you can check the client IP address against the Project Honey Pot\nHTTPBL (dnsbl.httpbl.org). In order to use this, you need to register to get a\nfree API key. Set it here with SecHttpBlKey.\nProject Honeypot returns multiple different malicious IP types.\nYou may specify which you want to block by enabling or disabling them below.\nRef: https://www.projecthoneypot.org/httpbl.php\nRef: https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual#wiki-SecHttpBlKey\nUncomment these rules to use this feature:\n#SecHttpBlKey XXXXXXXXXXXXXXXXX"
}
setvar['tx.block_spammer_ip'] = {
    "id": "900500",
    "name": "tx.block_spammer_ip",
    "description": "Optionally, you can check the client IP address against the Project Honey Pot",
    "type": "bool",
    "value": "1",
    "help": "Optionally, you can check the client IP address against the Project Honey Pot\nHTTPBL (dnsbl.httpbl.org). In order to use this, you need to register to get a\nfree API key. Set it here with SecHttpBlKey.\nProject Honeypot returns multiple different malicious IP types.\nYou may specify which you want to block by enabling or disabling them below.\nRef: https://www.projecthoneypot.org/httpbl.php\nRef: https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual#wiki-SecHttpBlKey\nUncomment these rules to use this feature:\n#SecHttpBlKey XXXXXXXXXXXXXXXXX"
}
setvar['tx.dos_burst_time_slice'] = {
    "id": "900700",
    "name": "tx.dos_burst_time_slice",
    "description": "Optional DoS protection against clients making requests too quickly.",
    "type": "str",
    "value": "60",
    "help": "Optional DoS protection against clients making requests too quickly.\nWhen a client is making more than 100 requests (excluding static files) within\n60 seconds, this is considered a 'burst'. After two bursts, the client is\nblocked for 600 seconds.\nRequests to static files are not counted towards DoS; they are listed in the\n'tx.static_extensions' setting, which you can change in this file (see\nsection \"HTTP Policy Settings\").\nFor a detailed description, see rule file REQUEST-912-DOS-PROTECTION.conf.\nUncomment this rule to use this feature:"
}
setvar['tx.dos_counter_threshold'] = {
    "id": "900700",
    "name": "tx.dos_counter_threshold",
    "description": "Optional DoS protection against clients making requests too quickly.",
    "type": "str",
    "value": "100",
    "help": "Optional DoS protection against clients making requests too quickly.\nWhen a client is making more than 100 requests (excluding static files) within\n60 seconds, this is considered a 'burst'. After two bursts, the client is\nblocked for 600 seconds.\nRequests to static files are not counted towards DoS; they are listed in the\n'tx.static_extensions' setting, which you can change in this file (see\nsection \"HTTP Policy Settings\").\nFor a detailed description, see rule file REQUEST-912-DOS-PROTECTION.conf.\nUncomment this rule to use this feature:"
}
setvar['tx.dos_block_timeout'] = {
    "id": "900700",
    "name": "tx.dos_block_timeout",
    "description": "Optional DoS protection against clients making requests too quickly.",
    "type": "str",
    "value": "600",
    "help": "Optional DoS protection against clients making requests too quickly.\nWhen a client is making more than 100 requests (excluding static files) within\n60 seconds, this is considered a 'burst'. After two bursts, the client is\nblocked for 600 seconds.\nRequests to static files are not counted towards DoS; they are listed in the\n'tx.static_extensions' setting, which you can change in this file (see\nsection \"HTTP Policy Settings\").\nFor a detailed description, see rule file REQUEST-912-DOS-PROTECTION.conf.\nUncomment this rule to use this feature:"
}
setvar['tx.crs_validate_utf8_encoding'] = {
    "id": "900950",
    "name": "tx.crs_validate_utf8_encoding",
    "description": "The CRS can optionally check request contents for invalid UTF-8 encoding.",
    "type": "bool",
    "value": "1",
    "help": "The CRS can optionally check request contents for invalid UTF-8 encoding.\nWe only want to apply this check if UTF-8 encoding is actually used by the\nsite; otherwise it will result in false positives.\nUncomment this rule to use this feature:"
}
setvar['tx.do_reput_block'] = {
    "id": "900960",
    "name": "tx.do_reput_block",
    "description": "Blocking based on reputation is permanent in the CRS. Unlike other rules,",
    "type": "bool",
    "value": "1",
    "help": "Blocking based on reputation is permanent in the CRS. Unlike other rules,\nwhich look at the indvidual request, the blocking of IPs is based on\na persistent record in the IP collection, which remains active for a\ncertain amount of time.\nThere are two ways an individual client can become flagged for blocking:\n- External information (RBL, GeoIP, etc.)\n- Internal information (Core Rules)\nThe record in the IP collection carries a flag, which tags requests from\nindividual clients with a flag named IP.reput_block_flag.\nBut the flag alone is not enough to have a client blocked. There is also\na global switch named tx.do_reput_block. This is off by default. If you set\nit to 1 (=On), requests from clients with the IP.reput_block_flag will\nbe blocked for a certain duration.\nVariables\nip.reput_block_flag      Blocking flag for the IP collection record\nip.reput_block_reason    Reason (= rule message) that caused to blocking flag\ntx.do_reput_block        Switch deciding if we really block based on flag\ntx.reput_block_duration  Setting to define the duration of a block\nIt may be important to know, that all the other core rules are skipped for\nrequests, when it is clear that they carry the blocking flag in question.\nUncomment this rule to use this feature:"
}
setvar['tx.reput_block_duration'] = {
    "id": "900970",
    "name": "tx.reput_block_duration",
    "description": "Uncomment this rule to change the blocking time:",
    "type": "str",
    "value": "300",
................................................................................
    plugins = {}
    groups = [
        ["global", "module", "CoreRuleSet variables", "Update CRS setvars in\n", "^id|^fn|tx\.paranoia|executing|sampling|score_threshold"],
        ["allow", "allowdeny", "Allowed/Restricted", "White and blacklist some HTTP parameters", "allowed|restricted|urlencoded|static_ext"],
        ["args", "args", "Arguments", "GET and POST parameter restrictions", "args|arg_|file_size|utf8"],
        ["excl", "exclusion", "Exclusions", "Some rules to skip (this should have been tags, but here we are)", "exclusions"],
        ["class", "classification", "Paranoia level classification", "Assign default levels", "anomaly_score(?!_threshold$)"],
        ["else", "setvar:else", "Other flags", "RBL blocking and DOS protection", "-"]
    ]
    """
        "name": "tx.block_search_ip",
        "name": "tx.block_suspicious_ip",
        "name": "tx.block_harvester_ip",
        "name": "tx.block_spammer_ip",
        "name": "tx.dos_burst_time_slice",
................................................................................
                conf[k] = ""
    prev = copy.copy(conf)

    # show
    save = pluginconf.gui.window(
        conf, plugin_states, files=[], plugins=plugins,
        title="mod_security option directives", icon=icons.crs,
        opt_label=True, size=(710,770)
    )
    if not save:
        return
        
    # id,fn
    id = int(conf["id"])
    confn = conf["fn"]
    del conf["id"], conf["fn"]
    
    # combine into SecRule
    act = []
    rem_id = []
    for k,v in conf.items():
        #print(k, " := ", repr(v), type(v), repr(prev.get(k)), type(prev.get(k)))
        if v in (None, "\n", "", prev.get(k)):
            continue
        elif type(v) is bool:
            v = "1" if v else "0"
        if re.search("^\\w+$", v):
            act.append(f"setvar:{k}={v}")
        else:
            act.append(f"setvar:'{k}={v.strip()}'")
        if utils.conf.get("crsopt_undefine") and id < 100000 and setvar.get(k,{}).get("id") and setvar[k]['id'] not in rem_id:
            act.append(f"   ctl:ruleRemoveById={setvar[k]['id']}")
            rem_id.append(setvar[k]['id'])
    act = ", \\\n    ".join(act)
    secrule = f"""SecAction "id:{id},pass,nolog,noauditlog,t:none, \\\n    {act}"\n"""
    print(secrule)
    
    # prepare update
    replace_rx = re.compile(f"""     # just โ†“ in case user picks a different secrule id
        ^[\ \t]*   SecAction   \s+   \"id:({id}|5999|900999),[^"]+\"   .*\\n
    """, re.X|re.M)

Changes to modseccfg/recipe.py.

7
8
9
10
11
12
13



14
15
16
17
18
19
20
..
39
40
41
42
43
44
45
















46
47
48
49
50
51
52
53
54
55
56
57
# category: config
# config:
#    { name: replace_rules, type: bool, value: 0, description: "try to find replacement spot, else just append" }
#
# Basically just blobs of text and an editor window.
# [Save] will append directives to selected vhost/*.conf file.
#





from modseccfg import utils, vhosts
import PySimpleGUI as sg
import re
from textwrap import dedent

................................................................................
        SecRuleRemoveById $id   #@wrap
      </FilesMatch>
    """
    
    exclude_parameter = """
       SecRuleUpdateTargetByID $id "!ARGS:param"
    """
















    
    macros = """
    <IfModule mod_alias.c>
      <Macro SecRuleRemoveByPath $id $path>
        SecRule REQUEST_URI "@eq $path" "id:%{md5:$id-$path},t:none,msg:'Whitelist $path',ctl:removeById=$id"
      </Macro>
    </IfModule>
    """

    @staticmethod
    def has(name):
        return hasattr(recipe, name)







>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>




|







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
..
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# category: config
# config:
#    { name: replace_rules, type: bool, value: 0, description: "try to find replacement spot, else just append" }
#
# Basically just blobs of text and an editor window.
# [Save] will append directives to selected vhost/*.conf file.
#
# Some samples from:
#  ยท https://wiki.atomicorp.com/wiki/index.php/Mod_security
#


from modseccfg import utils, vhosts
import PySimpleGUI as sg
import re
from textwrap import dedent

................................................................................
        SecRuleRemoveById $id   #@wrap
      </FilesMatch>
    """
    
    exclude_parameter = """
       SecRuleUpdateTargetByID $id "!ARGS:param"
    """
    
    rule_to_detectiononly = """
       SecRuleUpdateActionById $id "pass,status:200,log,auditlog"
    """

    url_to_detectiononly = """
       SecRule REQUEST_URI "$request_uri" "phase:1,id:$new_id,t:none,t:lowercase,pass,msg:'DetectionOnly for $request_uri',ctl:ruleEngine=DetectionOnly"
    """
    
    exempt_remote_addr = """
       SecRule REMOTE_ADDR "^\\Q$remote_addr\\E$" "phase:1,id:$new_id,t:none,nolog,allow,ctl:ruleEngine=Off,ctl:auditEngine=Off"
    """

    whitelist_file = """
       SecRule REMOTE_ADDR "@pmFromFile $confn.whitelist" "phase:1,id:$new_id,t:none,nolog,allow"
    """
    
    macros = """
    <IfModule mod_alias.c>
      <Macro SecRuleRemoveByPath $id $path>
        SecRule REQUEST_URI "@eq $request_uri" "id:$new_id,t:none,msg:'Whitelist $request_uri',ctl:removeById=$id"
      </Macro>
    </IfModule>
    """

    @staticmethod
    def has(name):
        return hasattr(recipe, name)