From de92065d22bfbd223548e1611770eba565f23a69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=2E=20Nam=C3=A8che?= Date: Thu, 8 Jan 2026 06:51:04 +0300 Subject: [PATCH] WIP --- ansible/roles/bgwaf/defaults/main.yml | 161 ++- ansible/roles/bgwaf/tasks/main.yml | 16 +- ansible/roles/bgwaf/templates/coraza.conf | 2 +- ansible/roles/bgwaf/templates/crs-setup.conf | 1045 ++++------------- .../templates/exclusions-request-before.conf | 3 + .../templates/exclusions-response-after.conf | 3 + ansible/roles/bgwaf/templates/exclusions.conf | 3 - ansible/vars.yml | 7 + 8 files changed, 413 insertions(+), 827 deletions(-) create mode 100644 ansible/roles/bgwaf/templates/exclusions-request-before.conf create mode 100644 ansible/roles/bgwaf/templates/exclusions-response-after.conf delete mode 100644 ansible/roles/bgwaf/templates/exclusions.conf diff --git a/ansible/roles/bgwaf/defaults/main.yml b/ansible/roles/bgwaf/defaults/main.yml index f7feca2..05ff2a9 100644 --- a/ansible/roles/bgwaf/defaults/main.yml +++ b/ansible/roles/bgwaf/defaults/main.yml @@ -54,10 +54,157 @@ bgwaf_sites: [] # - "" # after_response: # - "" -# redirect_from_aliases: true -# custom_cert: true -# custom_cert_file: "" -# custom_key_file: "" -# rate_events: 1000 -# rate_window: "1m" -# bot_barrier: false + +bgwaf_defaults: + redirect_from_aliases: true + custom_cert: true + custom_cert_file: "" + custom_key_file: "" + rate_events: 1000 + rate_window: "1m" + bot_barrier: false + log_only: true + paranoia_level: 1 + detection_paranoia_level: null + enforce_bodyproc_urlencoded: 1 + critical_anomaly_score: 5 + error_anomaly_score: 4 + warning_anomaly_score: 3 + notice_anomaly_score: 2 + inbound_anomaly_score_threshold: 5 + outbound_anomaly_score_threshold: 4 + reporting_level: 4 + max_num_args: 255 + arg_name_length: 100 + arg_length: 1000 + total_arg_length: 64000 + max_file_size: 10485760 # 10 Mo + combined_file_sizes: 20970520 # 20 Mo + sampling_percentage: 100 + allowed_methods: + - "GET" + - "HEAD" + - "POST" + - "OPTIONS" + allowed_request_content_type: + - "|application/x-www-form-urlencoded|" + - "|multipart/form-data|" + - "|text/xml|" + - "|application/xml|" + - "|application/soap+xml|" + - "|application/json|" + - "|application/reports+json|" + - "|application/csp-report|" + restricted_extensions: + - ".ani/" + - ".asa/" + - ".asax/" + - ".ascx/" + - ".backup/" + - ".bak/" + - ".bat/" + - ".cdx/" + - ".cer/" + - ".cfg/" + - ".cmd/" + - ".cnf/" + - ".com/" + - ".compositefont/" + - ".config/" + - ".conf/" + - ".copy/" + - ".crt/" + - ".cs/" + - ".csproj/" + - ".csr/" + - ".dat/" + - ".db/" + - ".dbf/" + - ".dist/" + - ".dll/" + - ".dos/" + - ".dpkg-dist/" + - ".drv/" + - ".gadget/" + - ".hta/" + - ".htr/" + - ".htw/" + - ".ida/" + - ".idc/" + - ".idq/" + - ".inc/" + - ".inf/" + - ".ini/" + - ".jse/" + - ".key/" + - ".licx/" + - ".lnk/" + - ".log/" + - ".mdb/" + - ".msc/" + - ".ocx/" + - ".old/" + - ".pass/" + - ".pdb/" + - ".pfx/" + - ".pif/" + - ".pem/" + - ".pol/" + - ".prf/" + - ".printer/" + - ".pwd/" + - ".rdb/" + - ".rdp/" + - ".reg/" + - ".resources/" + - ".resx/" + - ".save/" + - ".scr/" + - ".sct/" + - ".shs/" + - ".sql/" + - ".sqlite/" + - ".sqlite3/" + - ".swp/" + - ".sys/" + - ".temp/" + - ".tlb/" + - ".tmp/" + - ".vb/" + - ".vbe/" + - ".vbs/" + - ".vbproj/" + - ".vsdisco/" + - ".vxd/" + - ".webinfo/" + - ".ws/" + - ".wsc/" + - ".wsf/" + - ".wsh/" + - ".xsd/" + - ".xsx/" + restricted_headers_basic: + - "/content-encoding/" + - "/proxy/" + - "/lock-token/" + - "/content-range/" + - "/if/" + - "/x-http-method-override/" + - "/x-http-method/" + - "/x-method-override/" + - "/x-middleware-subrequest/" + - "/expect/" + allowed_http_versions: + - "HTTP/1.0" + - "HTTP/1.1" + - "HTTP/2" + - "HTTP/2.0" + - "HTTP/3" + - "HTTP/3.0" + restricted_headers_extended: + - "/accept-charset/" + allowed_request_content_type_charset: + - "|utf-8|" + - "|iso-8859-1|" + - "|iso-8859-15|" + - "|windows-1252|" diff --git a/ansible/roles/bgwaf/tasks/main.yml b/ansible/roles/bgwaf/tasks/main.yml index a301533..ddac5e5 100644 --- a/ansible/roles/bgwaf/tasks/main.yml +++ b/ansible/roles/bgwaf/tasks/main.yml @@ -145,11 +145,11 @@ - name: Generate sites exclusions before request file loop: "{{ bgwaf_sites }}" - vars: - bgwaf_site_exclusions: "{{ item.exceptions.before_request | default([]) }}" + loop_control: + loop_var: "site" ansible.builtin.template: - src: "templates/exclusions.conf" - dest: "/etc/caddy/sites/{{ item.name }}/exclusions-request-before.conf" + src: "templates/exclusions-request-before.conf" + dest: "/etc/caddy/sites/{{ site.name }}/exclusions-request-before.conf" group: "caddy" mode: "0640" notify: @@ -157,11 +157,11 @@ - name: Generate sites exclusions after response file loop: "{{ bgwaf_sites }}" - vars: - bgwaf_site_exclusions: "{{ item.exceptions.after_response | default([]) }}" + loop_control: + loop_var: "site" ansible.builtin.template: - src: "templates/exclusions.conf" - dest: "/etc/caddy/sites/{{ item.name }}/exclusions-response-after.conf" + src: "templates/exclusions-response-after.conf" + dest: "/etc/caddy/sites/{{ site.name }}/exclusions-response-after.conf" group: "caddy" mode: "0640" notify: diff --git a/ansible/roles/bgwaf/templates/coraza.conf b/ansible/roles/bgwaf/templates/coraza.conf index 373b268..cc30ae9 100644 --- a/ansible/roles/bgwaf/templates/coraza.conf +++ b/ansible/roles/bgwaf/templates/coraza.conf @@ -147,7 +147,7 @@ SecAuditLogType Serial # The format used to write the audit log. # Can be one of JSON|JsonLegacy|Native|OCSF -SecAuditLogFormat Native +SecAuditLogFormat JSON # The following settings are not supported by Coraza # SecCookieFormat 0 diff --git a/ansible/roles/bgwaf/templates/crs-setup.conf b/ansible/roles/bgwaf/templates/crs-setup.conf index c21d374..de776bf 100644 --- a/ansible/roles/bgwaf/templates/crs-setup.conf +++ b/ansible/roles/bgwaf/templates/crs-setup.conf @@ -1,849 +1,288 @@ -# ------------------------------------------------------------------------ -# OWASP CRS ver.4.20.0 -# Copyright (c) 2006-2020 Trustwave and contributors. All rights reserved. -# Copyright (c) 2021-2025 CRS project. All rights reserved. -# -# The OWASP CRS is distributed under -# Apache Software License (ASL) version 2 -# Please see the enclosed LICENSE file for full details. -# ------------------------------------------------------------------------ - - -# -# -- [[ Introduction ]] -------------------------------------------------------- -# -# The OWASP 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/coreruleset/coreruleset -# https://owasp.org/www-project-modsecurity-core-rule-set/ -# - - -# -# -- [[ 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. -# -# The CRS assumes that modsecurity.conf has been loaded. It is bundled with -# ModSecurity. If you don't have it, you can get it from: -# 2.x: https://raw.githubusercontent.com/owasp-modsecurity/ModSecurity/v2/master/modsecurity.conf-recommended -# 3.x: https://raw.githubusercontent.com/owasp-modsecurity/ModSecurity/v3/master/modsecurity.conf-recommended -# -# The order of file inclusion in your webserver configuration should always be: -# 1. modsecurity.conf -# 2. crs-setup.conf (this file) -# 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'. -# At the conclusion of the inbound rules, and again at the conclusion of the -# outbound rules, the anomaly score is checked, and the blocking evaluation -# rules apply a disruptive action, by default returning an error 403. -# -# -- [[ Self-Contained Mode ]] -- -# In this mode, rules apply an action instantly. This was the CRS2 default. -# It can lower resource usage, at the cost of less flexibility in blocking policy -# and less informative audit logs (only the first detected threat is logged). -# Rules inherit the disruptive action that you specify (i.e. deny, drop, etc). -# The first rule that matches will execute this action. In most cases this will -# cause evaluation to stop after the first rule has matched, similar to how many -# IDSs function. -# -# -- [[ Alert Logging Control ]] -- -# In the mode configuration, you must also adjust the desired logging options. -# There are three common options for dealing with logging. By default CRS enables -# logging to the webserver error log (or Event viewer) plus detailed logging to -# the ModSecurity audit log (configured under SecAuditLog in modsecurity.conf). -# -# - To log to both error log and ModSecurity audit log file, use: "log,auditlog" -# - To log *only* to the ModSecurity audit log file, use: "nolog,auditlog" -# - To log *only* to the error log file, use: "log,noauditlog" -# -# Examples for the various modes follow. -# You must leave one of the following options enabled. -# Note that you must specify the same line for phase:1 and phase:2. -# - -# Default: Anomaly Scoring mode, log to error log, log to ModSecurity audit log -# - By default, offending requests are blocked with an error 403 response. -# - To change the disruptive action, see RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf.example -# and review section 'Changing the Disruptive Action for Anomaly Mode'. -# - In Apache, you can use ErrorDocument to show a friendly error page or -# perform a redirect: https://httpd.apache.org/docs/2.4/custom-error.html -# +## Log destination SecDefaultAction "phase:1,log,auditlog,pass" SecDefaultAction "phase:2,log,auditlog,pass" -# Example: Anomaly Scoring mode, log only to ModSecurity audit log -# - By default, offending requests are blocked with an error 403 response. -# - To change the disruptive action, see RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf.example -# and review section 'Changing the Disruptive Action for Anomaly Mode'. -# - In Apache, you can use ErrorDocument to show a friendly error page or -# perform a redirect: https://httpd.apache.org/docs/2.4/custom-error.html -# -# SecDefaultAction "phase:1,nolog,auditlog,pass" -# SecDefaultAction "phase:2,nolog,auditlog,pass" +## Paranoia level +SecAction \ + "id:900000,\ + phase:1,\ + pass,\ + t:none,\ + nolog,\ + tag:'OWASP_CRS',\ + ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\ + setvar:tx.blocking_paranoia_level={{ site.paranoia_level | default(bgwaf_defaults.paranoia_level) }}" +{% if site.detection_paranoia_level | default(bgwaf_defaults.detection_paranoia_level) != None %} -# Example: Self-contained mode, return error 403 on blocking -# - In this configuration the default disruptive action becomes 'deny'. After a -# rule triggers, it will stop processing the request and return an error 403. -# - You can also use a different error status, such as 404, 406, et cetera. -# - In Apache, you can use ErrorDocument to show a friendly error page or -# perform a redirect: https://httpd.apache.org/docs/2.4/custom-error.html -# -# SecDefaultAction "phase:1,log,auditlog,deny,status:403" -# SecDefaultAction "phase:2,log,auditlog,deny,status:403" +## Detection paranoia level +SecAction \ + "id:900001,\ + phase:1,\ + pass,\ + t:none,\ + nolog,\ + tag:'OWASP_CRS',\ + ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\ + setvar:tx.detection_paranoia_level={{ site.detection_paranoia_level | default(bgwaf_defaults.detection_paranoia_level) }}" +{% endif %} -# Example: Self-contained mode, redirect back to homepage on blocking -# - In this configuration the 'tag' action includes the Host header data in the -# log. This helps to identify which virtual host triggered the rule (if any). -# - Note that this might cause redirect loops in some situations; for example -# 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}'" +## Enforce Body Processor URLENCODED +SecAction \ + "id:900010,\ + phase:1,\ + pass,\ + t:none,\ + nolog,\ + tag:'OWASP_CRS',\ + ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\ + setvar:tx.enforce_bodyproc_urlencoded={{ site.enforce_bodyproc_urlencoded | default(bgwaf_defaults.enforce_bodyproc_urlencoded) }}" +## Anomaly Scoring Mode Severity Levels +SecAction \ + "id:900100,\ + phase:1,\ + pass,\ + t:none,\ + nolog,\ + tag:'OWASP_CRS',\ + ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\ + setvar:tx.critical_anomaly_score={{ site.critical_anomaly_score | default(bgwaf_defaults.critical_anomaly_score) }},\ + setvar:tx.error_anomaly_score={{ site.error_anomaly_score | default(bgwaf_defaults.error_anomaly_score) }},\ + setvar:tx.warning_anomaly_score={{ site.warning_anomaly_score | default(bgwaf_defaults.warning_anomaly_score) }},\ + setvar:tx.notice_anomaly_score={{ site.notice_anomaly_score | default(bgwaf_defaults.notice_anomaly_score) }}" -# -# -- [[ 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 -# paranoia levels, it is likely that you will need to add some exclusion -# rules for certain requests and applications receiving complex input. -# -# - A paranoia level of 1 is default. In this level, most core rules -# are enabled. PL1 is advised for beginners, installations -# covering many different sites and applications, and for setups -# with standard security requirements. -# At PL1 you should face FPs rarely. If you encounter FPs, please -# open an issue on the CRS GitHub site and don't forget to attach your -# complete Audit Log record for the request with the issue. -# - Paranoia level 2 includes many extra rules, for instance enabling -# many regexp-based SQL and XSS injection protections, and adding -# extra keywords checked for code injections. PL2 is advised -# for moderate to experienced users desiring more complete coverage -# and for installations with elevated security requirements. -# PL2 comes with some FPs which you need to handle. -# - Paranoia level 3 enables more rules and keyword lists, and tweaks -# limits on special characters used. PL3 is aimed at users experienced -# at the handling of FPs and at installations with a high security -# requirement. -# - Paranoia level 4 further restricts special characters. -# The highest level is advised for experienced users protecting -# installations with very high security requirements. Running PL4 will -# likely produce a very high number of FPs which have to be -# treated before the site can go productive. -# -# All rules will log their PL to the audit log; -# example: [tag "paranoia-level/2"]. This allows you to deduct from the -# audit log how the WAF behavior is affected by paranoia level. -# -# It is important to also look into the variable -# tx.enforce_bodyproc_urlencoded (Enforce Body Processor URLENCODED) -# defined below. Enabling it closes a possible bypass of CRS. -# -# Uncomment this rule to change the default: -# -#SecAction \ -# "id:900000,\ -# phase:1,\ -# pass,\ -# t:none,\ -# nolog,\ -# tag:'OWASP_CRS',\ -# ver:'OWASP_CRS/4.20.0',\ -# setvar:tx.blocking_paranoia_level=1" +## Anomaly Scoring Mode Blocking Threshold Levels +SecAction \ + "id:900110,\ + phase:1,\ + pass,\ + t:none,\ + nolog,\ + tag:'OWASP_CRS',\ + ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\ + setvar:tx.inbound_anomaly_score_threshold={% if site.log_only | default(bgwaf_defaults.log_only) %}1000{% else %}{{ site.inbound_anomaly_score_threshold | default(bgwaf_defaults.inbound_anomaly_score_threshold) }}{% endif %},\ + setvar:tx.outbound_anomaly_score_threshold={% if site.log_only | default(bgwaf_defaults.log_only) %}1000{% else %}{{ site.outbound_anomaly_score_threshold | default(bgwaf_defaults.outbound_anomaly_score_threshold) }}{% endif %}" - -# It is possible to execute rules from a higher paranoia level but not include -# them in the anomaly scoring. This allows you to take a well-tuned system on -# paranoia level 1 and add rules from paranoia level 2 without having to fear -# the new rules would lead to false positives that raise your score above the -# threshold. -# This optional feature is enabled by uncommenting the following rule and -# setting the tx.detection_paranoia_level. -# Technically, rules up to the level defined in tx.detection_paranoia_level -# will be executed, but only the rules up to tx.blocking_paranoia_level affect the -# anomaly scores. -# By default, tx.detection_paranoia_level is set to tx.blocking_paranoia_level. -# tx.detection_paranoia_level must not be lower than tx.blocking_paranoia_level. -# -# Please notice that setting tx.detection_paranoia_level to a higher paranoia -# level results in a performance impact that is equally high as setting -# tx.blocking_paranoia_level to said level. -# -#SecAction \ -# "id:900001,\ -# phase:1,\ -# pass,\ -# t:none,\ -# nolog,\ -# tag:'OWASP_CRS',\ -# ver:'OWASP_CRS/4.20.0',\ -# setvar:tx.detection_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 -# false positives already on paranoia level 1. However, enabling this variable -# closes a possible bypass of CRS so it should be considered. -# -# Uncomment this rule to change the default: -# -#SecAction \ -# "id:900010,\ -# phase:1,\ -# pass,\ -# t:none,\ -# nolog,\ -# tag:'OWASP_CRS',\ -# ver:'OWASP_CRS/4.20.0',\ -# setvar:tx.enforce_bodyproc_urlencoded=1" - - -# -# -- [[ Anomaly Scoring 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). -# - ERROR severity: Anomaly Score of 4. -# Generated mostly from outbound leakage rules (95x files). -# - WARNING severity: Anomaly Score of 3. -# Generated mostly by malicious client rules (91x files). -# - NOTICE severity: Anomaly Score of 2. -# Generated mostly by the protocol rules (92x files). -# -# In anomaly mode, these scores are cumulative. -# So it's possible for a request to hit multiple rules. -# -# (Note: In this file, we use 'phase:1' to set CRS configuration variables. -# In general, 'phase:request' is used. However, we want to make absolutely sure -# that all configuration variables are set before the CRS rules are processed.) -# -#SecAction \ -# "id:900100,\ -# phase:1,\ -# pass,\ -# t:none,\ -# nolog,\ -# tag:'OWASP_CRS',\ -# ver:'OWASP_CRS/4.20.0',\ -# 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 Scoring 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 ] -# If you keep the blocking thresholds at the defaults, the CRS will work -# similarly to previous CRS versions: a single critical rule match will cause -# the request to be blocked and logged. -# -# [ Using higher values ] -# If you want to make the CRS less sensitive, you can increase the blocking -# thresholds, for instance to 7 (which would require multiple rule matches -# before blocking) or 10 (which would require at least two critical alerts - or -# a combination of many lesser alerts), or even higher. However, increasing the -# thresholds might cause some attacks to bypass the CRS rules or your policies. -# -# [ New deployment strategy: Starting high and decreasing ] -# It is a common practice to start a fresh CRS installation with elevated -# anomaly scoring thresholds (>100) and then lower the limits as your -# confidence in the setup grows. You may also look into the Sampling -# Percentage section below for a different strategy to ease into a new -# CRS installation. -# -# [ Anomaly Threshold / Paranoia Level Quadrant ] -# -# High Anomaly Limit | High Anomaly Limit -# Low Paranoia Level | High Paranoia Level -# -> Fresh Site | -> Experimental Site -# ------------------------------------------------------ -# Low Anomaly Limit | Low Anomaly Limit -# Low Paranoia Level | High Paranoia Level -# -> Standard Site | -> High Security Site -# -# Uncomment this rule to change the defaults: -# -#SecAction \ -# "id:900110,\ -# phase:1,\ -# pass,\ -# t:none,\ -# nolog,\ -# tag:'OWASP_CRS',\ -# ver:'OWASP_CRS/4.20.0',\ -# setvar:tx.inbound_anomaly_score_threshold=5,\ -# setvar:tx.outbound_anomaly_score_threshold=4" - - -# -# -- [[ Application Specific Rule Exclusions ]] -------------------------------- -# -# CRS 3.x contained exclusion packages to tweak the CRS for use with common -# web applications, lowering the number of false positives. -# +## Application Specific Rule Exclusions +# FIXME # In CRS 4, these are no longer part of the CRS itself, but they are available # as "CRS plugins". Some plugins improve support for web applications, and others # may bring new functionality. Plugins are not installed by default, but can be # downloaded from the plugin registry: # https://github.com/coreruleset/plugin-registry -# # For detailed information about using and installing plugins, please see: # https://coreruleset.org/docs/concepts/plugins/ - -# -# -- [[ Anomaly Score Reporting Level ]] --------------------------------------- -# -# When a request is blocked due to the anomaly score meeting or exceeding the -# anomaly threshold then the blocking rule will also report the anomaly score. -# This applies to the separate inbound and outbound anomaly scores. -# -# In phase 5, there are additional rules that can perform additional reporting -# of anomaly scores with a verbosity that depends on the reporting level defined -# below. -# -# By setting the reporting level you control whether you want additional -# reporting beyond the blocking rule or not and, if yes, which requests should -# be covered. The higher the reporting level, the more verbose the reporting is. -# -# There are 6 reporting levels: -# +## Anomaly Score Reporting Level # 0 - Reporting disabled # 1 - Reporting for requests with a blocking anomaly score >= a threshold # 2 - Reporting for requests with a detection anomaly score >= a threshold # 3 - Reporting for requests with a blocking anomaly score greater than 0 # 4 - Reporting for requests with a detection anomaly score greater than 0 # 5 - Reporting for all requests -# -# Note: Reporting levels 1 and 2 make it possible to differentiate between -# requests that are blocked and requests that are *not* blocked but would have -# been blocked if the blocking PL was equal to detection PL. This may be useful -# for certain FP tuning methodologies, for example moving to a higher PL. -# -# A value of 5 can be useful on platforms where you are interested in logging -# non-scoring requests, yet it is not possible to report this information in -# the request/access log. This applies to Nginx, for example. -# -#SecAction \ -# "id:900115,\ -# phase:1,\ -# pass,\ -# t:none,\ -# nolog,\ -# tag:'OWASP_CRS',\ -# ver:'OWASP_CRS/4.20.0',\ -# setvar:tx.reporting_level=4" +SecAction \ + "id:900115,\ + phase:1,\ + pass,\ + t:none,\ + nolog,\ + tag:'OWASP_CRS',\ + ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\ + setvar:tx.reporting_level={{ site.reporting_level | default(bgwaf_defaults.reporting_level) }}" +## Early Anomaly Scoring Mode Blocking +SecAction \ + "id:900120,\ + phase:1,\ + pass,\ + t:none,\ + nolog,\ + tag:'OWASP_CRS',\ + ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\ + setvar:tx.early_blocking=0" -# -# -- [[ Early Anomaly Scoring Mode Blocking ]] ------------------------------ -# -# The anomaly scores for the request and the responses are generally summed up -# and evaluated at the end of phase:2 and at the end of phase:4 respectively. -# However, it is possible to enable an early evaluation of these anomaly scores -# at the end of phase:1 and at the end of phase:3. -# -# If a request (or a response) hits the anomaly threshold in this early -# evaluation, then blocking happens immediately (if blocking is enabled) and -# the phase 2 (and phase 4 respectively) will no longer be executed. -# -# Enable the rule 900120 that sets the variable tx.early_blocking to 1 in order -# to enable early blocking. The variable tx.early_blocking is set to 0 by -# default. Early blocking is thus disabled by default. -# -# Please note that early blocking will hide potential alerts from you. This -# means that a payload that would appear in an alert in phase 2 (or phase 4) -# does not get evaluated if the request is being blocked early. So when you -# disabled early blocking again at some point in the future, then new alerts -# from phase 2 might pop up. -#SecAction \ -# "id:900120,\ -# phase:1,\ -# pass,\ -# t:none,\ -# nolog,\ -# tag:'OWASP_CRS',\ -# ver:'OWASP_CRS/4.20.0',\ -# setvar:tx.early_blocking=1" +## Initialize Default Collections +SecAction \ + "id:900130,\ + phase:1,\ + pass,\ + t:none,\ + nolog,\ + tag:'OWASP_CRS',\ + ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\ + setvar:tx.enable_default_collections=1" +## HTTP Policy Settings +SecAction \ + "id:900200,\ + phase:1,\ + pass,\ + t:none,\ + nolog,\ + tag:'OWASP_CRS',\ + ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\ + setvar:'tx.allowed_methods={{ site.allowed_methods | default(bgwaf_defaults.allowed_methods) | join(" ") }}'" -# -# -- [[ Initialize Default Collections ]] ----------------------------------- -# -# CRS provides a centralized option to initialize and populate collections -# meant to be used by plugins (E.g.DoS protection plugin). -# By default, Global and IP collections (see rule 901320), -# being not used by core rules, are not initialized. -# -# Uncomment this rule to change the default: -# -#SecAction \ -# "id:900130,\ -# phase:1,\ -# pass,\ -# t:none,\ -# nolog,\ -# tag:'OWASP_CRS',\ -# ver:'OWASP_CRS/4.20.0',\ -# setvar:tx.enable_default_collections=1" +# Content-Types that a client is allowed to send in a request +SecAction \ + "id:900220,\ + phase:1,\ + pass,\ + t:none,\ + nolog,\ + tag:'OWASP_CRS',\ + ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\ + setvar:'tx.allowed_request_content_type={{ site.allowed_request_content_type | default(bgwaf_defaults.allowed_request_content_type) | join(" ") }}'" +## Allowed HTTP versions +SecAction \ + "id:900230,\ + phase:1,\ + pass,\ + t:none,\ + nolog,\ + tag:'OWASP_CRS',\ + ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\ + setvar:'tx.allowed_http_versions={{ site.allowed_http_versions | default(bgwaf_defaults.allowed_http_versions) | join(" ") }}'" -# -# -- [[ 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-920-PROTOCOL-ENFORCEMENT.conf +## Forbidden file extensions +SecAction \ + "id:900240,\ + phase:1,\ + pass,\ + t:none,\ + nolog,\ + tag:'OWASP_CRS',\ + ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\ + setvar:'tx.restricted_extensions={{ site.restricted_extensions | default(bgwaf_defaults.restricted_extensions) | join(" ") }}'" -# HTTP methods that a client is allowed to use. -# Default: GET HEAD POST OPTIONS -# Example: for RESTful APIs, add the following methods: PUT PATCH DELETE -# Example: for WebDAV, add the following methods: CHECKOUT COPY DELETE LOCK -# MERGE MKACTIVITY MKCOL MOVE PROPFIND PROPPATCH PUT UNLOCK -# Uncomment this rule to change the default. -# -# The HTTP PUT method is normally used to upload data that is saved on the server at a user-supplied URL. -# If enabled, an attacker may be able to inject arbitrary, and potentially malicious, content into the application or on to the file system of the web server. -# Depending on the server's configuration, this may lead to compromise of other users (by uploading -# client-executable scripts), compromise of the server (by uploading server-executable code), or other attacks. -# For this reason, the PUT method is disabled by default. -# GET, HEAD, POST and OPTIONS are seen as the minimal set of HTTP methods -# from a security perspective. For static sites, removing the POST is -# recommended. Add other HTTP methods as seen fit (see above). -# -#SecAction \ -# "id:900200,\ -# phase:1,\ -# pass,\ -# t:none,\ -# nolog,\ -# tag:'OWASP_CRS',\ -# ver:'OWASP_CRS/4.20.0',\ -# setvar:'tx.allowed_methods=GET HEAD POST OPTIONS'" +## Restricted request headers +SecAction \ + "id:900250,\ + phase:1,\ + pass,\ + t:none,\ + nolog,\ + tag:'OWASP_CRS',\ + ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\ + setvar:'tx.restricted_headers_basic={{ site.restricted_headers_basic | default(bgwaf_defaults.restricted_headers_basic) | join(" ") }}'" -# Content-Types that a client is allowed to send in a request. -# Default: |application/x-www-form-urlencoded| |multipart/form-data| |text/xml| -# |application/xml| |application/soap+xml| |application/json| |application/reports+json| |application/csp-report| -# -# Please note, that the rule where CRS uses this variable (920420) evaluates it with operator -# `@within`, which is case sensitive, but uses t:lowercase. You must add your whole custom -# Content-Type with lowercase. -# -# Bypass Warning: some applications may not rely on the content-type request header in order -# to parse the request body. This could make an attacker able to send malicious URLENCODED/JSON/XML -# payloads without being detected by the WAF. Allowing request content-type that doesn't activate any -# body processor (for example: "text/plain", "application/x-amf", "application/octet-stream", etc..) -# could lead to a WAF bypass. For example, a malicious JSON payload submitted with a "text/plain" -# content type may still be interpreted as JSON by a backend application but would not trigger the -# JSON body parser at the WAF, leading to a bypass. To avoid bypasses, you must enable the appropriate -# body parser based on the expected data in the request bodies (For example JSON for JSON data, XML for XML data, etc). -# -# When additional JSON content types are legitimately used in a deployment, -# e.g. application/cloudevents+json, it is extremely important to ensure that a -# rule exists to enable the engine's JSON body processor for these additional -# JSON content types. Failure to do so can lead to a request body bypass. The -# default JSON rule in modsecurity.conf-recommended (200001) will only activate -# the JSON body processor for the specific content type application/json. The -# optional modsecurity.conf-recommended rule 200006 can be used to enable the -# JSON body processor for a wide variety of JSON content types. -# -# To prevent blocking request with not allowed content-type by default, you can create an exclusion -# rule that removes rule 920420. It's important that you enable the correct body parser when allowing -# an additional content type to prevent bypasses. For example, this rule enables the JSON body processor -# for the text/plain content type: -#SecRule REQUEST_HEADERS:Content-Type "@beginsWith text/plain" \ -# "id:1234,\ -# phase:1,\ -# pass,\ -# t:none,\ -# nolog,\ -# tag:'OWASP_CRS',\ -# ver:'OWASP_CRS/4.20.0',\ -# chain" -# SecRule REQUEST_URI "@rx ^/foo/bar" \ -# "t:none,\ -# ctl:ruleRemoveById=920420,\ -# ctl:requestBodyProcessor=JSON" -# -# See: https://github.com/owasp-modsecurity/ModSecurity/wiki/Reference-Manual-(v2.x)#ctl -# See: https://github.com/owasp-modsecurity/ModSecurity/wiki/Reference-Manual-(v3.x)#ctl -# -# Uncomment this rule to change the default. -# -#SecAction \ -# "id:900220,\ -# phase:1,\ -# pass,\ -# t:none,\ -# nolog,\ -# tag:'OWASP_CRS',\ -# ver:'OWASP_CRS/4.20.0',\ -# setvar:'tx.allowed_request_content_type=|application/x-www-form-urlencoded| |multipart/form-data| |text/xml| |application/xml| |application/soap+xml| |application/json| |application/reports+json| |application/csp-report|'" +## Extended restricted request headers (forbidden at a higher paranoia level) +SecAction \ + "id:900255,\ + phase:1,\ + pass,\ + t:none,\ + nolog,\ + tag:'OWASP_CRS',\ + ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\ + setvar:'tx.restricted_headers_extended={{ site.restricted_headers_extended | default(bgwaf.restricted_headers_extended) | join(" ") }}'" -# Allowed HTTP versions. -# Default: HTTP/1.0 HTTP/1.1 HTTP/2 HTTP/2.0 HTTP/3 HTTP/3.0 -# Example for legacy clients: HTTP/0.9 HTTP/1.0 HTTP/1.1 HTTP/2 HTTP/2.0 HTTP/3 HTTP/3.0 -# Note that some web server versions use 'HTTP/2', some 'HTTP/2.0', so -# we include both version strings by default. -# Uncomment this rule to change the default. -#SecAction \ -# "id:900230,\ -# phase:1,\ -# pass,\ -# t:none,\ -# nolog,\ -# tag:'OWASP_CRS',\ -# ver:'OWASP_CRS/4.20.0',\ -# setvar:'tx.allowed_http_versions=HTTP/1.0 HTTP/1.1 HTTP/2 HTTP/2.0 HTTP/3 HTTP/3.0'" - -# Forbidden file extensions. -# Guards against unintended exposure of development/configuration files. -# Default: .ani/ .asa/ .asax/ .ascx/ .backup/ .bak/ .bat/ .cdx/ .cer/ .cfg/ .cmd/ .cnf/ .com/ .compositefont/ .config/ .conf/ .copy/ .crt/ .cs/ .csproj/ .csr/ .dat/ .db/ .dbf/ .dist/ .dll/ .dos/ .dpkg-dist/ .drv/ .gadget/ .hta/ .htr/ .htw/ .ida/ .idc/ .idq/ .inc/ .inf/ .ini/ .jse/ .key/ .licx/ .lnk/ .log/ .mdb/ .msc/ .ocx/ .old/ .pass/ .pdb/ .pfx/ .pif/ .pem/ .pol/ .prf/ .printer/ .pwd/ .rdb/ .rdp/ .reg/ .resources/ .resx/ .save/ .scr/ .sct/ .shs/ .sql/ .sqlite/ .sqlite3/ .swp/ .sys/ .temp/ .tlb/ .tmp/ .vb/ .vbe/ .vbs/ .vbproj/ .vsdisco/ .vxd/ .webinfo/ .ws/ .wsc/ .wsf/ .wsh/ .xsd/ .xsx/ -# Example: .bak/ .config/ .conf/ .db/ .ini/ .log/ .old/ .pass/ .pdb/ .rdb/ .sql/ -# Note that .axd was removed due to false positives (see PR 1925). -# -# To additionally guard against configuration/install archive files from being -# accidentally exposed, common archive file extensions can be added to the -# restricted extensions list. An example list of common archive file extensions -# is presented below: -# .7z/ .br/ .bz/ .bz2/ .cab/ .cpio/ .gz/ .img/ .iso/ .jar/ .rar/ .tar/ .tbz2/ .tgz/ .txz/ .xz/ .zip/ .zst/ -# (Source: https://en.wikipedia.org/wiki/List_of_archive_formats) -# -# Uncomment this rule to change the default. -#SecAction \ -# "id:900240,\ -# phase:1,\ -# pass,\ -# t:none,\ -# nolog,\ -# tag:'OWASP_CRS',\ -# ver:'OWASP_CRS/4.20.0',\ -# setvar:'tx.restricted_extensions=.ani/ .asa/ .asax/ .ascx/ .backup/ .bak/ .bat/ .cdx/ .cer/ .cfg/ .cmd/ .cnf/ .com/ .compositefont/ .config/ .conf/ .copy/ .crt/ .cs/ .csproj/ .csr/ .dat/ .db/ .dbf/ .dist/ .dll/ .dos/ .dpkg-dist/ .drv/ .gadget/ .hta/ .htr/ .htw/ .ida/ .idc/ .idq/ .inc/ .inf/ .ini/ .jse/ .key/ .licx/ .lnk/ .log/ .mdb/ .msc/ .ocx/ .old/ .pass/ .pdb/ .pfx/ .pif/ .pem/ .pol/ .prf/ .printer/ .pwd/ .rdb/ .rdp/ .reg/ .resources/ .resx/ .save/ .scr/ .sct/ .shs/ .sql/ .sqlite/ .sqlite3/ .swp/ .sys/ .temp/ .tlb/ .tmp/ .vb/ .vbe/ .vbs/ .vbproj/ .vsdisco/ .vxd/ .webinfo/ .ws/ .wsc/ .wsf/ .wsh/ .xsd/ .xsx/'" - -# Restricted request headers. -# The HTTP request headers that CRS restricts are split into two categories: -# basic (always forbidden) and extended (may be forbidden). All header names -# should be lowercase and enclosed by /slashes/ as delimiters. -# -# [ Basic ] -# Includes deprecated headers and headers with known security risks. Always -# forbidden. -# Default: /content-encoding/ /proxy/ /lock-token/ /content-range/ /if/ /x-http-method-override/ /x-http-method/ /x-method-override/ /x-middleware-subrequest/ /expect/ -# -# /content-encoding/ -# Used to list any encodings that have been applied to the original payload. -# Only used for compression, which isn't supported by CRS by default since CRS -# blocks newlines and null bytes inside the request body. Most compression -# algorithms require at least null bytes per RFC. Blocking Content-Encoding -# shouldn't break anything and increases security since WAF engines, including -# ModSecurity, are typically incapable of properly scanning compressed request -# bodies. -# -# /proxy/ -# Blocking this prevents the 'httpoxy' vulnerability: https://httpoxy.org -# -# /lock-token/ -# -# /content-range/ -# -# /if/ -# -# /x-http-method-override/ -# /x-http-method/ -# /x-method-override/ -# Blocking these headers prevents method override attacks, as described here: -# https://www.sidechannel.blog/en/http-method-override-what-it-is-and-how-a-pentester-can-use-it -# -# /x-middleware-subrequest/ -# CVE-2025-29927 (Next.js) -# -# /expect/ -# Blocking this header prevents Expect-based desync attacks -# https://portswigger.net/research/http1-must-die#expect-based-desync-attacks -# -# Uncomment this rule to change the default. -#SecAction \ -# "id:900250,\ -# phase:1,\ -# pass,\ -# t:none,\ -# nolog,\ -# tag:'OWASP_CRS',\ -# ver:'OWASP_CRS/4.20.0',\ -# setvar:'tx.restricted_headers_basic=/content-encoding/ /proxy/ /lock-token/ /content-range/ /if/ /x-http-method-override/ /x-http-method/ /x-method-override/ /x-middleware-subrequest/ /expect/'" -# -# [ Extended ] -# Includes deprecated headers that are still in use (so false positives are -# possible) and headers with possible security risks. Forbidden at a higher -# paranoia level. -# Default: /accept-charset/ -# -# /accept-charset/ -# Deprecated header that should not be used by clients and should be ignored -# by servers. Can be used for a response WAF bypass by asking for a charset -# that the WAF cannot decode. Considered to be a good indicator of suspicious -# behavior but produces too many false positives to be forbidden by default. -# References: -# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Charset -# https://github.com/coreruleset/coreruleset/issues/3140 -# -# Uncomment this rule to change the default. -#SecAction \ -# "id:900255,\ -# phase:1,\ -# pass,\ -# t:none,\ -# nolog,\ -# tag:'OWASP_CRS',\ -# ver:'OWASP_CRS/4.20.0',\ -# setvar:'tx.restricted_headers_extended=/accept-charset/'" - -# Content-Types charsets that a client is allowed to send in a request. -# The content-types are enclosed by |pipes| as delimiters to guarantee exact matches. -# -# You can add additional character sets if something more exotic is required. One caveat: you will also need to edit 'regex-assembly/include/allowed-charsets.ra' and rebuild all the associated regular expressions using `crs-toolchain regex update --all`. See https://coreruleset.org/docs/6-development/6-2-crs-toolchain/. -# -# Warning: If the WAF engine is unable to fully and correctly decode a newly added character encoding then this can lead to a full request body or response body bypass. Additional permitted character encodings should be added with caution and tested to ensure inspection is not affected. -# -# Default: |utf-8| |iso-8859-1| |iso-8859-15| |windows-1252| -# Uncomment this rule to change the default. -#SecAction \ -# "id:900280,\ -# phase:1,\ -# pass,\ -# t:none,\ -# nolog,\ -# tag:'OWASP_CRS',\ -# ver:'OWASP_CRS/4.20.0',\ -# 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. -# +# Content-Types charsets that a client is allowed to send in a request +SecAction \ + "id:900280,\ + phase:1,\ + pass,\ + t:none,\ + nolog,\ + tag:'OWASP_CRS',\ + ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\ + setvar:'tx.allowed_request_content_type_charset={{ bgwaf_defaults.allowed_request_content_type_charset | default(bgwaf_defaults.allowed_request_content_type_charset) | join(" ") }}'" # Block request if number of arguments is too high -# Default: unlimited -# Example: 255 -# Note that a hard limit by the engine may also apply here (SecArgumentsLimit). -# This would override this soft limit. -# Uncomment this rule to set a limit. -#SecAction \ -# "id:900300,\ -# phase:1,\ -# pass,\ -# t:none,\ -# nolog,\ -# tag:'OWASP_CRS',\ -# ver:'OWASP_CRS/4.20.0',\ -# setvar:tx.max_num_args=255" +SecAction \ + "id:900300,\ + phase:1,\ + pass,\ + t:none,\ + nolog,\ + tag:'OWASP_CRS',\ + ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\ + setvar:tx.max_num_args={{ site.max_num_args | default(bgwaf_defaults.max_num_args) }}" # Block request if the length of any argument name is too high -# Default: unlimited -# Example: 100 -# Uncomment this rule to set a limit. -#SecAction \ -# "id:900310,\ -# phase:1,\ -# pass,\ -# t:none,\ -# nolog,\ -# tag:'OWASP_CRS',\ -# ver:'OWASP_CRS/4.20.0',\ -# setvar:tx.arg_name_length=100" +SecAction \ + "id:900310,\ + phase:1,\ + pass,\ + t:none,\ + nolog,\ + tag:'OWASP_CRS',\ + ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\ + setvar:tx.arg_name_length={{ site.arg_name_length | default(bgwaf_defaults.arg_name_length) }}" # Block request if the length of any argument value is too high -# Default: unlimited -# Example: 400 -# Uncomment this rule to set a limit. -#SecAction \ -# "id:900320,\ -# phase:1,\ -# pass,\ -# t:none,\ -# nolog,\ -# tag:'OWASP_CRS',\ -# ver:'OWASP_CRS/4.20.0',\ -# setvar:tx.arg_length=400" +SecAction \ + "id:900320,\ + phase:1,\ + pass,\ + t:none,\ + nolog,\ + tag:'OWASP_CRS',\ + ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\ + setvar:tx.arg_length={{ site.arg_length | default(bgwaf_defaults.arg_length) }}" # Block request if the total length of all combined arguments is too high -# Default: unlimited -# Example: 64000 -# Uncomment this rule to set a limit. -#SecAction \ -# "id:900330,\ -# phase:1,\ -# pass,\ -# t:none,\ -# nolog,\ -# tag:'OWASP_CRS',\ -# ver:'OWASP_CRS/4.20.0',\ -# setvar:tx.total_arg_length=64000" +SecAction \ + "id:900330,\ + phase:1,\ + pass,\ + t:none,\ + nolog,\ + tag:'OWASP_CRS',\ + ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\ + setvar:tx.total_arg_length={{ site.total_arg_length | default(bgwaf_defaults.total_arg_length) }}" # Block request if the file size of any individual uploaded file is too high -# Default: unlimited -# Example: 1048576 -# Uncomment this rule to set a limit. -#SecAction \ -# "id:900340,\ -# phase:1,\ -# pass,\ -# t:none,\ -# nolog,\ -# tag:'OWASP_CRS',\ -# ver:'OWASP_CRS/4.20.0',\ -# setvar:tx.max_file_size=1048576" +SecAction \ + "id:900340,\ + phase:1,\ + pass,\ + t:none,\ + nolog,\ + tag:'OWASP_CRS',\ + ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\ + setvar:tx.max_file_size={{ site.max_file_size | default(bgwaf_defaults.max_file_size) }}" # Block request if the total size of all combined uploaded files is too high -# Default: unlimited -# Example: 1048576 -# Uncomment this rule to set a limit. -#SecAction \ -# "id:900350,\ -# phase:1,\ -# pass,\ -# t:none,\ -# nolog,\ -# tag:'OWASP_CRS',\ -# ver:'OWASP_CRS/4.20.0',\ -# setvar:tx.combined_file_sizes=1048576" +SecAction \ + "id:900350,\ + phase:1,\ + pass,\ + t:none,\ + nolog,\ + tag:'OWASP_CRS',\ + ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\ + setvar:tx.combined_file_sizes={{ site.combined_file_sizes | default(bgwaf_defaults.combined_file_sizes) }}" +## Easing In / Sampling Percentage +SecAction \ + "id:900400,\ + phase:1,\ + pass,\ + nolog,\ + tag:'OWASP_CRS',\ + ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\ + setvar:tx.sampling_percentage={{ site.sampling_percentage | default(bgwaf_defaults.sampling_percentage) }}" -# -# -- [[ Easing In / Sampling Percentage ]] ------------------------------------- -# -# Adding the CRS 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. -# -# Adjust the percentage of requests that are funnelled into the Core Rules by -# setting TX.sampling_percentage below. The default is 100, meaning that every -# request gets checked by the CRS. The selection of requests, which are going -# to be checked, is based on a pseudo random number generated by ModSecurity. -# -# If a request is allowed to pass without being checked by the CRS, there is no -# entry in the audit log (for performance reasons), but an error log entry is -# written. If you want to disable the error log entry, then issue the -# following directive somewhere after the inclusion of the CRS -# (E.g., RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf). -# -#SecRuleUpdateActionById 901450 "nolog" -# -# ATTENTION: If this TX.sampling_percentage is below 100, then some of the -# requests will bypass the Core Rules completely and you lose the ability to -# protect your service with ModSecurity. -# -# Uncomment this rule to enable this feature: -# -#SecAction \ -# "id:900400,\ -# phase:1,\ -# pass,\ -# nolog,\ -# tag:'OWASP_CRS',\ -# ver:'OWASP_CRS/4.20.0',\ -# setvar:tx.sampling_percentage=100" +## Check UTF-8 encoding +SecAction \ + "id:900950,\ + phase:1,\ + pass,\ + t:none,\ + nolog,\ + tag:'OWASP_CRS',\ + ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\ + setvar:tx.crs_validate_utf8_encoding=1" - - -# -# -- [[ 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 \ -# "id:900950,\ -# phase:1,\ -# pass,\ -# t:none,\ -# nolog,\ -# tag:'OWASP_CRS',\ -# ver:'OWASP_CRS/4.20.0',\ -# setvar:tx.crs_validate_utf8_encoding=1" - -# -- [[ Skip Checking Responses ]] ------------------------------------------------ -# +## Skip Checking Responses # CRS will perform analysis of the response contents if this is enabled and you have # the directive `SecResponseBodyAccess On`. -# # Warning: this feature is _enabled_ by default, but depending on your applications # you might be targeted in a Request Filter Denial of Service (RFDoS) attack. -# # References: https://blog.sicuranext.com/response-filter-denial-of-service-a-new-way-to-shutdown-a-website/ -# # Uncomment this rule to _skip checking responses_. -# #SecAction \ # "id:900500,\ # phase:1,\ @@ -851,20 +290,10 @@ SecDefaultAction "phase:2,log,auditlog,pass" # t:none,\ # nolog,\ # tag:'OWASP_CRS',\ -# ver:'OWASP_CRS/4.20.0',\ +# ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\ # setvar:tx.crs_skip_response_analysis=1" -# -# -- [[ 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. -# +## End of setup SecAction \ "id:900990,\ phase:1,\ @@ -872,5 +301,5 @@ SecAction \ t:none,\ nolog,\ tag:'OWASP_CRS',\ - ver:'OWASP_CRS/4.21.0',\ - setvar:tx.crs_setup_version=4210" + ver:'OWASP_CRS/{{ bgwaf_owasp_crs_version }}',\ + setvar:tx.crs_setup_version={{ bgwaf_owasp_crs_version | regex_replace('\.', '') }}" diff --git a/ansible/roles/bgwaf/templates/exclusions-request-before.conf b/ansible/roles/bgwaf/templates/exclusions-request-before.conf new file mode 100644 index 0000000..aae4a96 --- /dev/null +++ b/ansible/roles/bgwaf/templates/exclusions-request-before.conf @@ -0,0 +1,3 @@ +{% for exclusion in site.exceptions.before_request | default([]) %} +{{ exclusion }} +{% endfor %} diff --git a/ansible/roles/bgwaf/templates/exclusions-response-after.conf b/ansible/roles/bgwaf/templates/exclusions-response-after.conf new file mode 100644 index 0000000..7ffde16 --- /dev/null +++ b/ansible/roles/bgwaf/templates/exclusions-response-after.conf @@ -0,0 +1,3 @@ +{% for exclusion in site.exceptions.after_response | default([]) %} +{{ exclusion }} +{% endfor %} diff --git a/ansible/roles/bgwaf/templates/exclusions.conf b/ansible/roles/bgwaf/templates/exclusions.conf deleted file mode 100644 index 61dfffd..0000000 --- a/ansible/roles/bgwaf/templates/exclusions.conf +++ /dev/null @@ -1,3 +0,0 @@ -{% for exclusion in bgwaf_site_exclusions %} -{{ exclusion }} -{% endfor %} diff --git a/ansible/vars.yml b/ansible/vars.yml index 0a1fe0c..fa4b5c5 100644 --- a/ansible/vars.yml +++ b/ansible/vars.yml @@ -13,6 +13,13 @@ waf: - "http://www1" - "http://www2" - "http://www3" + log_only: true +# paranoia_level: 1 +# detection_paranoia_level: null custom_cert: true custom_cert_file: "/etc/ssl/certs/local.crt" custom_key_file: "/etc/ssl/private/local.key" +# exceptions: +# before_request: +# - 'SecRule REQUEST_URI "@beginsWith /?bin/sh" "id:1,nolog,ctl:ruleRemoveById=932160"' +# - 'SecRule REQUEST_URI "@beginsWith /?bin/sh" "id:2,nolog,ctl:ruleRemoveById=932250"'