{"id":950,"date":"2016-10-11T09:20:32","date_gmt":"2016-10-11T07:20:32","guid":{"rendered":"http:\/\/www.netnea.com\/cms\/?page_id=950"},"modified":"2026-01-26T22:18:34","modified_gmt":"2026-01-26T21:18:34","slug":"apache-tutorial-7_including-modsecurity-core-rules","status":"publish","type":"page","link":"https:\/\/www.netnea.com\/cms\/apache-tutorial-7_including-modsecurity-core-rules\/","title":{"rendered":"Including OWASP ModSecurity Core Rule Set"},"content":{"rendered":"\n<h2 id=\"including-the-owasp-crs\">Including the OWASP CRS<\/h2>\n<h3 id=\"what-are-we-doing\">What are we doing?<\/h3>\n<p>We are embedding the OWASP CRS in our Apache web server and eliminating false alarms.<\/p>\n<h3 id=\"why-are-we-doing-this\">Why are we doing this?<\/h3>\n<p>The ModSecurity Web Application Firewall, as we set up in Tutorial 6, still has barely any rules. The protection only works when you configure an additional rule set. The CRS provides generic blacklisting. This means that they inspect requests and responses for signs of attacks. The signs are often keywords or typical patterns that may be suggestive of a wide variety of attacks. This also entails false alarms (<em>false positives<\/em>) being triggered and we have to eliminate these for a successful installation.<\/p>\n<h3 id=\"requirements\">Requirements<\/h3>\n<ul>\n<li>An Apache web server, ideally one created using the file structure shown in <a href=\"https:\/\/www.netnea.com\/cms\/apache-tutorial-1_compiling-apache\/\">Tutorial 1 (Compiling an Apache web server)<\/a>.<\/li>\n<li>Understanding of the minimal configuration from <a href=\"https:\/\/www.netnea.com\/cms\/apache-tutorial-2_minimal-apache-configuration\/\">Tutorial 2 (Configuring a minimal Apache server)<\/a>.<\/li>\n<li>An Apache web server with SSL\/TLS support as shown in <a href=\"https:\/\/www.netnea.com\/cms\/apache-tutorial-4_configuring-ssl-tls\/\">Tutorial 4 (Configuring an SSL server)<\/a>.<\/li>\n<li>An Apache web server with extended access log as shown in <a href=\"https:\/\/www.netnea.com\/cms\/apache-tutorial-5\/apache-tutorial-5_extending-access-log\/\">Tutorial 5 (Extending and analyzing the access log)<\/a>.<\/li>\n<li>An Apache web server with ModSecurity as shown in <a href=\"https:\/\/www.netnea.com\/cms\/apache-tutorial-6\/apache-tutorial-6_embedding-modsecurity\/\">Tutorial 6 (Embedding ModSecurity)<\/a>.<\/li>\n<\/ul>\n<p>We will be working with the new major release of the CRS, CRS3; short for CRS 3.0. The official distribution comes with an <em>INSTALL<\/em> file that does a good job explaining the setup (after all, yours truly wrote a good deal of that file), but we will tweak the process a bit to suit our needs.<\/p>\n<h3 id=\"step-1-downloading-owasp-crs\">Step 1: Downloading OWASP CRS<\/h3>\n<p>The CRS are being developed under the umbrella of <em>OWASP<\/em>, the Open Web Application Security Project. The rules themselves are available on <em>GitHub<\/em> and can be downloaded via <em>git<\/em> or with the following <em>wget<\/em> command:<\/p>\n<pre><code>$&gt; cd \/apache\/conf\n$&gt; wget https:\/\/github.com\/coreruleset\/coreruleset\/archive\/refs\/tags\/v4.22.0.tar.gz\n$&gt; tar -xvzf v4.22.0.tar.gz\ncoreruleset-4.22.0\ncoreruleset-4.22.0\/\ncoreruleset-4.22.0\/.github\/\ncoreruleset-4.22.0\/.github\/ISSUE_TEMPLATE.md\ncoreruleset-4.22.0\/.gitignore\ncoreruleset-4.22.0\/.gitmodules\ncoreruleset-4.22.0\/.travis.yml\ncoreruleset-4.22.0\/CHANGES\ncoreruleset-4.22.0\/IDNUMBERING\ncoreruleset-4.22.0\/INSTALL\ncoreruleset-4.22.0\/KNOWN_BUGS\ncoreruleset-4.22.0\/LICENSE\ncoreruleset-4.22.0\/README.md\ncoreruleset-4.22.0\/crs-setup.conf.example\ncoreruleset-4.22.0\/documentation\/\ncoreruleset-4.22.0\/documentation\/OWASP-CRS-Documentation\/\ncoreruleset-4.22.0\/documentation\/README\n...\n$&gt; ln -s coreruleset-4.22.0 \/apache\/conf\/crs\n$&gt; cp crs\/crs-setup.conf.example crs\/crs-setup.conf\n$&gt; rm v4.22.0.tar.gz<\/code><\/pre>\n<p>This unpacks the base part of the CRS in the directory <code>\/apache\/conf\/coreruleset-4.22.0<\/code>. We create a link from <code>\/apache\/conf\/crs<\/code> to this folder. Then we copy a file named <code>crs-setup.conf.example<\/code> to a new file <code>crs-setup.conf<\/code> and finally, we delete the CRS tar file.<\/p>\n<p>The setup file allows us to tweak many different settings. It is worth a look &#8211; if only to see what is included. However, we are OK with the default settings and will not touch the file: We just make sure it is available under the new filename <code>crs-setup.conf<\/code>. Then we can continue to update the configuration to include the rules files.<\/p>\n<h3 id=\"step-2-embedding-the-crs\">Step 2: Embedding the CRS<\/h3>\n<p>In Tutorial 6, where we embedded ModSecurity itself, we marked out a section for the CRS. We now add several <em>Include<\/em> directives into this section. Specifically, four parts are added to the existing configuration. (1) The CRS base configuration, (2) a part for self-defined rule exclusions before the CRS rules. Then (3) CRS themselves as well as CRS plugins and finally a part (4) for rule exclusions after CRS.<\/p>\n<p>The rule exclusions are directives and rules used for managing the false alarms described above. Some false alarms must be prevented before the corresponding CRS rule is loaded. Some false alarms can only be intercepted following the definition of the rule itself. But one thing at a time. Here is the new block of configuration which we will insert into the base configuration we assembled when we enabled ModSecurity:<\/p>\n<div class=\"sourceCode\" id=\"cb2\"><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=\"cb2-1\"><a href=\"#cb2-1\" aria-hidden=\"true\"><\/a><span class=\"co\"># === ModSec CRS Base Configuration (ids: 900000-900999)<\/span><\/span>\n<span id=\"cb2-2\"><a href=\"#cb2-2\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb2-3\"><a href=\"#cb2-3\" aria-hidden=\"true\"><\/a><span class=\"ex\">Include<\/span>    \/apache\/conf\/crs\/crs-setup.conf<\/span>\n<span id=\"cb2-4\"><a href=\"#cb2-4\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb2-5\"><a href=\"#cb2-5\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecAction<\/span> <span class=\"st\">&quot;id:900110,phase:1,pass,nolog,\\<\/span><\/span>\n<span id=\"cb2-6\"><a href=\"#cb2-6\" aria-hidden=\"true\"><\/a><span class=\"st\">  setvar:tx.inbound_anomaly_score_threshold=10000,\\<\/span><\/span>\n<span id=\"cb2-7\"><a href=\"#cb2-7\" aria-hidden=\"true\"><\/a><span class=\"st\">  setvar:tx.outbound_anomaly_score_threshold=10000,\\<\/span><\/span>\n<span id=\"cb2-8\"><a href=\"#cb2-8\" aria-hidden=\"true\"><\/a><span class=\"st\">  setvar:tx.blocking_paranoia_level=1,\\<\/span><\/span>\n<span id=\"cb2-9\"><a href=\"#cb2-9\" aria-hidden=\"true\"><\/a><span class=\"st\">  setvar:tx.reporting_level=4&quot;<\/span><\/span>\n<span id=\"cb2-10\"><a href=\"#cb2-10\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb2-11\"><a href=\"#cb2-11\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb2-12\"><a href=\"#cb2-12\" aria-hidden=\"true\"><\/a><span class=\"co\"># === ModSec CRS: Runtime Exclusion Rules (ids: 10000-49999)<\/span><\/span>\n<span id=\"cb2-13\"><a href=\"#cb2-13\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb2-14\"><a href=\"#cb2-14\" aria-hidden=\"true\"><\/a><span class=\"co\"># ...<\/span><\/span>\n<span id=\"cb2-15\"><a href=\"#cb2-15\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb2-16\"><a href=\"#cb2-16\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb2-17\"><a href=\"#cb2-17\" aria-hidden=\"true\"><\/a><span class=\"co\"># === CRS and CRS Plugin Inclusion<\/span><\/span>\n<span id=\"cb2-18\"><a href=\"#cb2-18\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb2-19\"><a href=\"#cb2-19\" aria-hidden=\"true\"><\/a><span class=\"ex\">Include<\/span> \/apache\/conf\/crs\/plugins\/*-config.conf<\/span>\n<span id=\"cb2-20\"><a href=\"#cb2-20\" aria-hidden=\"true\"><\/a><span class=\"ex\">Include<\/span> \/apache\/conf\/crs\/plugins\/*-before.conf<\/span>\n<span id=\"cb2-21\"><a href=\"#cb2-21\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb2-22\"><a href=\"#cb2-22\" aria-hidden=\"true\"><\/a><span class=\"ex\">Include<\/span> \/apache\/conf\/crs\/rules\/*.conf<\/span>\n<span id=\"cb2-23\"><a href=\"#cb2-23\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb2-24\"><a href=\"#cb2-24\" aria-hidden=\"true\"><\/a><span class=\"ex\">Include<\/span> \/apache\/conf\/crs\/plugins\/*-after.conf<\/span>\n<span id=\"cb2-25\"><a href=\"#cb2-25\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb2-26\"><a href=\"#cb2-26\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb2-27\"><a href=\"#cb2-27\" aria-hidden=\"true\"><\/a><span class=\"co\"># === ModSec CRS: Startup Time Rules Exclusions<\/span><\/span>\n<span id=\"cb2-28\"><a href=\"#cb2-28\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb2-29\"><a href=\"#cb2-29\" aria-hidden=\"true\"><\/a><span class=\"co\"># ...<\/span><\/span><\/code><\/pre><\/div>\n<p>The CRS comes with a base configuration file named <code>crs-setup.conf<\/code> which we prepared during the installation. Copying the original example file guarantees that we can update the CRS distribution without harming our copy of the config file unless we want to.<\/p>\n<p>We have the option to edit settings in that base configuration file. However, the strategy for this series of tutorials has been to define all the important things in our single Apache configuration file. We do not want to insert the complete contents of the <code>crs-setup.conf<\/code> file into our configuration (but we include it) in order to get the minimal set of configuration items needed to run CRS. I do not want to dive into all the options in the settings file, but it is worth having a look at.<\/p>\n<p>For now, we leave the file untouched, but we take four important values out of <code>crs-setup.conf<\/code> and define them in our config so we have them in sight at all times. We define two thresholds in the unconditional rule <em>900110<\/em>: The inbound anomaly score and the outbound anomaly score. This is done via the <code>setvar<\/code> action which sets both values to 10000.<\/p>\n<p>What does that mean? The CRS works with a scoring mechanism by default. For every rule a request violates, there is a score being raised. When all the request rules have passed, the score is compared to the limit. If if hits the limit, the request is blocked. The same thing happens with the responses, where we want to avoid information leaks to the client.<\/p>\n<p>The CRS comes in blocking mode by default. If a rule is violated and the score hits the limit, the blocking will be effective immediately. But we are not yet sure our service runs smoothly and the danger of false alarms is always there. We want to avoid unwanted blocks, so we set the threshold at a value of 10000. Rule violations score 5 points at most, so even if cumulation is possible, a request is unlikely to hit the limit. Yet, we remain in blocking mode and when we grow more confident in our configuration, we can lower the threshold gradually.<\/p>\n<p>Then we add the definition of another two variable to this rules. <code>tx.blocking_paranoia_level<\/code>, defines the <em>Paranoia Level<\/em> to 1. CRS rules are divided in four groups at paranoia levels 1 &#8211; 4. As the name suggests, the higher the paranoia level, the more paranoid the rules. The default is paranoia level 1, where the rules are quite sane and false alarms are rare. When you raise the PL to 2, additional rules are enabled. Starting with PL 2, you will face more and more false alarms, also called false positives. This number grows with PL3 and when you arrive at PL4, you are likely to face false alarms as though your web application firewall has become quite paranoid, so to speak. We will deal with false positives later in this tutorial, but for the moment you just need to be aware that you can control the aggressiveness of the rule set with the paranoia level setting and that PL3 and PL4 are really for advanced users with very high security needs.<\/p>\n<p>And finally, we set the reporting level via <code>tx.reporting_level<\/code>. The reporting level configures a reporting rule that lists a summary of CRS for a given request. CRS can write this summary for every request, also those that did not trigger any alerts, it can write the summary for those requests that did, it can write it for requests that have been blocked or it can leave out that summary report. Depening on your use case, this information can be useful, but I personally run without it (-&gt; reporting level <code>0<\/code>).<\/p>\n<h3 id=\"step-3-a-closer-look-at-the-rules-folder\">Step 3: A closer look at the rules folder<\/h3>\n<p>The center of the previous config snippet follows the includes statement for CRS and any plugins. CRS v4 introduced an architecture for plugins. Plugins are rules with additional detection abilities or rules performing special tasks, that are not interesting for the majority of setups. We are not loading any plugins just yet, but we prepare the include directives, so we can drop plugins in the said folder in the future and have them enabled immediately.<\/p>\n<p>The CRS include is the third in the row and it loads all files with suffix <code>.conf<\/code> from the rules sub folder in the CRS directory. This is where all the rules are being loaded. Let\u2019s take a look at them:<\/p>\n<div class=\"sourceCode\" id=\"cb3\"><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=\"cb3-1\"><a href=\"#cb3-1\" aria-hidden=\"true\"><\/a>$<span class=\"op\">&gt;<\/span> <span class=\"fu\">ls<\/span> -1 crs\/rules\/*.conf<\/span>\n<span id=\"cb3-2\"><a href=\"#cb3-2\" aria-hidden=\"true\"><\/a><span class=\"ex\">crs\/rules\/REQUEST-901-INITIALIZATION.conf<\/span><\/span>\n<span id=\"cb3-3\"><a href=\"#cb3-3\" aria-hidden=\"true\"><\/a><span class=\"ex\">crs\/rules\/REQUEST-905-COMMON-EXCEPTIONS.conf<\/span><\/span>\n<span id=\"cb3-4\"><a href=\"#cb3-4\" aria-hidden=\"true\"><\/a><span class=\"ex\">crs\/rules\/REQUEST-911-METHOD-ENFORCEMENT.conf<\/span><\/span>\n<span id=\"cb3-5\"><a href=\"#cb3-5\" aria-hidden=\"true\"><\/a><span class=\"ex\">crs\/rules\/REQUEST-913-SCANNER-DETECTION.conf<\/span><\/span>\n<span id=\"cb3-6\"><a href=\"#cb3-6\" aria-hidden=\"true\"><\/a><span class=\"ex\">crs\/rules\/REQUEST-920-PROTOCOL-ENFORCEMENT.conf<\/span><\/span>\n<span id=\"cb3-7\"><a href=\"#cb3-7\" aria-hidden=\"true\"><\/a><span class=\"ex\">crs\/rules\/REQUEST-921-PROTOCOL-ATTACK.conf<\/span><\/span>\n<span id=\"cb3-8\"><a href=\"#cb3-8\" aria-hidden=\"true\"><\/a><span class=\"ex\">crs\/rules\/REQUEST-922-MULTIPART-ATTACK.conf<\/span><\/span>\n<span id=\"cb3-9\"><a href=\"#cb3-9\" aria-hidden=\"true\"><\/a><span class=\"ex\">crs\/rules\/REQUEST-930-APPLICATION-ATTACK-LFI.conf<\/span><\/span>\n<span id=\"cb3-10\"><a href=\"#cb3-10\" aria-hidden=\"true\"><\/a><span class=\"ex\">crs\/rules\/REQUEST-931-APPLICATION-ATTACK-RFI.conf<\/span><\/span>\n<span id=\"cb3-11\"><a href=\"#cb3-11\" aria-hidden=\"true\"><\/a><span class=\"ex\">crs\/rules\/REQUEST-932-APPLICATION-ATTACK-RCE.conf<\/span><\/span>\n<span id=\"cb3-12\"><a href=\"#cb3-12\" aria-hidden=\"true\"><\/a><span class=\"ex\">crs\/rules\/REQUEST-933-APPLICATION-ATTACK-PHP.conf<\/span><\/span>\n<span id=\"cb3-13\"><a href=\"#cb3-13\" aria-hidden=\"true\"><\/a><span class=\"ex\">crs\/rules\/REQUEST-934-APPLICATION-ATTACK-GENERIC.conf<\/span><\/span>\n<span id=\"cb3-14\"><a href=\"#cb3-14\" aria-hidden=\"true\"><\/a><span class=\"ex\">crs\/rules\/REQUEST-941-APPLICATION-ATTACK-XSS.conf<\/span><\/span>\n<span id=\"cb3-15\"><a href=\"#cb3-15\" aria-hidden=\"true\"><\/a><span class=\"ex\">crs\/rules\/REQUEST-942-APPLICATION-ATTACK-SQLI.conf<\/span><\/span>\n<span id=\"cb3-16\"><a href=\"#cb3-16\" aria-hidden=\"true\"><\/a><span class=\"ex\">crs\/rules\/REQUEST-943-APPLICATION-ATTACK-SESSION-FIXATION.conf<\/span><\/span>\n<span id=\"cb3-17\"><a href=\"#cb3-17\" aria-hidden=\"true\"><\/a><span class=\"ex\">crs\/rules\/REQUEST-944-APPLICATION-ATTACK-JAVA.conf<\/span><\/span>\n<span id=\"cb3-18\"><a href=\"#cb3-18\" aria-hidden=\"true\"><\/a><span class=\"ex\">crs\/rules\/REQUEST-949-BLOCKING-EVALUATION.conf<\/span><\/span>\n<span id=\"cb3-19\"><a href=\"#cb3-19\" aria-hidden=\"true\"><\/a><span class=\"ex\">crs\/rules\/RESPONSE-950-DATA-LEAKAGES.conf<\/span><\/span>\n<span id=\"cb3-20\"><a href=\"#cb3-20\" aria-hidden=\"true\"><\/a><span class=\"ex\">crs\/rules\/RESPONSE-951-DATA-LEAKAGES-SQL.conf<\/span><\/span>\n<span id=\"cb3-21\"><a href=\"#cb3-21\" aria-hidden=\"true\"><\/a><span class=\"ex\">crs\/rules\/RESPONSE-952-DATA-LEAKAGES-JAVA.conf<\/span><\/span>\n<span id=\"cb3-22\"><a href=\"#cb3-22\" aria-hidden=\"true\"><\/a><span class=\"ex\">crs\/rules\/RESPONSE-953-DATA-LEAKAGES-PHP.conf<\/span><\/span>\n<span id=\"cb3-23\"><a href=\"#cb3-23\" aria-hidden=\"true\"><\/a><span class=\"ex\">crs\/rules\/RESPONSE-954-DATA-LEAKAGES-IIS.conf<\/span><\/span>\n<span id=\"cb3-24\"><a href=\"#cb3-24\" aria-hidden=\"true\"><\/a><span class=\"ex\">crs\/rules\/RESPONSE-955-WEB-SHELLS.conf<\/span><\/span>\n<span id=\"cb3-25\"><a href=\"#cb3-25\" aria-hidden=\"true\"><\/a><span class=\"ex\">crs\/rules\/RESPONSE-956-DATA-LEAKAGES-RUBY.conf<\/span><\/span>\n<span id=\"cb3-26\"><a href=\"#cb3-26\" aria-hidden=\"true\"><\/a><span class=\"ex\">crs\/rules\/RESPONSE-959-BLOCKING-EVALUATION.conf<\/span><\/span>\n<span id=\"cb3-27\"><a href=\"#cb3-27\" aria-hidden=\"true\"><\/a><span class=\"ex\">crs\/rules\/RESPONSE-980-CORRELATION.conf<\/span><\/span><\/code><\/pre><\/div>\n<p>The rule files are grouped by request and response rules. We start off with an initialization rule file. There are a lot of things commented out in the <code>crs-setup.conf<\/code> file. These values are simply set to their default value in the 901 rule file. This helps keep the config neat and tidy and still have all default settings applied. Then we have two application specific rule files for WordPress and Drupal, followed by an exceptions file that is mostly irrelevant to us. Starting with 910, we have the real rules.<\/p>\n<p>Every file is dedicated to a topic or type of attack. The CRS occupies the ID namespace from 900,000 to 999,999. The three digit long numbers in the filenames correspond to the first three digits of the IDs of the rules managed within the file. This means the IP reputation rules in <code>REQUEST-910-IP-REPUTATION.conf<\/code> will occupy the rule range 910,000 &#8211; 910,999. The method enforcement rules follow between 911,000 and 911,999, etc.. Some of these rule files are small and they do not use up their assigned rule range by far. Others are much bigger and the infamous SQL Injection rules run the risk of touching their ID ceiling one day.<\/p>\n<p>An important rule file is <code>REQUEST-949-BLOCKING-EVALUATION.conf<\/code>. This is where the anomaly score is checked against the inbound threshold and the request is blocked accordingly.<\/p>\n<p>Then begin the outbound rules, which are less numerous and basically check for code leakages (stack traces!) and leakages in error messages (which give an attacker useful information to construct an SQL injection attack). The outbound score is checked in the file with the 980 prefix.<\/p>\n<p>Some of the rules come with data files. These files have a <code>.data<\/code> extension and reside in the same folder with the rule files. Data files are typically used when the request has to be checked against a long list of keywords, like unwanted user agents or php function names. Have a look if you are interested.<\/p>\n<p>Before and after the rules <em>Include<\/em> directive in our Apache configuration file, there is a bit of configuration space reserved. This is where we will be handling false alarms in the future. Some of them are being treated before the rules are loaded in the configuration, some after the <em>Include<\/em> directive. We\u2019ll return to this later in this tutorial.<\/p>\n<p>For completeness, here is the complete Apache configuration including ModSecurity, CRS and all the other config bits from the earlier tutorials that we depend on:<\/p>\n<div class=\"sourceCode\" id=\"cb4\"><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=\"cb4-1\"><a href=\"#cb4-1\" aria-hidden=\"true\"><\/a><span class=\"ex\">ServerName<\/span>        localhost<\/span>\n<span id=\"cb4-2\"><a href=\"#cb4-2\" aria-hidden=\"true\"><\/a><span class=\"ex\">ServerAdmin<\/span>       root@localhost<\/span>\n<span id=\"cb4-3\"><a href=\"#cb4-3\" aria-hidden=\"true\"><\/a><span class=\"ex\">ServerRoot<\/span>        \/apache<\/span>\n<span id=\"cb4-4\"><a href=\"#cb4-4\" aria-hidden=\"true\"><\/a><span class=\"ex\">User<\/span>              www-data<\/span>\n<span id=\"cb4-5\"><a href=\"#cb4-5\" aria-hidden=\"true\"><\/a><span class=\"ex\">Group<\/span>             www-data<\/span>\n<span id=\"cb4-6\"><a href=\"#cb4-6\" aria-hidden=\"true\"><\/a><span class=\"ex\">PidFile<\/span>           logs\/httpd.pid<\/span>\n<span id=\"cb4-7\"><a href=\"#cb4-7\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-8\"><a href=\"#cb4-8\" aria-hidden=\"true\"><\/a><span class=\"ex\">ServerTokens<\/span>      Prod<\/span>\n<span id=\"cb4-9\"><a href=\"#cb4-9\" aria-hidden=\"true\"><\/a><span class=\"ex\">UseCanonicalName<\/span>  On<\/span>\n<span id=\"cb4-10\"><a href=\"#cb4-10\" aria-hidden=\"true\"><\/a><span class=\"ex\">TraceEnable<\/span>       Off<\/span>\n<span id=\"cb4-11\"><a href=\"#cb4-11\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-12\"><a href=\"#cb4-12\" aria-hidden=\"true\"><\/a><span class=\"ex\">Timeout<\/span>           10<\/span>\n<span id=\"cb4-13\"><a href=\"#cb4-13\" aria-hidden=\"true\"><\/a><span class=\"ex\">MaxRequestWorkers<\/span> 100<\/span>\n<span id=\"cb4-14\"><a href=\"#cb4-14\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-15\"><a href=\"#cb4-15\" aria-hidden=\"true\"><\/a><span class=\"ex\">Listen<\/span>            127.0.0.1:80<\/span>\n<span id=\"cb4-16\"><a href=\"#cb4-16\" aria-hidden=\"true\"><\/a><span class=\"ex\">Listen<\/span>            127.0.0.1:443<\/span>\n<span id=\"cb4-17\"><a href=\"#cb4-17\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-18\"><a href=\"#cb4-18\" aria-hidden=\"true\"><\/a><span class=\"ex\">LoadModule<\/span>        mpm_event_module        modules\/mod_mpm_event.so<\/span>\n<span id=\"cb4-19\"><a href=\"#cb4-19\" aria-hidden=\"true\"><\/a><span class=\"ex\">LoadModule<\/span>        unixd_module            modules\/mod_unixd.so<\/span>\n<span id=\"cb4-20\"><a href=\"#cb4-20\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-21\"><a href=\"#cb4-21\" aria-hidden=\"true\"><\/a><span class=\"ex\">LoadModule<\/span>        log_config_module       modules\/mod_log_config.so<\/span>\n<span id=\"cb4-22\"><a href=\"#cb4-22\" aria-hidden=\"true\"><\/a><span class=\"ex\">LoadModule<\/span>        logio_module            modules\/mod_logio.so<\/span>\n<span id=\"cb4-23\"><a href=\"#cb4-23\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-24\"><a href=\"#cb4-24\" aria-hidden=\"true\"><\/a><span class=\"ex\">LoadModule<\/span>        authn_core_module       modules\/mod_authn_core.so<\/span>\n<span id=\"cb4-25\"><a href=\"#cb4-25\" aria-hidden=\"true\"><\/a><span class=\"ex\">LoadModule<\/span>        authz_core_module       modules\/mod_authz_core.so<\/span>\n<span id=\"cb4-26\"><a href=\"#cb4-26\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-27\"><a href=\"#cb4-27\" aria-hidden=\"true\"><\/a><span class=\"ex\">LoadModule<\/span>        ssl_module              modules\/mod_ssl.so<\/span>\n<span id=\"cb4-28\"><a href=\"#cb4-28\" aria-hidden=\"true\"><\/a><span class=\"ex\">LoadModule<\/span>        headers_module          modules\/mod_headers.so<\/span>\n<span id=\"cb4-29\"><a href=\"#cb4-29\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-30\"><a href=\"#cb4-30\" aria-hidden=\"true\"><\/a><span class=\"ex\">LoadModule<\/span>        unique_id_module        modules\/mod_unique_id.so<\/span>\n<span id=\"cb4-31\"><a href=\"#cb4-31\" aria-hidden=\"true\"><\/a><span class=\"ex\">LoadModule<\/span>        security2_module        modules\/mod_security2.so<\/span>\n<span id=\"cb4-32\"><a href=\"#cb4-32\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-33\"><a href=\"#cb4-33\" aria-hidden=\"true\"><\/a><span class=\"ex\">ErrorLogFormat<\/span>          <span class=\"st\">&quot;[%{cu}t] [%-m:%-l] %-a %-L %M&quot;<\/span><\/span>\n<span id=\"cb4-34\"><a href=\"#cb4-34\" aria-hidden=\"true\"><\/a><span class=\"ex\">LogFormat<\/span> <span class=\"st\">&quot;%h %{GEOIP_COUNTRY_CODE}e %u [%{%Y-%m-%d %H:%M:%S}t.%{usec_frac}t] <\/span><span class=\"dt\">\\&quot;<\/span><span class=\"st\">%r<\/span><span class=\"dt\">\\&quot;<\/span><span class=\"st\"> %&gt;s %b \\<\/span><\/span>\n<span id=\"cb4-35\"><a href=\"#cb4-35\" aria-hidden=\"true\"><\/a><span class=\"dt\">\\&quot;<\/span><span class=\"st\">%{Referer}i<\/span><span class=\"dt\">\\&quot;<\/span><span class=\"st\"> <\/span><span class=\"dt\">\\&quot;<\/span><span class=\"st\">%{User-Agent}i<\/span><span class=\"dt\">\\&quot;<\/span><span class=\"st\"> <\/span><span class=\"dt\">\\&quot;<\/span><span class=\"st\">%{Content-Type}i<\/span><span class=\"dt\">\\&quot;<\/span><span class=\"st\"> %{remote}p %v %A %p %R \\<\/span><\/span>\n<span id=\"cb4-36\"><a href=\"#cb4-36\" aria-hidden=\"true\"><\/a><span class=\"st\">%{BALANCER_WORKER_ROUTE}e %X <\/span><span class=\"dt\">\\&quot;<\/span><span class=\"st\">%{cookie}n<\/span><span class=\"dt\">\\&quot;<\/span><span class=\"st\"> %{UNIQUE_ID}e %{SSL_PROTOCOL}x %{SSL_CIPHER}x \\<\/span><\/span>\n<span id=\"cb4-37\"><a href=\"#cb4-37\" aria-hidden=\"true\"><\/a><span class=\"st\">%I %O %{ratio}n%% %D %{ModSecTimeIn}e %{ApplicationTime}e %{ModSecTimeOut}e \\<\/span><\/span>\n<span id=\"cb4-38\"><a href=\"#cb4-38\" aria-hidden=\"true\"><\/a><span class=\"st\">%{ModSecAnomalyScoreInPLs}e %{ModSecAnomalyScoreOutPLs}e \\<\/span><\/span>\n<span id=\"cb4-39\"><a href=\"#cb4-39\" aria-hidden=\"true\"><\/a><span class=\"st\">%{ModSecAnomalyScoreIn}e %{ModSecAnomalyScoreOut}e&quot;<\/span> extended<\/span>\n<span id=\"cb4-40\"><a href=\"#cb4-40\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-41\"><a href=\"#cb4-41\" aria-hidden=\"true\"><\/a><span class=\"ex\">LogFormat<\/span> <span class=\"st\">&quot;[%{%Y-%m-%d %H:%M:%S}t.%{usec_frac}t] %{UNIQUE_ID}e %D \\<\/span><\/span>\n<span id=\"cb4-42\"><a href=\"#cb4-42\" aria-hidden=\"true\"><\/a><span class=\"st\">PerfModSecInbound: %{TX.perf_modsecinbound}M \\<\/span><\/span>\n<span id=\"cb4-43\"><a href=\"#cb4-43\" aria-hidden=\"true\"><\/a><span class=\"st\">PerfAppl: %{TX.perf_application}M \\<\/span><\/span>\n<span id=\"cb4-44\"><a href=\"#cb4-44\" aria-hidden=\"true\"><\/a><span class=\"st\">PerfModSecOutbound: %{TX.perf_modsecoutbound}M \\<\/span><\/span>\n<span id=\"cb4-45\"><a href=\"#cb4-45\" aria-hidden=\"true\"><\/a><span class=\"st\">TS-Phase1: %{TX.ModSecTimestamp1start}M-%{TX.ModSecTimestamp1end}M \\<\/span><\/span>\n<span id=\"cb4-46\"><a href=\"#cb4-46\" aria-hidden=\"true\"><\/a><span class=\"st\">TS-Phase2: %{TX.ModSecTimestamp2start}M-%{TX.ModSecTimestamp2end}M \\<\/span><\/span>\n<span id=\"cb4-47\"><a href=\"#cb4-47\" aria-hidden=\"true\"><\/a><span class=\"st\">TS-Phase3: %{TX.ModSecTimestamp3start}M-%{TX.ModSecTimestamp3end}M \\<\/span><\/span>\n<span id=\"cb4-48\"><a href=\"#cb4-48\" aria-hidden=\"true\"><\/a><span class=\"st\">TS-Phase4: %{TX.ModSecTimestamp4start}M-%{TX.ModSecTimestamp4end}M \\<\/span><\/span>\n<span id=\"cb4-49\"><a href=\"#cb4-49\" aria-hidden=\"true\"><\/a><span class=\"st\">TS-Phase5: %{TX.ModSecTimestamp5start}M-%{TX.ModSecTimestamp5end}M \\<\/span><\/span>\n<span id=\"cb4-50\"><a href=\"#cb4-50\" aria-hidden=\"true\"><\/a><span class=\"st\">Perf-Phase1: %{PERF_PHASE1}M \\<\/span><\/span>\n<span id=\"cb4-51\"><a href=\"#cb4-51\" aria-hidden=\"true\"><\/a><span class=\"st\">Perf-Phase2: %{PERF_PHASE2}M \\<\/span><\/span>\n<span id=\"cb4-52\"><a href=\"#cb4-52\" aria-hidden=\"true\"><\/a><span class=\"st\">Perf-Phase3: %{PERF_PHASE3}M \\<\/span><\/span>\n<span id=\"cb4-53\"><a href=\"#cb4-53\" aria-hidden=\"true\"><\/a><span class=\"st\">Perf-Phase4: %{PERF_PHASE4}M \\<\/span><\/span>\n<span id=\"cb4-54\"><a href=\"#cb4-54\" aria-hidden=\"true\"><\/a><span class=\"st\">Perf-Phase5: %{PERF_PHASE5}M \\<\/span><\/span>\n<span id=\"cb4-55\"><a href=\"#cb4-55\" aria-hidden=\"true\"><\/a><span class=\"st\">Perf-ReadingStorage: %{PERF_SREAD}M \\<\/span><\/span>\n<span id=\"cb4-56\"><a href=\"#cb4-56\" aria-hidden=\"true\"><\/a><span class=\"st\">Perf-WritingStorage: %{PERF_SWRITE}M \\<\/span><\/span>\n<span id=\"cb4-57\"><a href=\"#cb4-57\" aria-hidden=\"true\"><\/a><span class=\"st\">Perf-GarbageCollection: %{PERF_GC}M \\<\/span><\/span>\n<span id=\"cb4-58\"><a href=\"#cb4-58\" aria-hidden=\"true\"><\/a><span class=\"st\">Perf-ModSecLogging: %{PERF_LOGGING}M \\<\/span><\/span>\n<span id=\"cb4-59\"><a href=\"#cb4-59\" aria-hidden=\"true\"><\/a><span class=\"st\">Perf-ModSecCombined: %{PERF_COMBINED}M&quot;<\/span> perflog<\/span>\n<span id=\"cb4-60\"><a href=\"#cb4-60\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-61\"><a href=\"#cb4-61\" aria-hidden=\"true\"><\/a><span class=\"ex\">LogLevel<\/span>                      debug<\/span>\n<span id=\"cb4-62\"><a href=\"#cb4-62\" aria-hidden=\"true\"><\/a><span class=\"ex\">ErrorLog<\/span>                      logs\/error.log<\/span>\n<span id=\"cb4-63\"><a href=\"#cb4-63\" aria-hidden=\"true\"><\/a><span class=\"ex\">CustomLog<\/span>                     logs\/access.log extended<\/span>\n<span id=\"cb4-64\"><a href=\"#cb4-64\" aria-hidden=\"true\"><\/a><span class=\"ex\">CustomLog<\/span>                     logs\/modsec-perf.log perflog env=write_perflog<\/span>\n<span id=\"cb4-65\"><a href=\"#cb4-65\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-66\"><a href=\"#cb4-66\" aria-hidden=\"true\"><\/a><span class=\"co\"># == ModSec Base Configuration<\/span><\/span>\n<span id=\"cb4-67\"><a href=\"#cb4-67\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-68\"><a href=\"#cb4-68\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecRuleEngine<\/span>                 On<\/span>\n<span id=\"cb4-69\"><a href=\"#cb4-69\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-70\"><a href=\"#cb4-70\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecRequestBodyAccess<\/span>          On<\/span>\n<span id=\"cb4-71\"><a href=\"#cb4-71\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecRequestBodyLimit<\/span>           10000000<\/span>\n<span id=\"cb4-72\"><a href=\"#cb4-72\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecRequestBodyNoFilesLimit<\/span>    64000<\/span>\n<span id=\"cb4-73\"><a href=\"#cb4-73\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-74\"><a href=\"#cb4-74\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecResponseBodyAccess<\/span>         On<\/span>\n<span id=\"cb4-75\"><a href=\"#cb4-75\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecResponseBodyLimit<\/span>          10000000<\/span>\n<span id=\"cb4-76\"><a href=\"#cb4-76\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-77\"><a href=\"#cb4-77\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecPcreMatchLimit<\/span>             100000<\/span>\n<span id=\"cb4-78\"><a href=\"#cb4-78\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecPcreMatchLimitRecursion<\/span>    100000<\/span>\n<span id=\"cb4-79\"><a href=\"#cb4-79\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecRequestBodyJsonDepthLimit<\/span>  16<\/span>\n<span id=\"cb4-80\"><a href=\"#cb4-80\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-81\"><a href=\"#cb4-81\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecTmpDir<\/span>                     \/tmp\/<\/span>\n<span id=\"cb4-82\"><a href=\"#cb4-82\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecUploadDir<\/span>                  \/tmp\/<\/span>\n<span id=\"cb4-83\"><a href=\"#cb4-83\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecDataDir<\/span>                    \/tmp\/<\/span>\n<span id=\"cb4-84\"><a href=\"#cb4-84\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-85\"><a href=\"#cb4-85\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecDebugLog<\/span>                   \/apache\/logs\/modsec_debug.log<\/span>\n<span id=\"cb4-86\"><a href=\"#cb4-86\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecDebugLogLevel<\/span>              0<\/span>\n<span id=\"cb4-87\"><a href=\"#cb4-87\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-88\"><a href=\"#cb4-88\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecAuditEngine<\/span>                RelevantOnly<\/span>\n<span id=\"cb4-89\"><a href=\"#cb4-89\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecAuditLogRelevantStatus<\/span>     <span class=\"st\">&quot;^(?:5|4(?!04))&quot;<\/span><\/span>\n<span id=\"cb4-90\"><a href=\"#cb4-90\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecAuditLogParts<\/span>              ABIJEFHKZ<\/span>\n<span id=\"cb4-91\"><a href=\"#cb4-91\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-92\"><a href=\"#cb4-92\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecAuditLogType<\/span>               Concurrent<\/span>\n<span id=\"cb4-93\"><a href=\"#cb4-93\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecAuditLog<\/span>                   \/apache\/logs\/modsec_audit.log<\/span>\n<span id=\"cb4-94\"><a href=\"#cb4-94\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecAuditLogStorageDir<\/span>         \/apache\/logs\/audit\/<\/span>\n<span id=\"cb4-95\"><a href=\"#cb4-95\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-96\"><a href=\"#cb4-96\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecDefaultAction<\/span>              <span class=\"st\">&quot;phase:2,pass,log,tag:&#39;Local Lab Service&#39;&quot;<\/span><\/span>\n<span id=\"cb4-97\"><a href=\"#cb4-97\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-98\"><a href=\"#cb4-98\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-99\"><a href=\"#cb4-99\" aria-hidden=\"true\"><\/a><span class=\"co\"># == ModSec Rule ID Namespace Definition<\/span><\/span>\n<span id=\"cb4-100\"><a href=\"#cb4-100\" aria-hidden=\"true\"><\/a><span class=\"co\"># Service-specific before CRS: 10000 -  49999<\/span><\/span>\n<span id=\"cb4-101\"><a href=\"#cb4-101\" aria-hidden=\"true\"><\/a><span class=\"co\"># Service-specific after CRS:  50000 -  79999<\/span><\/span>\n<span id=\"cb4-102\"><a href=\"#cb4-102\" aria-hidden=\"true\"><\/a><span class=\"co\"># Locally shared rules:                  80000 -  99999<\/span><\/span>\n<span id=\"cb4-103\"><a href=\"#cb4-103\" aria-hidden=\"true\"><\/a><span class=\"co\">#  - Performance:                        90000 -  90199<\/span><\/span>\n<span id=\"cb4-104\"><a href=\"#cb4-104\" aria-hidden=\"true\"><\/a><span class=\"co\"># Recommended ModSec Rules (few):       200000 - 200010<\/span><\/span>\n<span id=\"cb4-105\"><a href=\"#cb4-105\" aria-hidden=\"true\"><\/a><span class=\"co\"># OWASP CRS:                  900000 - 999999<\/span><\/span>\n<span id=\"cb4-106\"><a href=\"#cb4-106\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-107\"><a href=\"#cb4-107\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-108\"><a href=\"#cb4-108\" aria-hidden=\"true\"><\/a><span class=\"co\"># === ModSec timestamps at the start of each phase (ids: 90000 - 90009)<\/span><\/span>\n<span id=\"cb4-109\"><a href=\"#cb4-109\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-110\"><a href=\"#cb4-110\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecAction<\/span> <span class=\"st\">&quot;id:90000,phase:1,nolog,pass,setvar:TX.ModSecTimestamp1start=%{DURATION}&quot;<\/span><\/span>\n<span id=\"cb4-111\"><a href=\"#cb4-111\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecAction<\/span> <span class=\"st\">&quot;id:90001,phase:2,nolog,pass,setvar:TX.ModSecTimestamp2start=%{DURATION}&quot;<\/span><\/span>\n<span id=\"cb4-112\"><a href=\"#cb4-112\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecAction<\/span> <span class=\"st\">&quot;id:90002,phase:3,nolog,pass,setvar:TX.ModSecTimestamp3start=%{DURATION}&quot;<\/span><\/span>\n<span id=\"cb4-113\"><a href=\"#cb4-113\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecAction<\/span> <span class=\"st\">&quot;id:90003,phase:4,nolog,pass,setvar:TX.ModSecTimestamp4start=%{DURATION}&quot;<\/span><\/span>\n<span id=\"cb4-114\"><a href=\"#cb4-114\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecAction<\/span> <span class=\"st\">&quot;id:90004,phase:5,nolog,pass,setvar:TX.ModSecTimestamp5start=%{DURATION}&quot;<\/span><\/span>\n<span id=\"cb4-115\"><a href=\"#cb4-115\" aria-hidden=\"true\"><\/a>                      <\/span>\n<span id=\"cb4-116\"><a href=\"#cb4-116\" aria-hidden=\"true\"><\/a><span class=\"co\"># SecRule REQUEST_FILENAME &quot;@beginsWith \/&quot; &quot;id:90005,phase:5,t:none,nolog,noauditlog,pass,\\<\/span><\/span>\n<span id=\"cb4-117\"><a href=\"#cb4-117\" aria-hidden=\"true\"><\/a><span class=\"co\"># setenv:write_perflog&quot;<\/span><\/span>\n<span id=\"cb4-118\"><a href=\"#cb4-118\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-119\"><a href=\"#cb4-119\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-120\"><a href=\"#cb4-120\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-121\"><a href=\"#cb4-121\" aria-hidden=\"true\"><\/a><span class=\"co\"># === ModSec Recommended Rules (in modsec src package) (ids: 200000-200010)<\/span><\/span>\n<span id=\"cb4-122\"><a href=\"#cb4-122\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-123\"><a href=\"#cb4-123\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecRule<\/span> REQUEST_HEADERS:Content-Type <span class=\"st\">&quot;(?:application(?:\/soap\\+|\/)|text\/)xml&quot;<\/span> <span class=\"kw\">\\<\/span><\/span>\n<span id=\"cb4-124\"><a href=\"#cb4-124\" aria-hidden=\"true\"><\/a>  <span class=\"st\">&quot;id:200000,phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML&quot;<\/span><\/span>\n<span id=\"cb4-125\"><a href=\"#cb4-125\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-126\"><a href=\"#cb4-126\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecRule<\/span> REQUEST_HEADERS:Content-Type <span class=\"st\">&quot;application\/json&quot;<\/span> <span class=\"kw\">\\<\/span><\/span>\n<span id=\"cb4-127\"><a href=\"#cb4-127\" aria-hidden=\"true\"><\/a>  <span class=\"st\">&quot;id:200001,phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON&quot;<\/span><\/span>\n<span id=\"cb4-128\"><a href=\"#cb4-128\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-129\"><a href=\"#cb4-129\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecRule<\/span> REQBODY_ERROR <span class=\"st\">&quot;!@eq 0&quot;<\/span> <span class=\"kw\">\\<\/span><\/span>\n<span id=\"cb4-130\"><a href=\"#cb4-130\" aria-hidden=\"true\"><\/a>  <span class=\"st\">&quot;id:200002,phase:2,t:none,deny,status:400,log,msg:&#39;Failed to parse request body.&#39;,\\<\/span><\/span>\n<span id=\"cb4-131\"><a href=\"#cb4-131\" aria-hidden=\"true\"><\/a><span class=\"st\">  logdata:&#39;%{reqbody_error_msg}&#39;,severity:2&quot;<\/span><\/span>\n<span id=\"cb4-132\"><a href=\"#cb4-132\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-133\"><a href=\"#cb4-133\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecRule<\/span> MULTIPART_STRICT_ERROR <span class=\"st\">&quot;!@eq 0&quot;<\/span> <span class=\"kw\">\\<\/span><\/span>\n<span id=\"cb4-134\"><a href=\"#cb4-134\" aria-hidden=\"true\"><\/a><span class=\"st\">&quot;id:200003,phase:2,t:none,log,deny,status:403, \\<\/span><\/span>\n<span id=\"cb4-135\"><a href=\"#cb4-135\" aria-hidden=\"true\"><\/a><span class=\"st\">msg:&#39;Multipart request body failed strict validation: \\<\/span><\/span>\n<span id=\"cb4-136\"><a href=\"#cb4-136\" aria-hidden=\"true\"><\/a><span class=\"st\">PE %{REQBODY_PROCESSOR_ERROR}, \\<\/span><\/span>\n<span id=\"cb4-137\"><a href=\"#cb4-137\" aria-hidden=\"true\"><\/a><span class=\"st\">BQ %{MULTIPART_BOUNDARY_QUOTED}, \\<\/span><\/span>\n<span id=\"cb4-138\"><a href=\"#cb4-138\" aria-hidden=\"true\"><\/a><span class=\"st\">BW %{MULTIPART_BOUNDARY_WHITESPACE}, \\<\/span><\/span>\n<span id=\"cb4-139\"><a href=\"#cb4-139\" aria-hidden=\"true\"><\/a><span class=\"st\">DB %{MULTIPART_DATA_BEFORE}, \\<\/span><\/span>\n<span id=\"cb4-140\"><a href=\"#cb4-140\" aria-hidden=\"true\"><\/a><span class=\"st\">DA %{MULTIPART_DATA_AFTER}, \\<\/span><\/span>\n<span id=\"cb4-141\"><a href=\"#cb4-141\" aria-hidden=\"true\"><\/a><span class=\"st\">HF %{MULTIPART_HEADER_FOLDING}, \\<\/span><\/span>\n<span id=\"cb4-142\"><a href=\"#cb4-142\" aria-hidden=\"true\"><\/a><span class=\"st\">LF %{MULTIPART_LF_LINE}, \\<\/span><\/span>\n<span id=\"cb4-143\"><a href=\"#cb4-143\" aria-hidden=\"true\"><\/a><span class=\"st\">SM %{MULTIPART_MISSING_SEMICOLON}, \\<\/span><\/span>\n<span id=\"cb4-144\"><a href=\"#cb4-144\" aria-hidden=\"true\"><\/a><span class=\"st\">IQ %{MULTIPART_INVALID_QUOTING}, \\<\/span><\/span>\n<span id=\"cb4-145\"><a href=\"#cb4-145\" aria-hidden=\"true\"><\/a><span class=\"st\">IP %{MULTIPART_INVALID_PART}, \\<\/span><\/span>\n<span id=\"cb4-146\"><a href=\"#cb4-146\" aria-hidden=\"true\"><\/a><span class=\"st\">IH %{MULTIPART_INVALID_HEADER_FOLDING}, \\<\/span><\/span>\n<span id=\"cb4-147\"><a href=\"#cb4-147\" aria-hidden=\"true\"><\/a><span class=\"st\">FL %{MULTIPART_FILE_LIMIT_EXCEEDED}&#39;&quot;<\/span><\/span>\n<span id=\"cb4-148\"><a href=\"#cb4-148\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-149\"><a href=\"#cb4-149\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecRule<\/span> TX:\/^MSC_\/ <span class=\"st\">&quot;!@streq 0&quot;<\/span> <span class=\"kw\">\\<\/span><\/span>\n<span id=\"cb4-150\"><a href=\"#cb4-150\" aria-hidden=\"true\"><\/a>  <span class=\"st\">&quot;id:200005,phase:2,t:none,deny,status:500,\\<\/span><\/span>\n<span id=\"cb4-151\"><a href=\"#cb4-151\" aria-hidden=\"true\"><\/a><span class=\"st\">  msg:&#39;ModSecurity internal error flagged: %{MATCHED_VAR_NAME}&#39;&quot;<\/span><\/span>\n<span id=\"cb4-152\"><a href=\"#cb4-152\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-153\"><a href=\"#cb4-153\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-154\"><a href=\"#cb4-154\" aria-hidden=\"true\"><\/a><span class=\"co\"># === ModSec CRS Base Configuration (ids: 900000-900999)<\/span><\/span>\n<span id=\"cb4-155\"><a href=\"#cb4-155\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-156\"><a href=\"#cb4-156\" aria-hidden=\"true\"><\/a><span class=\"ex\">Include<\/span>    \/apache\/conf\/crs\/crs-setup.conf<\/span>\n<span id=\"cb4-157\"><a href=\"#cb4-157\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-158\"><a href=\"#cb4-158\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecAction<\/span> <span class=\"st\">&quot;id:900110,phase:1,pass,nolog,\\<\/span><\/span>\n<span id=\"cb4-159\"><a href=\"#cb4-159\" aria-hidden=\"true\"><\/a><span class=\"st\">  setvar:tx.inbound_anomaly_score_threshold=10000,\\<\/span><\/span>\n<span id=\"cb4-160\"><a href=\"#cb4-160\" aria-hidden=\"true\"><\/a><span class=\"st\">  setvar:tx.outbound_anomaly_score_threshold=10000,\\<\/span><\/span>\n<span id=\"cb4-161\"><a href=\"#cb4-161\" aria-hidden=\"true\"><\/a><span class=\"st\">  setvar:tx.blocking_paranoia_level=1,\\<\/span><\/span>\n<span id=\"cb4-162\"><a href=\"#cb4-162\" aria-hidden=\"true\"><\/a><span class=\"st\">  setvar:tx.reporting_level=0&quot;<\/span><\/span>\n<span id=\"cb4-163\"><a href=\"#cb4-163\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-164\"><a href=\"#cb4-164\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-165\"><a href=\"#cb4-165\" aria-hidden=\"true\"><\/a><span class=\"co\"># === ModSec CRS: Runtime Exclusion Rules (ids: 10000-49999)<\/span><\/span>\n<span id=\"cb4-166\"><a href=\"#cb4-166\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-167\"><a href=\"#cb4-167\" aria-hidden=\"true\"><\/a><span class=\"co\"># ...<\/span><\/span>\n<span id=\"cb4-168\"><a href=\"#cb4-168\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-169\"><a href=\"#cb4-169\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-170\"><a href=\"#cb4-170\" aria-hidden=\"true\"><\/a><span class=\"co\"># === CRS and CRS Plugin Inclusion<\/span><\/span>\n<span id=\"cb4-171\"><a href=\"#cb4-171\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-172\"><a href=\"#cb4-172\" aria-hidden=\"true\"><\/a><span class=\"ex\">Include<\/span> \/apache\/conf\/crs\/plugins\/*-config.conf<\/span>\n<span id=\"cb4-173\"><a href=\"#cb4-173\" aria-hidden=\"true\"><\/a><span class=\"ex\">Include<\/span> \/apache\/conf\/crs\/plugins\/*-before.conf<\/span>\n<span id=\"cb4-174\"><a href=\"#cb4-174\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-175\"><a href=\"#cb4-175\" aria-hidden=\"true\"><\/a><span class=\"ex\">Include<\/span> \/apache\/conf\/crs\/rules\/*.conf<\/span>\n<span id=\"cb4-176\"><a href=\"#cb4-176\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-177\"><a href=\"#cb4-177\" aria-hidden=\"true\"><\/a><span class=\"ex\">Include<\/span> \/apache\/conf\/crs\/plugins\/*-after.conf<\/span>\n<span id=\"cb4-178\"><a href=\"#cb4-178\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-179\"><a href=\"#cb4-179\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-180\"><a href=\"#cb4-180\" aria-hidden=\"true\"><\/a><span class=\"co\"># === ModSec CRS: Startup Time Rules Exclusions<\/span><\/span>\n<span id=\"cb4-181\"><a href=\"#cb4-181\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-182\"><a href=\"#cb4-182\" aria-hidden=\"true\"><\/a><span class=\"co\"># ...<\/span><\/span>\n<span id=\"cb4-183\"><a href=\"#cb4-183\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-184\"><a href=\"#cb4-184\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-185\"><a href=\"#cb4-185\" aria-hidden=\"true\"><\/a><span class=\"co\"># === ModSec Timestamps at the End of Each Phase (ids: 90010 - 90019)<\/span><\/span>\n<span id=\"cb4-186\"><a href=\"#cb4-186\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-187\"><a href=\"#cb4-187\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecAction<\/span> <span class=\"st\">&quot;id:90010,phase:1,pass,nolog,setvar:TX.ModSecTimestamp1end=%{DURATION}&quot;<\/span><\/span>\n<span id=\"cb4-188\"><a href=\"#cb4-188\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecAction<\/span> <span class=\"st\">&quot;id:90011,phase:2,pass,nolog,setvar:TX.ModSecTimestamp2end=%{DURATION}&quot;<\/span><\/span>\n<span id=\"cb4-189\"><a href=\"#cb4-189\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecAction<\/span> <span class=\"st\">&quot;id:90012,phase:3,pass,nolog,setvar:TX.ModSecTimestamp3end=%{DURATION}&quot;<\/span><\/span>\n<span id=\"cb4-190\"><a href=\"#cb4-190\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecAction<\/span> <span class=\"st\">&quot;id:90013,phase:4,pass,nolog,setvar:TX.ModSecTimestamp4end=%{DURATION}&quot;<\/span><\/span>\n<span id=\"cb4-191\"><a href=\"#cb4-191\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecAction<\/span> <span class=\"st\">&quot;id:90014,phase:5,pass,nolog,setvar:TX.ModSecTimestamp5end=%{DURATION}&quot;<\/span><\/span>\n<span id=\"cb4-192\"><a href=\"#cb4-192\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-193\"><a href=\"#cb4-193\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-194\"><a href=\"#cb4-194\" aria-hidden=\"true\"><\/a><span class=\"co\"># === ModSec performance calculations and variable export (ids: 90100 - 90199)<\/span><\/span>\n<span id=\"cb4-195\"><a href=\"#cb4-195\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-196\"><a href=\"#cb4-196\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecAction<\/span> <span class=\"st\">&quot;id:90100,phase:5,pass,nolog,\\<\/span><\/span>\n<span id=\"cb4-197\"><a href=\"#cb4-197\" aria-hidden=\"true\"><\/a><span class=\"st\">  setvar:TX.perf_modsecinbound=%{PERF_PHASE1},\\<\/span><\/span>\n<span id=\"cb4-198\"><a href=\"#cb4-198\" aria-hidden=\"true\"><\/a><span class=\"st\">  setvar:TX.perf_modsecinbound=+%{PERF_PHASE2},\\<\/span><\/span>\n<span id=\"cb4-199\"><a href=\"#cb4-199\" aria-hidden=\"true\"><\/a><span class=\"st\">  setvar:TX.perf_application=%{TX.ModSecTimestamp3start},\\<\/span><\/span>\n<span id=\"cb4-200\"><a href=\"#cb4-200\" aria-hidden=\"true\"><\/a><span class=\"st\">  setvar:TX.perf_application=-%{TX.ModSecTimestamp2end},\\<\/span><\/span>\n<span id=\"cb4-201\"><a href=\"#cb4-201\" aria-hidden=\"true\"><\/a><span class=\"st\">  setvar:TX.perf_modsecoutbound=%{PERF_PHASE3},\\<\/span><\/span>\n<span id=\"cb4-202\"><a href=\"#cb4-202\" aria-hidden=\"true\"><\/a><span class=\"st\">  setvar:TX.perf_modsecoutbound=+%{PERF_PHASE4},\\<\/span><\/span>\n<span id=\"cb4-203\"><a href=\"#cb4-203\" aria-hidden=\"true\"><\/a><span class=\"st\">  setenv:ModSecTimeIn=%{TX.perf_modsecinbound},\\<\/span><\/span>\n<span id=\"cb4-204\"><a href=\"#cb4-204\" aria-hidden=\"true\"><\/a><span class=\"st\">  setenv:ApplicationTime=%{TX.perf_application},\\<\/span><\/span>\n<span id=\"cb4-205\"><a href=\"#cb4-205\" aria-hidden=\"true\"><\/a><span class=\"st\">  setenv:ModSecTimeOut=%{TX.perf_modsecoutbound},\\<\/span><\/span>\n<span id=\"cb4-206\"><a href=\"#cb4-206\" aria-hidden=\"true\"><\/a><span class=\"st\">  setenv:ModSecAnomalyScoreInPLs=%{TX.inbound_anomaly_score_pl1}-%{TX.inbound_anomaly_score_pl2}-%{TX.inbound_anomaly_score_pl3}-%{TX.inbound_anomaly_score_pl4},\\<\/span><\/span>\n<span id=\"cb4-207\"><a href=\"#cb4-207\" aria-hidden=\"true\"><\/a><span class=\"st\">  setenv:ModSecAnomalyScoreOutPLs=%{TX.outbound_anomaly_score_pl1}-%{TX.outbound_anomaly_score_pl2}-%{TX.outbound_anomaly_score_pl3}-%{TX.outbound_anomaly_score_pl4},\\<\/span><\/span>\n<span id=\"cb4-208\"><a href=\"#cb4-208\" aria-hidden=\"true\"><\/a><span class=\"st\">  setenv:ModSecAnomalyScoreIn=%{TX.blocking_inbound_anomaly_score},\\<\/span><\/span>\n<span id=\"cb4-209\"><a href=\"#cb4-209\" aria-hidden=\"true\"><\/a><span class=\"st\">  setenv:ModSecAnomalyScoreOut=%{TX.blocking_outbound_anomaly_score}&quot;<\/span><\/span>\n<span id=\"cb4-210\"><a href=\"#cb4-210\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-211\"><a href=\"#cb4-211\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-212\"><a href=\"#cb4-212\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-213\"><a href=\"#cb4-213\" aria-hidden=\"true\"><\/a><span class=\"ex\">SSLCertificateKeyFile<\/span>   \/etc\/ssl\/private\/ssl-cert-snakeoil.key<\/span>\n<span id=\"cb4-214\"><a href=\"#cb4-214\" aria-hidden=\"true\"><\/a><span class=\"ex\">SSLCertificateFile<\/span>      \/etc\/ssl\/certs\/ssl-cert-snakeoil.pem<\/span>\n<span id=\"cb4-215\"><a href=\"#cb4-215\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-216\"><a href=\"#cb4-216\" aria-hidden=\"true\"><\/a><span class=\"ex\">SSLProtocol<\/span>             All -SSLv2 -SSLv3 -TLSv1 -TLSv1.1<\/span>\n<span id=\"cb4-217\"><a href=\"#cb4-217\" aria-hidden=\"true\"><\/a><span class=\"ex\">SSLCipherSuite<\/span>          <span class=\"st\">&#39;kEECDH+ECDSA kEECDH kEDH HIGH +SHA !aNULL !eNULL !LOW !MEDIUM !MD5 !EXP !DSS \\<\/span><\/span>\n<span id=\"cb4-218\"><a href=\"#cb4-218\" aria-hidden=\"true\"><\/a><span class=\"st\">!PSK !SRP !kECDH !CAMELLIA !RC4&#39;<\/span><\/span>\n<span id=\"cb4-219\"><a href=\"#cb4-219\" aria-hidden=\"true\"><\/a><span class=\"ex\">SSLHonorCipherOrder<\/span>     On<\/span>\n<span id=\"cb4-220\"><a href=\"#cb4-220\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-221\"><a href=\"#cb4-221\" aria-hidden=\"true\"><\/a><span class=\"ex\">SSLRandomSeed<\/span>           startup file:\/dev\/urandom 2048<\/span>\n<span id=\"cb4-222\"><a href=\"#cb4-222\" aria-hidden=\"true\"><\/a><span class=\"ex\">SSLRandomSeed<\/span>           connect builtin<\/span>\n<span id=\"cb4-223\"><a href=\"#cb4-223\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-224\"><a href=\"#cb4-224\" aria-hidden=\"true\"><\/a><span class=\"ex\">DocumentRoot<\/span>        \/apache\/htdocs<\/span>\n<span id=\"cb4-225\"><a href=\"#cb4-225\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-226\"><a href=\"#cb4-226\" aria-hidden=\"true\"><\/a><span class=\"op\">&lt;<\/span><span class=\"ex\">Directory<\/span> \/<span class=\"op\">&gt;<\/span><\/span>\n<span id=\"cb4-227\"><a href=\"#cb4-227\" aria-hidden=\"true\"><\/a>      <\/span>\n<span id=\"cb4-228\"><a href=\"#cb4-228\" aria-hidden=\"true\"><\/a>    <span class=\"ex\">Require<\/span> all denied<\/span>\n<span id=\"cb4-229\"><a href=\"#cb4-229\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-230\"><a href=\"#cb4-230\" aria-hidden=\"true\"><\/a>    <span class=\"ex\">Options<\/span> SymLinksIfOwnerMatch<\/span>\n<span id=\"cb4-231\"><a href=\"#cb4-231\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-232\"><a href=\"#cb4-232\" aria-hidden=\"true\"><\/a><span class=\"op\">&lt;<\/span>\/<span class=\"ex\">Directory<\/span><span class=\"op\">&gt;<\/span><\/span>\n<span id=\"cb4-233\"><a href=\"#cb4-233\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-234\"><a href=\"#cb4-234\" aria-hidden=\"true\"><\/a><span class=\"op\">&lt;<\/span><span class=\"ex\">VirtualHost<\/span> 127.0.0.1:<span class=\"op\">80&gt;<\/span><\/span>\n<span id=\"cb4-235\"><a href=\"#cb4-235\" aria-hidden=\"true\"><\/a>      <\/span>\n<span id=\"cb4-236\"><a href=\"#cb4-236\" aria-hidden=\"true\"><\/a>      <span class=\"op\">&lt;<\/span><span class=\"ex\">Directory<\/span> \/apache\/htdocs<span class=\"op\">&gt;<\/span><\/span>\n<span id=\"cb4-237\"><a href=\"#cb4-237\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-238\"><a href=\"#cb4-238\" aria-hidden=\"true\"><\/a>        <span class=\"ex\">Require<\/span> all granted<\/span>\n<span id=\"cb4-239\"><a href=\"#cb4-239\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-240\"><a href=\"#cb4-240\" aria-hidden=\"true\"><\/a>        <span class=\"ex\">Options<\/span> None<\/span>\n<span id=\"cb4-241\"><a href=\"#cb4-241\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-242\"><a href=\"#cb4-242\" aria-hidden=\"true\"><\/a>      <span class=\"op\">&lt;<\/span>\/<span class=\"ex\">Directory<\/span><span class=\"op\">&gt;<\/span><\/span>\n<span id=\"cb4-243\"><a href=\"#cb4-243\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-244\"><a href=\"#cb4-244\" aria-hidden=\"true\"><\/a><span class=\"op\">&lt;<\/span>\/<span class=\"ex\">VirtualHost<\/span><span class=\"op\">&gt;<\/span><\/span>\n<span id=\"cb4-245\"><a href=\"#cb4-245\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-246\"><a href=\"#cb4-246\" aria-hidden=\"true\"><\/a><span class=\"op\">&lt;<\/span><span class=\"ex\">VirtualHost<\/span> 127.0.0.1:<span class=\"op\">443&gt;<\/span><\/span>\n<span id=\"cb4-247\"><a href=\"#cb4-247\" aria-hidden=\"true\"><\/a>    <\/span>\n<span id=\"cb4-248\"><a href=\"#cb4-248\" aria-hidden=\"true\"><\/a>      <span class=\"ex\">SSLEngine<\/span> On<\/span>\n<span id=\"cb4-249\"><a href=\"#cb4-249\" aria-hidden=\"true\"><\/a>      <span class=\"ex\">Header<\/span> always set Strict-Transport-Security <span class=\"st\">&quot;max-age=31536000; includeSubDomains&quot;<\/span> env=HTTPS<\/span>\n<span id=\"cb4-250\"><a href=\"#cb4-250\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-251\"><a href=\"#cb4-251\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-252\"><a href=\"#cb4-252\" aria-hidden=\"true\"><\/a>      <span class=\"op\">&lt;<\/span><span class=\"ex\">Directory<\/span> \/apache\/htdocs<span class=\"op\">&gt;<\/span><\/span>\n<span id=\"cb4-253\"><a href=\"#cb4-253\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-254\"><a href=\"#cb4-254\" aria-hidden=\"true\"><\/a>              <span class=\"ex\">Require<\/span> all granted<\/span>\n<span id=\"cb4-255\"><a href=\"#cb4-255\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-256\"><a href=\"#cb4-256\" aria-hidden=\"true\"><\/a>              <span class=\"ex\">Options<\/span> None<\/span>\n<span id=\"cb4-257\"><a href=\"#cb4-257\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-258\"><a href=\"#cb4-258\" aria-hidden=\"true\"><\/a>      <span class=\"op\">&lt;<\/span>\/<span class=\"ex\">Directory<\/span><span class=\"op\">&gt;<\/span><\/span>\n<span id=\"cb4-259\"><a href=\"#cb4-259\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb4-260\"><a href=\"#cb4-260\" aria-hidden=\"true\"><\/a><span class=\"op\">&lt;<\/span>\/<span class=\"ex\">VirtualHost<\/span><span class=\"op\">&gt;<\/span><\/span><\/code><\/pre><\/div>\n<p>We have embedded the CRS and are now ready for a test operation. The rules inspect requests and responses. They will trigger alarms if they encounter fishy requests, but they will not block any transaction, because the limits have been set very high. Let\u2019s give it a shot.<\/p>\n<h3 id=\"step-4-triggering-alarms-for-testing-purposes\">Step 4: Triggering alarms for testing purposes<\/h3>\n<p>For starters, we will do something easy. It is a request that will trigger exactly one rule by attempting to execute a bash shell. We know that our simple lab server is not vulnerable to such a blatant attack, but ModSecurity does not know this and will still try to protect us:<\/p>\n<div class=\"sourceCode\" id=\"cb5\"><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=\"cb5-1\"><a href=\"#cb5-1\" aria-hidden=\"true\"><\/a>$<span class=\"op\">&gt;<\/span> <span class=\"ex\">curl<\/span> localhost\/index.html?exec=\/bin\/bash<\/span>\n<span id=\"cb5-2\"><a href=\"#cb5-2\" aria-hidden=\"true\"><\/a><span class=\"op\">&lt;<\/span>!<span class=\"ex\">DOCTYPE<\/span> HTML PUBLIC <span class=\"st\">&quot;-\/\/W3C\/\/DTD HTML 4.01\/\/EN&quot;<\/span> <span class=\"st\">&quot;http:\/\/www.w3.org\/TR\/html4\/strict.dtd&quot;<\/span><span class=\"op\">&gt;<\/span><\/span>\n<span id=\"cb5-3\"><a href=\"#cb5-3\" aria-hidden=\"true\"><\/a><span class=\"op\">&lt;<\/span><span class=\"ex\">html<\/span><span class=\"op\">&gt;<\/span><\/span>\n<span id=\"cb5-4\"><a href=\"#cb5-4\" aria-hidden=\"true\"><\/a><span class=\"op\">&lt;<\/span><span class=\"fu\">head<\/span><span class=\"op\">&gt;<\/span><\/span>\n<span id=\"cb5-5\"><a href=\"#cb5-5\" aria-hidden=\"true\"><\/a><span class=\"op\">&lt;<\/span><span class=\"ex\">title<\/span><span class=\"op\">&gt;<\/span>It works! Apache httpd<span class=\"op\">&lt;<\/span>\/title<span class=\"op\">&gt;<\/span><\/span>\n<span id=\"cb5-6\"><a href=\"#cb5-6\" aria-hidden=\"true\"><\/a><span class=\"op\">&lt;<\/span>\/<span class=\"ex\">head<\/span><span class=\"op\">&gt;<\/span><\/span>\n<span id=\"cb5-7\"><a href=\"#cb5-7\" aria-hidden=\"true\"><\/a><span class=\"op\">&lt;<\/span><span class=\"ex\">body<\/span><span class=\"op\">&gt;<\/span><\/span>\n<span id=\"cb5-8\"><a href=\"#cb5-8\" aria-hidden=\"true\"><\/a><span class=\"op\">&lt;<\/span><span class=\"ex\">p<\/span><span class=\"op\">&gt;<\/span>It works!<span class=\"op\">&lt;<\/span>\/p<span class=\"op\">&gt;<\/span><\/span>\n<span id=\"cb5-9\"><a href=\"#cb5-9\" aria-hidden=\"true\"><\/a><span class=\"op\">&lt;<\/span>\/<span class=\"ex\">body<\/span><span class=\"op\">&gt;<\/span><\/span>\n<span id=\"cb5-10\"><a href=\"#cb5-10\" aria-hidden=\"true\"><\/a><span class=\"op\">&lt;<\/span>\/<span class=\"ex\">html<\/span><span class=\"op\">&gt;<\/span><\/span><\/code><\/pre><\/div>\n<p>As predicted, we have not been blocked, but let\u2019s check the logs to see if anything happened:<\/p>\n<div class=\"sourceCode\" id=\"cb6\"><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=\"cb6-1\"><a href=\"#cb6-1\" aria-hidden=\"true\"><\/a>$<span class=\"op\">&gt;<\/span> <span class=\"fu\">tail<\/span> -1 \/apache\/logs\/access.log<\/span>\n<span id=\"cb6-2\"><a href=\"#cb6-2\" aria-hidden=\"true\"><\/a><span class=\"ex\">127.0.0.1<\/span> - - [2026-01-20 12:48:39.414556] <span class=\"st\">&quot;GET \/index.html?exec=\/bin\/bash HTTP\/1.1&quot;<\/span> 200 191 <span class=\"st\">&quot;-&quot;<\/span> \u2026<\/span>\n<span id=\"cb6-3\"><a href=\"#cb6-3\" aria-hidden=\"true\"><\/a><span class=\"st\">&quot;curl\/8.14.1&quot;<\/span> <span class=\"st\">&quot;-&quot;<\/span> <span class=\"ex\">35054<\/span> localhost 127.0.0.1 80 - - + <span class=\"st\">&quot;-&quot;<\/span> aW9rl_uSFsccG5-mOAeHXQAAAAA - - 98 378 \u2026<\/span>\n<span id=\"cb6-4\"><a href=\"#cb6-4\" aria-hidden=\"true\"><\/a><span class=\"ex\">-%<\/span> 5848 3490 88 774 5-0-0-0 0-0-0-0 5 0<\/span><\/code><\/pre><\/div>\n<p>It looks like a standard <code>GET<\/code> request with a status 200. The interesting bit is the second field from the end. In the log file tutorial, we defined a lengthy Apache access log format with two items reserved for the anomaly score. So far, these values have been empty; now they are being filled. The first of the two numbers at the end is the request\u2019s inbound anomaly score. Our submission of <code>\/bin\/bash<\/code> as parameter got us a score of 5. This is considered a critical rule violation by CRS. An error level violation is set at 4, a warning at 3 and a notice at 2. However, if you look over the rules in all the files, most of them score as critical violations with a score of 5.<\/p>\n<p>But now we want to know what rule triggered the alert. This information can be found in the error log. We could simply tail the error log and look at the last entry but in a real world scenario, this entry might be buried somewhere in the middle of the error log. Therefore we find the request ID in the access log entry and then search for all entries in the error log that are related to that request ID.<\/p>\n<div class=\"sourceCode\" id=\"cb7\"><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=\"cb7-1\"><a href=\"#cb7-1\" aria-hidden=\"true\"><\/a>[<span class=\"ex\">2026-01-20<\/span> 12:48:39.416127] [authz_core:debug] 127.0.0.1:35054 aW9rl_uSFsccG5-mOAeHXQAAAAA \u2026<\/span>\n<span id=\"cb7-2\"><a href=\"#cb7-2\" aria-hidden=\"true\"><\/a><span class=\"ex\">AH01626<\/span>: authorization result of Require all granted: granted<\/span>\n<span id=\"cb7-3\"><a href=\"#cb7-3\" aria-hidden=\"true\"><\/a>[<span class=\"ex\">2026-01-20<\/span> 12:48:39.416180] [authz_core:debug] 127.0.0.1:35054 aW9rl_uSFsccG5-mOAeHXQAAAAA \u2026<\/span>\n<span id=\"cb7-4\"><a href=\"#cb7-4\" aria-hidden=\"true\"><\/a><span class=\"ex\">AH01626<\/span>: authorization result of <span class=\"op\">&lt;<\/span>RequireAny<span class=\"op\">&gt;<\/span>: granted<\/span>\n<span id=\"cb7-5\"><a href=\"#cb7-5\" aria-hidden=\"true\"><\/a>[<span class=\"ex\">2026-01-20<\/span> 12:48:39.417069] [security2:error] 127.0.0.1:35054 aW9rl_uSFsccG5-mOAeHXQAAAAA \u2026<\/span>\n<span id=\"cb7-6\"><a href=\"#cb7-6\" aria-hidden=\"true\"><\/a><span class=\"ex\">ModSecurity<\/span>: Warning. Matched phrase <span class=\"st\">&quot;bin\/bash&quot;<\/span> at ARGS:exec. [file <span class=\"st\">&quot;\/apache\/conf\/crs\/rules\/\u2026<\/span><\/span>\n<span id=\"cb7-7\"><a href=\"#cb7-7\" aria-hidden=\"true\"><\/a><span class=\"st\">REQUEST-932-APPLICATION-ATTACK-RCE.conf&quot;<\/span>] [line <span class=\"st\">&quot;650&quot;<\/span>] [id <span class=\"st\">&quot;932160&quot;<\/span>] [msg <span class=\"st\">&quot;Remote Command \u2026<\/span><\/span>\n<span id=\"cb7-8\"><a href=\"#cb7-8\" aria-hidden=\"true\"><\/a><span class=\"st\">Execution: Unix Shell Code Found&quot;<\/span>] [data <span class=\"st\">&quot;Matched Data: bin\/bash found within ARGS:exec: \u2026<\/span><\/span>\n<span id=\"cb7-9\"><a href=\"#cb7-9\" aria-hidden=\"true\"><\/a><span class=\"st\">\/bin\/bash&quot;<\/span>] [severity <span class=\"st\">&quot;CRITICAL&quot;<\/span>] [ver <span class=\"st\">&quot;OWASP_CRS\/4.22.0&quot;<\/span>] [tag <span class=\"st\">&quot;application-multi&quot;<\/span>] [tag \u2026<\/span>\n<span id=\"cb7-10\"><a href=\"#cb7-10\" aria-hidden=\"true\"><\/a><span class=\"st\">&quot;language-shell&quot;<\/span>] [<span class=\"ex\">tag<\/span> <span class=\"st\">&quot;platform-unix&quot;<\/span>] [tag <span class=\"st\">&quot;attack-rce&quot;<\/span>] [tag <span class=\"st\">&quot;paranoia-level\/1&quot;<\/span>] [tag \u2026<\/span>\n<span id=\"cb7-11\"><a href=\"#cb7-11\" aria-hidden=\"true\"><\/a><span class=\"st\">&quot;OWASP_CRS&quot;<\/span>] [<span class=\"ex\">tag<\/span> <span class=\"st\">&quot;OWASP_CRS\/ATTACK-RCE&quot;<\/span>] [tag <span class=\"st\">&quot;capec\/1000\/152\/248\/88&quot;<\/span>] [hostname <span class=\"st\">&quot;localhost&quot;<\/span>] \u2026<\/span>\n<span id=\"cb7-12\"><a href=\"#cb7-12\" aria-hidden=\"true\"><\/a>[<span class=\"ex\">uri<\/span> <span class=\"st\">&quot;\/index.html&quot;<\/span>] [unique_id <span class=\"st\">&quot;aW9rl_uSFsccG5-mOAeHXQAAAAA&quot;<\/span>]<\/span>\n<span id=\"cb7-13\"><a href=\"#cb7-13\" aria-hidden=\"true\"><\/a>[<span class=\"ex\">2026-01-20<\/span> 12:48:39.420014] [security2:error] 127.0.0.1:35054 aW9rl_uSFsccG5-mOAeHXQAAAAA \u2026<\/span>\n<span id=\"cb7-14\"><a href=\"#cb7-14\" aria-hidden=\"true\"><\/a><span class=\"ex\">ModSecurity<\/span>: Warning. Unconditional match in SecAction. [file \u2026<\/span>\n<span id=\"cb7-15\"><a href=\"#cb7-15\" aria-hidden=\"true\"><\/a><span class=\"st\">&quot;\/apache\/conf\/crs\/rules\/RESPONSE-980-CORRELATION.conf&quot;<\/span>] [<span class=\"ex\">line<\/span> <span class=\"st\">&quot;98&quot;<\/span>] [id <span class=\"st\">&quot;980170&quot;<\/span>] [msg \u2026<\/span>\n<span id=\"cb7-16\"><a href=\"#cb7-16\" aria-hidden=\"true\"><\/a><span class=\"st\">&quot;Anomaly Scores: (Inbound Scores: blocking=5, detection=5, per_pl=5-0-0-0, threshold=1000) -\u2026<\/span><\/span>\n<span id=\"cb7-17\"><a href=\"#cb7-17\" aria-hidden=\"true\"><\/a><span class=\"st\">(Outbound Scores: blocking=0, detection=0, per_pl=0-0-0-0, threshold=1000) - (SQLI=0, XSS=0, \u2026<\/span><\/span>\n<span id=\"cb7-18\"><a href=\"#cb7-18\" aria-hidden=\"true\"><\/a><span class=\"st\">RFI=0, LFI=0, RCE=5, PHPI=0, HTTP=0, SESS=0, COMBINED_SCORE=5)&quot;<\/span>] [<span class=\"ex\">ver<\/span> <span class=\"st\">&quot;OWASP_CRS\/4.22.0&quot;<\/span>] [tag \u2026<\/span>\n<span id=\"cb7-19\"><a href=\"#cb7-19\" aria-hidden=\"true\"><\/a><span class=\"st\">&quot;reporting&quot;<\/span>] [<span class=\"ex\">tag<\/span> <span class=\"st\">&quot;OWASP_CRS&quot;<\/span>] [hostname <span class=\"st\">&quot;localhost&quot;<\/span>] [uri <span class=\"st\">&quot;\/index.html&quot;<\/span>] [unique_id \u2026<\/span>\n<span id=\"cb7-20\"><a href=\"#cb7-20\" aria-hidden=\"true\"><\/a><span class=\"st\">&quot;aW9rl_uSFsccG5-mOAeHXQAAAAA&quot;<\/span>]<\/span><\/code><\/pre><\/div>\n<p>The authorization modules report twice in the log file since we are running on level debug. But on the third line, we see the rule alert we are looking for. Let\u2019s look at this in detail. The CRS messages contain much more information than normal Apache messages, making it worthwhile to discuss the log format once more.<\/p>\n<p>The beginning of the line consists of the Apache-specific parts such as the timestamp and the severity of the message as the Apache server sees it. <em>ModSecurity<\/em> messages are always set to <em>error<\/em> level. ModSecurity\u2019s alert format and the Apache error log format we configured lead to some redundancy. The first occurrence client IP address with the source port number and the unique ID of the request are fields written by Apache. The square bracket with the same client IP address again marks the beginning of ModSecurity\u2019s alert message. The characteristic marker of a CRS alert is <code>ModSecurity: Warning<\/code>. It describes a rule being triggered without blocking the request. This is because the alert only raised the anomaly score. It is very easy to distinguish between the issuing of alarms and actual blocking in the Apache error log. Particularly since the individual CRS rules increase the anomaly score, but they do not trigger a blockade. The blockade itself is performed by a separate blocking rule taking the limit into account. But given the insanely high limit, this is not expected to appear anytime soon. ModSecurity logs normal rule violations in the error log as <em>ModSecurity. Warning \u2026<\/em>, and blockades will be logged as <em>ModSecurity. Access denied \u2026<\/em>. A <em>warning<\/em> never has any direct impact on the client: Unless you see the <em>Access denied \u2026<\/em>, the client was unaffected.<\/p>\n<p>What comes next? A reference to the pattern found in the request. The specific phrase <code>\/bin\/bash<\/code> was found in the argument <code>exec<\/code>. Then comes a series of information chunks that always have the same pattern: They are within square brackets and have their own identifier. First you\u2019ll see the <em>file<\/em> identifier. It shows us the file in which the rule that triggered the alarm is defined. This is followed by <em>line<\/em> for the line number within the file. The <em>id<\/em> parameter is an important one. The rule in question, <code>932160<\/code>, can be found in the set of rules that defend against remote command execution in the 932,000 &#8211; 932,999 rule block. Then comes <em>rev<\/em> as a reference to the revision number of the rule. In CRS, this parameter expresses how often the rule has been revised. If a modification is made to a rule, the developer that makes the change increases the rule\u2019s <em>rev<\/em> by one. However, this is not always done in practice and should not be relied upon. <em>msg<\/em>, short for <em>message<\/em>, describes the type of attack detected. The relevant part of the request, the <em>exec<\/em> parameter appears in <em>data<\/em>. In my example, this is obviously a case of <em>Remote Code Execution<\/em> (RCE).<\/p>\n<p>Then we have the <em>severity<\/em> level of the rule that set off the alarm and corresponds with the anomaly score of the rule. We have already established the fact that our rule is considered critical, that\u2019s why it is being reported here at this severity. At <em>ver<\/em>, we come to the release of the CRS, followed by <em>maturity<\/em> and then <em>accuracy<\/em>. Both values are meant to be references to the quality of the rule. But the support is in fact inconsistent and you should not trust these values very much.<\/p>\n<p>What follows is a series of <em>tags<\/em> assigned to the rule. They are included along with every alert message. These tags often classify the type of attack. These references can, for example, be used for analysis and statistics. Towards the end of the alarm comes three additional values, <em>hostname<\/em>, <em>uri<\/em> and <em>unique_id<\/em>, that more clearly specify the request (the <em>unique_id<\/em>, already listed by Apache, is somewhat redundant).<\/p>\n<p>With this, we have covered the full alert message that led to the inbound anomaly score of 5.<\/p>\n<p>But there is another rule in the dump above, <code>980170<\/code>, that has been mentioned above. This is said reporting rule. It brings a summary of the anomaly score per paranoia level and also per attack category, very much like the access log and the alert message. So the information here is mostly redundant. That\u2019s why I personally do not rely on it in production. Yet there are platforms, where you can not show the anomaly score of a request in the access log. In such a situation, this reporting rule is very useful.<\/p>\n<p>But as far as we are concerned here, let\u2019s disable this rule as follows (and don\u2019t forget to restart the server):<\/p>\n<div class=\"sourceCode\" id=\"cb8\"><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=\"cb8-1\"><a href=\"#cb8-1\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecAction<\/span> <span class=\"st\">&quot;id:900110,phase:1,pass,nolog,\\<\/span><\/span>\n<span id=\"cb8-2\"><a href=\"#cb8-2\" aria-hidden=\"true\"><\/a><span class=\"st\">  setvar:tx.inbound_anomaly_score_threshold=10000,\\<\/span><\/span>\n<span id=\"cb8-3\"><a href=\"#cb8-3\" aria-hidden=\"true\"><\/a><span class=\"st\">  setvar:tx.outbound_anomaly_score_threshold=10000,\\<\/span><\/span>\n<span id=\"cb8-4\"><a href=\"#cb8-4\" aria-hidden=\"true\"><\/a><span class=\"st\">  setvar:tx.blocking_paranoia_level=1,\\<\/span><\/span>\n<span id=\"cb8-5\"><a href=\"#cb8-5\" aria-hidden=\"true\"><\/a><span class=\"st\">  setvar:tx.reporting_level=0&quot;<\/span><\/span><\/code><\/pre><\/div>\n<p>Now the alerts above were only triggered by a single request. Let\u2019s generate more alerts. <em>Nikto<\/em> is a simple tool that can help us in this situation. It\u2019s a security scanner that has been around for ages. It\u2019s not very proficient, but it is fast and easy to use. Just the right tool to generate alerts for us. <em>Nikto<\/em> may still have to be installed. The scanner is, however, included in most distributions.<\/p>\n<div class=\"sourceCode\" id=\"cb9\"><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=\"cb9-1\"><a href=\"#cb9-1\" aria-hidden=\"true\"><\/a>$<span class=\"op\">&gt;<\/span> <span class=\"ex\">nikto<\/span> -h localhost<\/span>\n<span id=\"cb9-2\"><a href=\"#cb9-2\" aria-hidden=\"true\"><\/a><span class=\"ex\">-<\/span> Nikto v2.1.5<\/span>\n<span id=\"cb9-3\"><a href=\"#cb9-3\" aria-hidden=\"true\"><\/a><span class=\"ex\">---------------------------------------------------------------------------<\/span><\/span>\n<span id=\"cb9-4\"><a href=\"#cb9-4\" aria-hidden=\"true\"><\/a><span class=\"ex\">+<\/span> Target IP:          127.0.0.1<\/span>\n<span id=\"cb9-5\"><a href=\"#cb9-5\" aria-hidden=\"true\"><\/a><span class=\"ex\">+<\/span> Target Hostname:    localhost<\/span>\n<span id=\"cb9-6\"><a href=\"#cb9-6\" aria-hidden=\"true\"><\/a><span class=\"ex\">+<\/span> Target Port:        80<\/span>\n<span id=\"cb9-7\"><a href=\"#cb9-7\" aria-hidden=\"true\"><\/a><span class=\"ex\">+<\/span> Start Time:         2026-01-20 13:28:49 (GMT1)<\/span>\n<span id=\"cb9-8\"><a href=\"#cb9-8\" aria-hidden=\"true\"><\/a><span class=\"ex\">---------------------------------------------------------------------------<\/span><\/span>\n<span id=\"cb9-9\"><a href=\"#cb9-9\" aria-hidden=\"true\"><\/a><span class=\"ex\">+<\/span> Server: Apache<\/span>\n<span id=\"cb9-10\"><a href=\"#cb9-10\" aria-hidden=\"true\"><\/a><span class=\"ex\">+<\/span> The anti-clickjacking X-Frame-Options header is not present.<\/span>\n<span id=\"cb9-11\"><a href=\"#cb9-11\" aria-hidden=\"true\"><\/a><span class=\"ex\">+<\/span> No CGI Directories found (use <span class=\"st\">&#39;-C all&#39;<\/span> to force check all possible dirs)<\/span>\n<span id=\"cb9-12\"><a href=\"#cb9-12\" aria-hidden=\"true\"><\/a><span class=\"ex\">+<\/span> Server leaks inodes via ETags, header found with file \/index.html, fields: 0xbf 0x642fce432f300<\/span>\n<span id=\"cb9-13\"><a href=\"#cb9-13\" aria-hidden=\"true\"><\/a><span class=\"ex\">+<\/span> Allowed HTTP Methods: GET, POST, OPTIONS, HEAD<\/span>\n<span id=\"cb9-14\"><a href=\"#cb9-14\" aria-hidden=\"true\"><\/a><span class=\"ex\">+<\/span> 6544 items checked: 0 error(s) <span class=\"ex\">and<\/span> 3 item(s) <span class=\"ex\">reported<\/span> on remote host<\/span>\n<span id=\"cb9-15\"><a href=\"#cb9-15\" aria-hidden=\"true\"><\/a><span class=\"ex\">+<\/span> End Time:           2026-01-20 13:29:05 (GMT1) <span class=\"kw\">(<\/span><span class=\"ex\">16<\/span> seconds<span class=\"kw\">)<\/span><\/span>\n<span id=\"cb9-16\"><a href=\"#cb9-16\" aria-hidden=\"true\"><\/a><span class=\"ex\">---------------------------------------------------------------------------<\/span><\/span>\n<span id=\"cb9-17\"><a href=\"#cb9-17\" aria-hidden=\"true\"><\/a><span class=\"ex\">+<\/span> 1 host(s) <span class=\"ex\">tested<\/span><\/span><\/code><\/pre><\/div>\n<p>This scan should have triggered numerous <em>ModSecurity alarms<\/em> on the server. Let\u2019s take a close look at the <em>Apache error log<\/em>. In my case, there were over 13,000 entries in the error log. Combine this with the authorization messages and infos on many 404s (Nikto probes for files that do not exist on the server) and you end up with a fast-growing error log. The single Nikto run resulted in an 11 MB logfile. Looking over the audit log tree reveals 92 MB of logs. It\u2019s obvious: you need to keep a close eye on these log files or your server will collapse due to denial of service via log file exhaustion.<\/p>\n<h3 id=\"step-5-analyzing-the-alert-messages\">Step 5: Analyzing the alert messages<\/h3>\n<p>So we are looking at 13,000 alerts. And even if the format of the entries in the error log may be clear, without a tool they are very hard to read, let alone analyze. A simple remedy is to use a few <em>shell aliases<\/em>, which extract individual pieces of information from the entries. They are stored in the alias file we discussed in the log format in Tutorial 5.<\/p>\n<pre><code>$&gt; cat ~\/.apache-modsec.alias\n...\nalias meldata=&#39;grep -o &quot;\\[data [^]]*&quot; | cut -d\\&quot; -f2&#39;\nalias melfile=&#39;grep -o &quot;\\[file [^]]*&quot; | cut -d\\&quot; -f2&#39;\nalias melhostname=&#39;grep -o &quot;\\[hostname [^]]*&quot; | cut -d\\&quot; -f2&#39;\nalias melid=&#39;grep -o &quot;\\[id [^]]*&quot; | cut -d\\&quot; -f2&#39;\nalias melip=&#39;grep -E -o &quot;error\\] [^ ]*&quot; | cut -d\\  -f2 | sed -e &quot;s\/:[0-9]\\{4,\\}\/\/&quot;&#39;\nalias melidmsg=&#39;sed -e &quot;\/\\(compiled version\\|Status engine is currently\\)\/d&quot; -e &quot;s\/.*\\[id \\&quot;\/\/&quot; -e &quot;s\/PCRE limits exceeded\/[msg \\&quot;ERROR while processing rule: PCRE limits exceeded\\&quot;]\/&quot; -e &quot;s\/\\([0-9]*\\).*\\[msg \\&quot;\/\\1 \/&quot; -e &quot;s\/\\&quot;\\].*\/\/&quot; -e &quot;s\/(Total .*\/(Total ...) ...\/&quot; -e &quot;s\/Incoming and Outgoing Score: [0-9]* [0-9]*\/Incoming and Outgoing Score: ...\/&quot; -e &quot;s\/Anomaly Scores: .*\/Anomaly Scores: (Inbound Scores: ...) - (Outbound Scores: ...) - ...\/&quot;&#39;\nalias melline=&#39;grep -o &quot;\\[line [^]]*&quot; | cut -d\\&quot; -f2&#39;\nalias melmatch=&#39;grep -o &quot; at [^\\ ]*\\. \\[file&quot; | sed -e &quot;s\/\\. \\[file\/\/&quot; | cut -b5-&#39;\nalias melmsg=&#39;grep -o &quot;\\[msg [^]]*&quot; | cut -d\\&quot; -f2 | sed -e &quot;s\/(Total .*\/(Total ...) ...\/&quot; -e &quot;s\/Anomaly Scores: .*\/Anomaly Scores: (Inbound Scores: ...) - (Outbound Scores: ...) - ...\/&quot;&#39;\nalias meltimestamp=&#39;cut -b2-25&#39;\nalias melunique_id=&#39;grep -o &quot;\\[unique_id [^]]*&quot; | cut -d\\&quot; -f2&#39;\nalias meluri=&#39;grep -o &quot;\\[uri [^]]*&quot; | cut -d\\&quot; -f2&#39;\n...<\/code><\/pre>\n<p>These abbreviations all start with the prefix <em>mel<\/em>, short for <em>ModSecurity error log<\/em>, followed by the field name. Let\u2019s try it out to output the rule IDs from the alerts:<\/p>\n<pre><code>$&gt; cat logs\/error.log | melid\n...\n913100\n920440\n913100\n913100\n913100\n913100\n913100\n913100\n913100\n920440<\/code><\/pre>\n<p>This seems to do the job. So let\u2019s extend the example with a few steps:<\/p>\n<pre><code>$&gt; cat logs\/error.log | melid | sort | uniq -c | sort -n\n...\n    171 930120\n    244 941100\n    254 920440\n    273 941110\n    277 941160\n    282 930100\n    314 941390\n    539 930110\n   2262 931120\n   6207 913100\n$&gt; cat logs\/error.log | melidmsg | sucs\n...\n    171 930120 OS File Access Attempt\n    244 941100 XSS Attack Detected via libinjection\n    254 920440 URL file extension is restricted by policy\n    273 941110 XSS Filter - Category 1: Script Tag Vector\n    277 941160 NoScript XSS InjectionChecker: HTML Injection\n    282 930100 Path Traversal Attack (\/..\/) or (\/...\/)\n    314 941390 Javascript method detected\n    539 930110 Path Traversal Attack (\/..\/) or (\/...\/)\n   2262 931120 Possible Remote File Inclusion (RFI) Attack: URL Payload Used w\/Trailing ...\n   6207 913100 Found User-Agent associated with security scanner<\/code><\/pre>\n<p>This is something we can work with. But it\u2019s perhaps necessary to explain the <em>one-liners<\/em> used if you did not read through all the previous tutorials. We extract the rule IDs from the <em>error log<\/em>, then <em>sort<\/em> them, group them together in a list of found IDs (<em>uniq -c<\/em>) and sort again by the numbers found. That\u2019s the first <em>one-liner<\/em>. A relationship between the individual rules is still lacking, this is where <code>melidmsg<\/code> comes in. This alias apparently extracts the rule id as well as the alert message. The problem is that there can be dynamic parts in the message. If you unique those, you end up with multiple entries, one for each number combination. So the <code>melidmsg<\/code> alias takes that into account and covers various special cases on top.<\/p>\n<p>Coming back to the output above, we can see that CRS detected a lot of malicious requests and we now have an idea which rules played a role in this. The rule triggered most frequently, 913100, is no surprise, and when you look upwards in the output, this all makes a lot of sense.<\/p>\n<h3 id=\"step-6-evaluating-false-alarms\">Step 6: Evaluating false alarms<\/h3>\n<p>So the <em>Nikto<\/em> scan set off thousands of alarms. They were likely justified. In the normal use of <em>ModSecurity<\/em>, things are a bit different. The CRS is designed and optimized to have as few false alarms as possible in paranoia level 1. But in production use, there are going to be false positives sooner or later. Depending on the application, a normal installation will also see alarms and a lot of them will be false. And when you raise the paranoia level to become more vigilant towards attacks, the number of false positives will also rise. Actually, it will rise steeply when you move to PL 3 or 4; so steeply, some would call it exploding.<\/p>\n<p>In order to run smoothly, the configuration has to be fine tuned first: Legitimate requests and malicious exploitation attempts need to be distinct. We want to achieve a high degree of separation between the two. We wish to configure <em>ModSecurity<\/em> and the CRS so the engine knows exactly how to distinguish between legitimate requests and attacks.<\/p>\n<p>We differentiate between two categories of errors when examining requests. We already discussed false positives (or false alarms) above. The other category of errors is called <em>false negatives<\/em> and they consist of attacks that are not detected. CRS is strict and careful to keep the number of <em>false negatives<\/em> low. An attacker needs to possess a great deal of savvy to circumvent the system of rules, especially at higher paranoia levels. Unfortunately, this strictness also results in alarms being triggered for normal requests. It is commonly the case that at a low degree of separation, you either get a lot of <em>false negatives<\/em> or a lot of <em>false positives<\/em>. Reducing the number of <em>false negatives<\/em> leads to an increase in <em>false positives<\/em> and vice versa. Both correlate highly with one another.<\/p>\n<p>We have to overcome this link: We want to increase the degree of separation in order to reduce the number of <em>false positives<\/em> without increasing the number of <em>false negatives<\/em>. We can do this by fine tuning the system of rules in a few places. We have to exclude certain rules from being executed for certain requests or parameters. But first we need to have a clear picture of the current situation: How many <em>false positives<\/em> are there and which of the rules are being violated in a particular context? How many <em>false positives<\/em> are we willing to allow on the system? Reducing them to zero will be extremely difficult to do, but percentages are something we can work with. A possible target would be: 99.999% of legitimate requests should pass without being blocked by the web application firewall. This is realistic, but involves a bit of work depending on the application. 99.999% of requests without a false alarm is also a number where professional use starts in my experience. But I have setups where we are not willing to accept more than 1 false alarm in 1 million of requests. That\u2019s 99.9999%.<\/p>\n<p>To reach such a goal, we will need one or two tools to help us get a good footing. Specifically, we need to find out about these numbers. Then, in a second step, we look at the error log to understand the rules that led to these alerts. We have seen that the access log reports the anomaly scores of the requests. Let\u2019s try to extract these scores and to present them in a suitable form.<\/p>\n<p>In Tutorial 5 we worked with a sample log file containing 10,000 entries. We\u2019ll be using this log file again here: <a href=\"https:\/\/www.netnea.com\/apache-tutorials\/git\/laboratory\/tutorial-5\/tutorial-5-example-access.log\">tutorial-5-example-access.log<\/a>. The file comes from a real server, but the IP addresses, server names and paths have been simplified or rewritten. However, the information we need for our analysis is still there. Let\u2019s have a look at the distribution of <em>anomaly scores<\/em>:<\/p>\n<pre><code>$&gt; grep -E -o &quot;[0-9-]+ [0-9-]+$&quot; tutorial-5-example-access.log | cut -d\\  -f1 | sucs\n      3 10\n      5 3\n      6 2\n     55 5\n   9931 0\n$&gt; grep -E -o &quot;[0-9-]+$&quot; tutorial-5-example-access.log | sucs\n  10000 0<\/code><\/pre>\n<p>The first command line reads the inbound <em>anomaly score<\/em>. It\u2019s the second-to-last value in the <em>access log line<\/em>. We take the two last values (<em>grep -E<\/em>) and then <em>cut<\/em> the first one out. We then sort the results using the familiar <em>sucs<\/em> alias. The outbound <em>anomaly score<\/em> is the last value in the <em>log line<\/em>. This is why there is no <em>cut<\/em> command on the second command line.<\/p>\n<p>The results give us an idea of the situation: The vast majority of requests pass the inspection by CRS with no rule violation: 9931 requests with score 0. 69 requests violated one or more rules. This is not a standard situation for CRS. In fact, I provoked additional false alarms to give us something to look at. The CRS is so optimized these days that you need a lot of traffic to get a reasonable amount of alerts &#8211; or you need to raise the paranoia level very high on a non-tuned system.<\/p>\n<p>A score of 10 appears three times, corresponding to two violations in the same request (most rules score 5 points when violated), which is fairly standard in practice. In all likelihood, we will be seeing a fair number of violations from the requests and very few alarms from the responses; 0 in our example above.<\/p>\n<p>But this still doesn\u2019t give us the right idea about the <em>tuning steps<\/em> that would be needed to run this install smoothly. To present this information in a suitable form, I have prepared a ruby script that analyzes <em>anomaly scores<\/em>. You can download the script here: <a href=\"https:\/\/www.netnea.com\/files\/modsec-positive-stats.rb\">modsec-positive-stats.rb<\/a> and place it in your private <em>bin<\/em> directory (You might have to install the <em>ruby<\/em> package to get it working). It takes the two anomaly scores as input and we need to separate them with a semicolon in order to pipe them into the script. We can do this like this:<\/p>\n<pre><code>$&gt; cat tutorial-5-example-access.log  | grep -E -o &quot;[0-9-]+ [0-9-]+$&quot; | tr &quot; &quot; &quot;;&quot; | modsec-positive-stats.rb\nINCOMING                     Num of req. | % of req. |  Sum of % | Missing %\nNumber of incoming req. (total) |  10000 | 100.0000% | 100.0000% |   0.0000%\n\nEmpty or miss. incoming score   |      0 |   0.0000% |   0.0000% | 100.0000%\nReqs with incoming score of   0 |   9931 |  99.3100% |  99.3100% |   0.6900%\nReqs with incoming score of   1 |      0 |   0.0000% |  99.3100% |   0.6900%\nReqs with incoming score of   2 |      6 |   0.0600% |  99.3700% |   0.6300%\nReqs with incoming score of   3 |      5 |   0.0500% |  99.4200% |   0.5800%\nReqs with incoming score of   4 |      0 |   0.0000% |  99.4200% |   0.5800%\nReqs with incoming score of   5 |     55 |   0.5499% |  99.9700% |   0.0300%\nReqs with incoming score of   6 |      0 |   0.0000% |  99.9700% |   0.0300%\nReqs with incoming score of   7 |      0 |   0.0000% |  99.9700% |   0.0300%\nReqs with incoming score of   8 |      0 |   0.0000% |  99.9700% |   0.0300%\nReqs with incoming score of   9 |      0 |   0.0000% |  99.9700% |   0.0300%\nReqs with incoming score of  10 |      3 |   0.0300% | 100.0000% |   0.0000%\n\nIncoming average:   0.0332    Median   0.0000    Standard deviation   0.4163\n\n\nOUTGOING                     Num of req. | % of req. |  Sum of % | Missing %\nNumber of outgoing req. (total) |  10000 | 100.0000% | 100.0000% |   0.0000%\n\nEmpty or miss. outgoing score   |      0 |   0.0000% |   0.0000% | 100.0000%\nReqs with outgoing score of   0 |  10000 | 100.0000% | 100.0000% |   0.0000%\n\nOutgoing average:   0.0000    Median   0.0000    Standard deviation   0.0000<\/code><\/pre>\n<p>Please notice how there is an alias <code>alscores<\/code> that delivers exactly the format prepared by the <code>grep<\/code> and <code>tr<\/code> above.<\/p>\n<p>The script divides the inbound from the outbound <em>anomaly scores<\/em>. The incoming ones are handled first. Before the script can handle the scores, it describes how often an empty <em>anomaly score<\/em> has been found (<em>empty incoming score<\/em>). In our case, this did not happen at all. Then comes the statement about <em>score 0<\/em>: 9931 requests. This is covering 99.31% of the requests. 0.69% had a higher <em>anomaly score<\/em> (<em>Missing %<\/em>). Above, we set out to have 99.999% of requests able to pass the server. We are about 0.69% or 69 requests away from this target. The next <em>anomaly score<\/em> is 2. It appears 6 times or 0.06%. The <em>anomaly score<\/em> 3 appears 5 times and a score of 5 can be seen 55 times, a small cluster in the results. All in all, we are at 99.97%. Then there are 3 requests with a score of 10. To achieve 99.999% coverage we have get to this limit (and, based on the example log file, this would achieve 100% coverage).<\/p>\n<p>There are probably some <em>false positives<\/em>. In practice, we have to make certain of this before we start fine tuning the rules. It would be totally wrong to assume a false positive based on a justified alarm and suppress the alarm in the future. Before tuning, we must ensure that no attacks are present in the log file. This is not always easy. Manual review helps, restricting to known IP addresses, pre-authentication, testing\/tuning on a test system separated from the internet, filtering the access log by country of origin for the IP address, etc\u2026 It\u2019s a big topic and making general recommendations is difficult. But please do take this seriously. As a side-note, netnea offers a suite of tools calls C-Rex that performs the triage for you. See <a href=\"https:\/\/c-rex.netnea.com\">c-rex.netnea.com<\/a> for more information.<\/p>\n<h3 id=\"step-7-handling-false-positives-disabling-individual-rules\">Step 7: Handling false positives: Disabling individual rules<\/h3>\n<p>The simple way of dealing with a <em>false positive<\/em> is to simply disable the rule. We are thus making the alarm disappear by excluding a certain rule from the rule set. The CRS term for this technique is called <em>Rules Exclusion<\/em> or <em>Exclusion Rules<\/em>. It is called <em>Rule<\/em> because this exclusion involved writing rules or directives resembling rules themselves.<\/p>\n<p>Excluding a rule completely takes very little effort, but it is, of course, potentially risky because the rule is not being disabled for just legitimate users, but for attackers as well. By completely disabling a rule, we are restricting the capability of <em>ModSecurity<\/em>. Or, expressed more drastically, we\u2019re pulling the teeth out of the <em>WAF<\/em>.<\/p>\n<p>Especially at higher paranoia levels, there are rules that just fail to work with some applications and trigger false alarms in all sorts of situations. So there is a use for disabling a rule completely. One notable example is rule ID <code>920300<\/code>: <em>Request Missing an Accept Header<\/em>. There are just so many user agents that submit requests without an accept header, there is a rule dedicated to the problem. Let\u2019s raise the paranoia level to 2 by setting the <code>tx.blocking_paranoia_level<\/code> variable to 2 in our config. Then we will send a request without an <code>Accept<\/code> header to trigger an alert as follows (I recommend returning the paranoia level to 1 again afterwards):<\/p>\n<div class=\"sourceCode\" id=\"cb15\"><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=\"cb15-1\"><a href=\"#cb15-1\" aria-hidden=\"true\"><\/a>$<span class=\"op\">&gt;<\/span> <span class=\"ex\">curl<\/span> -v -H <span class=\"st\">&quot;Accept:&quot;<\/span> http:\/\/localhost\/index.html<\/span>\n<span id=\"cb15-2\"><a href=\"#cb15-2\" aria-hidden=\"true\"><\/a><span class=\"ex\">...<\/span><\/span>\n<span id=\"cb15-3\"><a href=\"#cb15-3\" aria-hidden=\"true\"><\/a><span class=\"op\">&gt;<\/span> <span class=\"ex\">GET<\/span> \/index.html HTTP\/1.1<\/span>\n<span id=\"cb15-4\"><a href=\"#cb15-4\" aria-hidden=\"true\"><\/a><span class=\"op\">&gt;<\/span> <span class=\"ex\">User-Agent<\/span>: curl\/7.47.0<\/span>\n<span id=\"cb15-5\"><a href=\"#cb15-5\" aria-hidden=\"true\"><\/a><span class=\"op\">&gt;<\/span> <span class=\"ex\">Host<\/span>: localhost<\/span>\n<span id=\"cb15-6\"><a href=\"#cb15-6\" aria-hidden=\"true\"><\/a><span class=\"ex\">...<\/span><\/span>\n<span id=\"cb15-7\"><a href=\"#cb15-7\" aria-hidden=\"true\"><\/a>$<span class=\"op\">&gt;<\/span> <span class=\"fu\">tail<\/span> \/apache\/logs\/error.log <span class=\"kw\">|<\/span> <span class=\"ex\">melidmsg<\/span> <span class=\"kw\">|<\/span> <span class=\"ex\">mappl<\/span><\/span>\n<span id=\"cb15-8\"><a href=\"#cb15-8\" aria-hidden=\"true\"><\/a><span class=\"ex\">920300<\/span> PL3 Request Missing an Accept Header<\/span><\/code><\/pre><\/div>\n<p>Notice the use of the <code>mappl<\/code> alias. It takes a rule id and appends the paranoia level of the rule.<\/p>\n<p>So the rule has been triggered as desired. Let us now exclude the rule. We have multiple options and we start with the simplest one: We exclude the rule at startup time for Apache. This means it removes the rule from the set of loaded rules and no processor cycles will be spent on the rule once the server has started. Of course, we can only remove things which have been loaded before. So this directive has to be placed after the CRS include statement. In the config recipe earlier in this tutorial, we reserved some space for these sorts of exclusion rules. We fill in our exclusion directive in this location:<\/p>\n<div class=\"sourceCode\" id=\"cb16\"><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=\"cb16-1\"><a href=\"#cb16-1\" aria-hidden=\"true\"><\/a><span class=\"co\"># === ModSec CRS: Startup Time Rules Exclusions<\/span><\/span>\n<span id=\"cb16-2\"><a href=\"#cb16-2\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb16-3\"><a href=\"#cb16-3\" aria-hidden=\"true\"><\/a><span class=\"co\"># ModSec Exclusion Rule: 920300 Request Missing an Accept Header<\/span><\/span>\n<span id=\"cb16-4\"><a href=\"#cb16-4\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecRuleRemoveById<\/span> 920300<\/span><\/code><\/pre><\/div>\n<p>The example comes with a comment, which describes the rule being excluded. This is a good practice, which you should adopt as well. We have the option to exclude by ID (as we just did), to add several comma separated rule IDs, to configure a rule range or we can select the rule by one of its tags. Here is an example using one of the tags of the rule <code>920300<\/code>:<\/p>\n<div class=\"sourceCode\" id=\"cb17\"><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=\"cb17-1\"><a href=\"#cb17-1\" aria-hidden=\"true\"><\/a><span class=\"co\"># ModSec Exclusion Rule: 920300 Request Missing an Accept Header<\/span><\/span>\n<span id=\"cb17-2\"><a href=\"#cb17-2\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecRuleRemoveByTag<\/span> <span class=\"st\">&quot;^OWASP_CRS\/PROTOCOL-ENFORCEMENT$&quot;<\/span><\/span><\/code><\/pre><\/div>\n<p>As you can see, this directive accepts regular expressions as parameters and will disable all the rules arrying this tag &#8211; that\u2019s a lot of rules in this example, so be careful.<\/p>\n<p>Unfortunately, the support is not universal: For example, the <em>OR<\/em> functionality, expressed with a pipe character, is not implemented. In practice, you will have to try it out and see for yourself what works and what does not.<\/p>\n<p>Technically, there is an additional directive, <code>SecRuleRemoveByMsg<\/code>. However, the messages are not guaranteed to be stable between releases and they are not very consistent anyways. So you should not try to build exlcusion rules for the CRS via this directive.<\/p>\n<p>So these are ways to disable an entire rule at startup time. Excluding a rule in this manner is simple and readable, but it is also a drastic step which we will not use in a production setup very often. Because, if our issues with the rule <code>920300<\/code> are limited to a single legitimate agent checking the availability of our service by requesting the index page, we can limit the exclusion to this individual request. This is no longer a startup time rule exclusion, but a runtime exclusion which is being applied on certain conditions. Runtime exclusions leverage the <em>SecRule<\/em> directive combined with a special action executing the rule exclusion. This depends on the SecRule statement running before the rule in question is applied. That\u2019s why runtime rule exclusions have to be placed before the CRS include statement, where we also reserved a space for this type of exclusion rule:<\/p>\n<div class=\"sourceCode\" id=\"cb18\"><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=\"cb18-1\"><a href=\"#cb18-1\" aria-hidden=\"true\"><\/a><span class=\"co\"># === ModSec CRS: Runtime Exclusion Rules (ids: 10000-49999)<\/span><\/span>\n<span id=\"cb18-2\"><a href=\"#cb18-2\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb18-3\"><a href=\"#cb18-3\" aria-hidden=\"true\"><\/a><span class=\"co\"># ModSec Exclusion Rule: 920300 Request Missing an Accept Header<\/span><\/span>\n<span id=\"cb18-4\"><a href=\"#cb18-4\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecRule<\/span> REQUEST_FILENAME <span class=\"st\">&quot;@streq \/index.html&quot;<\/span> <span class=\"kw\">\\<\/span><\/span>\n<span id=\"cb18-5\"><a href=\"#cb18-5\" aria-hidden=\"true\"><\/a>    <span class=\"st\">&quot;phase:1,nolog,pass,id:10000,ctl:ruleRemoveById=920300&quot;<\/span><\/span><\/code><\/pre><\/div>\n<p>Now this is harder to read. Watch out for the <em>ctl<\/em> statement: <code>ctl:ruleRemoveById=920300<\/code>. This is the control action, which is used for runtime changes of the configuration of the ModSecurity rule engine. We use <em>ruleRemoveById<\/em> as the control statement and apply it to rule ID <code>920300<\/code>. This block is placed within a standard <em>SecRule<\/em> directive. This allows us to use the complete power of <em>SecRule<\/em> to exclude rule <code>920300<\/code> in very specific situations. Here we exclude it based on the path of the request, but we could apply it depending on the agent\u2019s IP address &#8211; or a combination of the two in a chained rule statement.<\/p>\n<p>As with the startup rule exclusions, we are not limited to an exclusion by rule ID. Exclusions by tag will work just as well (<code>ctl:ruleRemoveByTag<\/code>). Again, regular expressions are supported, but only to a certain extent.<\/p>\n<p>Startup time rule exclusions and runtime rule exclusions have the same effect, but internally, they are really different. With the runtime exclusions, you gain granular control at the cost of performance, as the exclusion is being evaluated for every single request. Startup time exclusions are performing faster and they are easier to read and write.<\/p>\n<h3 id=\"step-8-handling-false-positives-disabling-individual-rules-for-specific-parameters\">Step 8: Handling false positives: Disabling individual rules for specific parameters<\/h3>\n<p>Next we look at excluding an individual parameter from being evaluated by a specific rule. So unlike our example <code>920300<\/code>, which looked at the specific <code>Accept<\/code>-header, we are now targeting rules examining the <code>ARGS<\/code> group of variables.<\/p>\n<p>Let\u2019s assume we have a password field in an authentication scheme like we used in the previous tutorial. Users are advised to use hard to guess passwords with lots of special characters which leads to the CRS sending a steady stream of alerts because of the strange passwords in this parameter field.<\/p>\n<p>Here is an artificial example triggering the rule <code>942100<\/code>, which leverages the libinjection library to detect SQL injections. Execute this command and you get an alert:<\/p>\n<div class=\"sourceCode\" id=\"cb19\"><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=\"cb19-1\"><a href=\"#cb19-1\" aria-hidden=\"true\"><\/a>$<span class=\"op\">&gt;<\/span> <span class=\"ex\">curl<\/span> --data <span class=\"st\">&quot;password=&#39; or f7x=gZs&quot;<\/span> localhost\/login\/login.do<\/span><\/code><\/pre><\/div>\n<p>There is nothing wrong with this password from a security perspective other than being a bit shot. In fact, we could just disable this rule. But it would be wrong to disable this rule completely. It serves a very important purpose with many other parameters, just not with the password. Ideally, we want to exclude the parameter password from being examined by this rule. Here is the startup time rule exclusion performing this task:<\/p>\n<div class=\"sourceCode\" id=\"cb20\"><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=\"cb20-1\"><a href=\"#cb20-1\" aria-hidden=\"true\"><\/a><span class=\"co\"># ModSec Exclusion Rule: 942100 SQL Injection Attack Detected via libinjection<\/span><\/span>\n<span id=\"cb20-2\"><a href=\"#cb20-2\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecRuleUpdateTargetById<\/span> 942100 !ARGS:password<\/span><\/code><\/pre><\/div>\n<p>This directive adds \u201cnot ARGS:password\u201d to the list of parameters to be examined by rule <code>942100<\/code>. This effectively excludes the parameter from the evaluation. This directive also accepts rule ranges as parameters. Of course, this directive also exists in a variant where we select the rule via its tag:<\/p>\n<div class=\"sourceCode\" id=\"cb21\"><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=\"cb21-1\"><a href=\"#cb21-1\" aria-hidden=\"true\"><\/a><span class=\"co\"># ModSec Exclusion Rule: 942100 SQL Injection Attack Detected via libinjection<\/span><\/span>\n<span id=\"cb21-2\"><a href=\"#cb21-2\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecRuleUpdateTargetByTag<\/span> <span class=\"st\">&quot;attack-sqli&quot;<\/span> !ARGS:password<\/span><\/code><\/pre><\/div>\n<p>The tag we are using in this example, <em>attack-sqli<\/em>, points to a wide range of SQL injection rules. So it will prevent a whole class of rules from looking at the password parameter. This makes sense for this password parameter, but it might go too far for other parameters. So it really depends on the application and the parameter in question.<\/p>\n<p>A password parameter is generally only used on the login request, so we can work with the <code>SecRuleUpdateTargetById<\/code> directive in practice, so that all occurrences of said parameter are exempt from examination by rule 942100. But let me stress, that this directive is server-wide. If you have multiple services with multiple Apache virtual hosts each running a different application, then <code>SecRuleUpdateTargetById<\/code> and <code>SecRuleUpdateTargetByTag<\/code> will disable the said rule or rules respectively for all occurrences of the password parameter on the whole server.<\/p>\n<p>So let\u2019s assume you want to exclude <em>password<\/em> only under certain conditions. For example the rule should still be active when a security scanner is submitting the request. One fairly good way to detect scanners is by looking at the <em>Referer<\/em> request header. So the idea is to check for the correct header and then exclude the parameter from examination by <code>942100<\/code>. This runtime rule exclusion works with a control action, similar to the ones we have seen before:<\/p>\n<div class=\"sourceCode\" id=\"cb22\"><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=\"cb22-1\"><a href=\"#cb22-1\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecRule<\/span> REQUEST_HEADERS:Referer <span class=\"st\">&quot;@streq https:\/\/localhost\/login\/displayLogin.do&quot;<\/span> <span class=\"kw\">\\<\/span><\/span>\n<span id=\"cb22-2\"><a href=\"#cb22-2\" aria-hidden=\"true\"><\/a>    <span class=\"st\">&quot;phase:1,nolog,pass,id:10000,ctl:ruleRemoveTargetById=942100;ARGS:password&quot;<\/span><\/span><\/code><\/pre><\/div>\n<p>The format of the control action is really difficult to grasp now: In addition to the rule ID, we add a semicolon and then the password parameter as part of the ARGS group of variables. In ModSecurity, this is called the ARGS collection with the colon as separator. Try to memorize this!<\/p>\n<p>In professional use, this is likely the exclusion rule construct that is used the most (not with the Referer header, though, but with the <em>REQUEST_FILENAME<\/em> variable as shown above). This exclusion construct is very granular on the parameter level and it can be constructed to have only minimal impact on the requests thanks to the power of <em>SecRule<\/em>. If you would rather go with a tag than with an ID, here is your example:<\/p>\n<div class=\"sourceCode\" id=\"cb23\"><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=\"cb23-1\"><a href=\"#cb23-1\" aria-hidden=\"true\"><\/a><span class=\"ex\">SecRule<\/span> REQUEST_HEADERS:Referer <span class=\"st\">&quot;@streq http:\/\/localhost\/login\/displayLogin.do&quot;<\/span> <span class=\"kw\">\\<\/span><\/span>\n<span id=\"cb23-2\"><a href=\"#cb23-2\" aria-hidden=\"true\"><\/a>    <span class=\"st\">&quot;phase:1,nolog,pass,id:10000,ctl:ruleRemoveTargetByTag=attack-sqli;ARGS:password&quot;<\/span><\/span><\/code><\/pre><\/div>\n<p>This section was very important. Therefore, to summarize once again: We define a rule to suppress another rule. We use a pattern for this which lets us define a path as a condition. This enables us to disable rules for individual parts of an application but only in places where false alarms occur. And at the same time, it prevents us from disabling rules on the entire server.<\/p>\n<p>With this, we have seen all basic methods to handle false positives via rule exclusions. You now use the patterns for <em>exclusion rules<\/em> described above to work through the various <em>false positives<\/em>.<\/p>\n<p>Looking ahead at the next tutorial we will be using a custom script to write these rule exclusions, since writing them by hand is very hard to get right.<\/p>\n<h3 id=\"step-9-readjusting-the-anomaly-threshold\">Step 9: Readjusting the anomaly threshold<\/h3>\n<p>Handling false positives is tedious at times. However, with the goal of protecting the application, it is most certainly worthwhile. When we introduced the statistic script I stated that we should make sure that at least 99.999% of requests pass through the rule set without any false positives. The remaining positives, the ones caused by attackers, should be blocked. But we are still running with an anomaly limit of 10,000. We need to reduce this to a decent level. Any limit above 30 or 40 is unlikely to stop anything serious. With a threshold of 20, you start to see an effect and then with 10 you get fairly good protection from standard attackers. Even if an individual rule only scores 5 points, some attack classes like SQL injections typically trigger multiple alarms, so a limit of 10 catches quite a few attack requests. In other categories, the coverage with rules is less extensive. This means, the accumulation of multiple rules is rare. So it is perfectly possible to stay beneath a score of 10 with a certain attack payload. That\u2019s why only a limit of 5 for the inbound score and 4 for the outbound score gives you a good level security. These are the default values of the CRS.<\/p>\n<p>But how to lower the limit from 10,000 to 5 without harming production? It takes a certain trust in your tuning skills to perform this step. A more natural approach is to go over multiple iterations: An initial tuning round is performed with a limit of 10,000. When the most blatant sources of false positives are eliminated this way, you wait for a given amount of time and then lower the limit to 50 and examine the logs again. Tune and reduce to 30, then 20, 10 and finally 5. After every reduction, you need to check the new log files and run the statistic script. By looking at the statistics, you see what you can expect from a reduction of the limit. Let\u2019s look once more at the stats we examined before:<\/p>\n<div class=\"sourceCode\" id=\"cb24\"><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=\"cb24-1\"><a href=\"#cb24-1\" aria-hidden=\"true\"><\/a>$<span class=\"op\">&gt;<\/span> <span class=\"fu\">cat<\/span> tutorial-5\/tutorial-5-example-access.log <span class=\"kw\">|<\/span> <span class=\"ex\">alscores<\/span> <span class=\"kw\">|<\/span> <span class=\"ex\">modsec-positive-stats.rb<\/span> <\/span>\n<span id=\"cb24-2\"><a href=\"#cb24-2\" aria-hidden=\"true\"><\/a><span class=\"ex\">INCOMING<\/span>                     Num of req. <span class=\"kw\">|<\/span> <span class=\"ex\">%<\/span> of req. <span class=\"kw\">|<\/span>  <span class=\"ex\">Sum<\/span> of % <span class=\"kw\">|<\/span> <span class=\"ex\">Missing<\/span> %<\/span>\n<span id=\"cb24-3\"><a href=\"#cb24-3\" aria-hidden=\"true\"><\/a><span class=\"ex\">Number<\/span> of incoming req. (total) <span class=\"kw\">|<\/span>  <span class=\"ex\">10000<\/span> <span class=\"kw\">|<\/span> <span class=\"ex\">100.0000%<\/span> <span class=\"kw\">|<\/span> <span class=\"ex\">100.0000%<\/span> <span class=\"kw\">|<\/span>   <span class=\"ex\">0.0000%<\/span><\/span>\n<span id=\"cb24-4\"><a href=\"#cb24-4\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb24-5\"><a href=\"#cb24-5\" aria-hidden=\"true\"><\/a><span class=\"ex\">Empty<\/span> or miss. incoming score   <span class=\"kw\">|<\/span>      <span class=\"ex\">0<\/span> <span class=\"kw\">|<\/span>   <span class=\"ex\">0.0000%<\/span> <span class=\"kw\">|<\/span>   <span class=\"ex\">0.0000%<\/span> <span class=\"kw\">|<\/span> <span class=\"ex\">100.0000%<\/span><\/span>\n<span id=\"cb24-6\"><a href=\"#cb24-6\" aria-hidden=\"true\"><\/a><span class=\"ex\">Reqs<\/span> with incoming score of   0 <span class=\"kw\">|<\/span>   <span class=\"ex\">9931<\/span> <span class=\"kw\">|<\/span>  <span class=\"ex\">99.3100%<\/span> <span class=\"kw\">|<\/span>  <span class=\"ex\">99.3100%<\/span> <span class=\"kw\">|<\/span>   <span class=\"ex\">0.6900%<\/span><\/span>\n<span id=\"cb24-7\"><a href=\"#cb24-7\" aria-hidden=\"true\"><\/a><span class=\"ex\">Reqs<\/span> with incoming score of   1 <span class=\"kw\">|<\/span>      <span class=\"ex\">0<\/span> <span class=\"kw\">|<\/span>   <span class=\"ex\">0.0000%<\/span> <span class=\"kw\">|<\/span>  <span class=\"ex\">99.3100%<\/span> <span class=\"kw\">|<\/span>   <span class=\"ex\">0.6900%<\/span><\/span>\n<span id=\"cb24-8\"><a href=\"#cb24-8\" aria-hidden=\"true\"><\/a><span class=\"ex\">Reqs<\/span> with incoming score of   2 <span class=\"kw\">|<\/span>      <span class=\"ex\">6<\/span> <span class=\"kw\">|<\/span>   <span class=\"ex\">0.0600%<\/span> <span class=\"kw\">|<\/span>  <span class=\"ex\">99.3700%<\/span> <span class=\"kw\">|<\/span>   <span class=\"ex\">0.6300%<\/span><\/span>\n<span id=\"cb24-9\"><a href=\"#cb24-9\" aria-hidden=\"true\"><\/a><span class=\"ex\">Reqs<\/span> with incoming score of   3 <span class=\"kw\">|<\/span>      <span class=\"ex\">5<\/span> <span class=\"kw\">|<\/span>   <span class=\"ex\">0.0500%<\/span> <span class=\"kw\">|<\/span>  <span class=\"ex\">99.4200%<\/span> <span class=\"kw\">|<\/span>   <span class=\"ex\">0.5800%<\/span><\/span>\n<span id=\"cb24-10\"><a href=\"#cb24-10\" aria-hidden=\"true\"><\/a><span class=\"ex\">Reqs<\/span> with incoming score of   4 <span class=\"kw\">|<\/span>      <span class=\"ex\">0<\/span> <span class=\"kw\">|<\/span>   <span class=\"ex\">0.0000%<\/span> <span class=\"kw\">|<\/span>  <span class=\"ex\">99.4200%<\/span> <span class=\"kw\">|<\/span>   <span class=\"ex\">0.5800%<\/span><\/span>\n<span id=\"cb24-11\"><a href=\"#cb24-11\" aria-hidden=\"true\"><\/a><span class=\"ex\">Reqs<\/span> with incoming score of   5 <span class=\"kw\">|<\/span>     <span class=\"ex\">55<\/span> <span class=\"kw\">|<\/span>   <span class=\"ex\">0.5499%<\/span> <span class=\"kw\">|<\/span>  <span class=\"ex\">99.9700%<\/span> <span class=\"kw\">|<\/span>   <span class=\"ex\">0.0300%<\/span><\/span>\n<span id=\"cb24-12\"><a href=\"#cb24-12\" aria-hidden=\"true\"><\/a><span class=\"ex\">Reqs<\/span> with incoming score of   6 <span class=\"kw\">|<\/span>      <span class=\"ex\">0<\/span> <span class=\"kw\">|<\/span>   <span class=\"ex\">0.0000%<\/span> <span class=\"kw\">|<\/span>  <span class=\"ex\">99.9700%<\/span> <span class=\"kw\">|<\/span>   <span class=\"ex\">0.0300%<\/span><\/span>\n<span id=\"cb24-13\"><a href=\"#cb24-13\" aria-hidden=\"true\"><\/a><span class=\"ex\">Reqs<\/span> with incoming score of   7 <span class=\"kw\">|<\/span>      <span class=\"ex\">0<\/span> <span class=\"kw\">|<\/span>   <span class=\"ex\">0.0000%<\/span> <span class=\"kw\">|<\/span>  <span class=\"ex\">99.9700%<\/span> <span class=\"kw\">|<\/span>   <span class=\"ex\">0.0300%<\/span><\/span>\n<span id=\"cb24-14\"><a href=\"#cb24-14\" aria-hidden=\"true\"><\/a><span class=\"ex\">Reqs<\/span> with incoming score of   8 <span class=\"kw\">|<\/span>      <span class=\"ex\">0<\/span> <span class=\"kw\">|<\/span>   <span class=\"ex\">0.0000%<\/span> <span class=\"kw\">|<\/span>  <span class=\"ex\">99.9700%<\/span> <span class=\"kw\">|<\/span>   <span class=\"ex\">0.0300%<\/span><\/span>\n<span id=\"cb24-15\"><a href=\"#cb24-15\" aria-hidden=\"true\"><\/a><span class=\"ex\">Reqs<\/span> with incoming score of   9 <span class=\"kw\">|<\/span>      <span class=\"ex\">0<\/span> <span class=\"kw\">|<\/span>   <span class=\"ex\">0.0000%<\/span> <span class=\"kw\">|<\/span>  <span class=\"ex\">99.9700%<\/span> <span class=\"kw\">|<\/span>   <span class=\"ex\">0.0300%<\/span><\/span>\n<span id=\"cb24-16\"><a href=\"#cb24-16\" aria-hidden=\"true\"><\/a><span class=\"ex\">Reqs<\/span> with incoming score of  10 <span class=\"kw\">|<\/span>      <span class=\"ex\">3<\/span> <span class=\"kw\">|<\/span>   <span class=\"ex\">0.0300%<\/span> <span class=\"kw\">|<\/span> <span class=\"ex\">100.0000%<\/span> <span class=\"kw\">|<\/span>   <span class=\"ex\">0.0000%<\/span><\/span>\n<span id=\"cb24-17\"><a href=\"#cb24-17\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb24-18\"><a href=\"#cb24-18\" aria-hidden=\"true\"><\/a><span class=\"ex\">Incoming<\/span> average:   0.0332    Median   0.0000    Standard deviation   0.4163<\/span>\n<span id=\"cb24-19\"><a href=\"#cb24-19\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb24-20\"><a href=\"#cb24-20\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb24-21\"><a href=\"#cb24-21\" aria-hidden=\"true\"><\/a><span class=\"ex\">OUTGOING<\/span>                     Num of req. <span class=\"kw\">|<\/span> <span class=\"ex\">%<\/span> of req. <span class=\"kw\">|<\/span>  <span class=\"ex\">Sum<\/span> of % <span class=\"kw\">|<\/span> <span class=\"ex\">Missing<\/span> %<\/span>\n<span id=\"cb24-22\"><a href=\"#cb24-22\" aria-hidden=\"true\"><\/a><span class=\"ex\">Number<\/span> of outgoing req. (total) <span class=\"kw\">|<\/span>  <span class=\"ex\">10000<\/span> <span class=\"kw\">|<\/span> <span class=\"ex\">100.0000%<\/span> <span class=\"kw\">|<\/span> <span class=\"ex\">100.0000%<\/span> <span class=\"kw\">|<\/span>   <span class=\"ex\">0.0000%<\/span><\/span>\n<span id=\"cb24-23\"><a href=\"#cb24-23\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb24-24\"><a href=\"#cb24-24\" aria-hidden=\"true\"><\/a><span class=\"ex\">Empty<\/span> or miss. outgoing score   <span class=\"kw\">|<\/span>      <span class=\"ex\">0<\/span> <span class=\"kw\">|<\/span>   <span class=\"ex\">0.0000%<\/span> <span class=\"kw\">|<\/span>   <span class=\"ex\">0.0000%<\/span> <span class=\"kw\">|<\/span> <span class=\"ex\">100.0000%<\/span><\/span>\n<span id=\"cb24-25\"><a href=\"#cb24-25\" aria-hidden=\"true\"><\/a><span class=\"ex\">Reqs<\/span> with outgoing score of   0 <span class=\"kw\">|<\/span>  <span class=\"ex\">10000<\/span> <span class=\"kw\">|<\/span> <span class=\"ex\">100.0000%<\/span> <span class=\"kw\">|<\/span> <span class=\"ex\">100.0000%<\/span> <span class=\"kw\">|<\/span>   <span class=\"ex\">0.0000%<\/span><\/span>\n<span id=\"cb24-26\"><a href=\"#cb24-26\" aria-hidden=\"true\"><\/a><\/span>\n<span id=\"cb24-27\"><a href=\"#cb24-27\" aria-hidden=\"true\"><\/a><span class=\"ex\">Outgoing<\/span> average:   0.0000    Median   0.0000    Standard deviation   0.0000<\/span><\/code><\/pre><\/div>\n<p>10,000 requests is not really a big log file, but it will do for our purposes. Based on the data, we can immediately decide to reduce the limit to 50. It is unlikely that a request will hit that threshold &#8211; and if it does, it is going to be an isolated transaction which is very rare.<\/p>\n<p>Reducing the limit to 5 would be a bit overzealous, because the column on the right states that 0.03% of the requests scored higher than 5. We should get rid of the 3 false positives at 10 before we should reduce the limit to 5.<\/p>\n<p>With this statistical data, the iterative tuning process becomes quite clear: The <em>modsec-positive-stats.rb<\/em> script brings sense and reason to the process.<\/p>\n<p>For the outbound responses, the situation is a bit simpler as you will hardly see any scores above 5. There simply are not enough rules to have any cumulative effect; probably because there is not much you can check in a response. So, I reduce the response threshold down to 5 or 4 rather quickly (which happens to be the default value of the CRS outbound request threshold).<\/p>\n<p>I think the tuning concept and the theory are now quite clear. In the next tutorial, we will continue with tuning false positives to gain some practice with the methods demonstrated here. As mentioned in the previous step, I will also introduce a script which helps with the construction of the more complicated exclusion rules.<\/p>\n<h3 id=\"step-10-goodie-summary-of-the-ways-of-combating-false-positives\">Step 10 (Goodie): Summary of the ways of combating false positives<\/h3>\n<p>It is possibly best to summarize the four tuning methods in a graphic. So here is a cheatsheet for your use!<\/p>\n<p><a href=\"https:\/\/www.netnea.com\/cms\/rule-exclusion-cheatsheet-download\/\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.netnea.com\/files\/tutorial-7-rule-exclusion-cheatsheet_small.png\" alt=\"Rule Exclusion CheatSheet\" width=\"476\" height=\"673\" \/><\/a><\/p>\n<h3 id=\"references\">References<\/h3>\n<ul>\n<li><a href=\"https:\/\/coreruleset.org\">OWASP CRS<\/a><\/li>\n<li><a href=\"http:\/\/blog.spiderlabs.com\/2011\/08\/modsecurity-advanced-topic-of-the-week-exception-handling.html\">Spider Labs Blog Post: Exception Handling<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/SpiderLabs\/ModSecurity\/wiki\/Reference-Manual\">ModSecurity Reference Manual<\/a><\/li>\n<\/ul>\n<h3 id=\"license-copying-further-use\">License \/ Copying \/ Further use<\/h3>\n<p><a rel=\"license\" href=\"http:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/\"><img decoding=\"async\" alt=\"Creative Commons License\" style=\"border-width:0\" src=\"https:\/\/i.creativecommons.org\/l\/by-nc-sa\/4.0\/80x15.png\" \/><\/a><br \/>This work is licensed under a <a rel=\"license\" href=\"http:\/\/creativecommons.org\/licenses\/by-nc-sa\/4.0\/\">Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License<\/a>.<\/p>\n<h5 id=\"changelog\">Changelog<\/h5>\n<ul>\n<li>2026-01-26: Updated CRS 3.3.7 to version CRS 4.22.0<\/li>\n<li>2024-11-08: Updated CRS version from 3.3.5 to 3.3.7<\/li>\n<li>2024-01-13: Updated CRS version from 3.3.4 to 3.3.5<\/li>\n<li>2023-03-10: Add SecRequestBodyJsonDepthLimit directive<\/li>\n<li>2022-11-25: Removed unnecessary sudo from ln comand in step 1<\/li>\n<li>2022-11-17: Update log example in step 4 to extended-2019 logformat<\/li>\n<li>2022-11-14: Updated CRS version from 3.3.2 to 3.3.4<\/li>\n<li>2022-09-06: Updated CRS version from 3.3.0 to 3.3.2<\/li>\n<li>2019-07-22: Moved CRS repo to new github at https:\/\/github.com\/coreruleset\/coreruleset<\/li>\n<li>2019-11-04: Added env=HTTPS condition to STS header config<\/li>\n<li>2019-11-01: Consistent naming of CRS in config comments<\/li>\n<li>2019-10-31: Disabling TLSv1 and TLSv1.1<\/li>\n<li>2019-04-03: Raise initial anomaly threshold to 10,000.<\/li>\n<li>2019-03-21: Upgrade CRS 3.0.2 -&gt; 3.1.0<\/li>\n<li>2018-04-13: Update title format (markdown); rewordings (Simon Studer)<\/li>\n<li>2017-12-17: Renumbered 200004-&gt;200005<\/li>\n<li>2017-07-26: Upgrade CRS 3.0.0 -&gt; 3.0.2<\/li>\n<li>2017-03-05: MaxClients -&gt; MaxRequestWorkers; changed order of ModSec tmp data folders<\/li>\n<li>2017-02-25: Getting rid of AllowOverride completely, mentioning ruby package<\/li>\n<li>2017-02-16: Reformatting<\/li>\n<li>2017-02-15: Typos pointed out by Osama Elnaggar<\/li>\n<li>2016-12-28: Removing single quotes from id actions in ModSec rules, fixing broken link<\/li>\n<li>2016-11-14: Fixing links to previous tutorials<\/li>\n<li>2016-11-02: CRS 3.0.0-rc2 -&gt; CRS 3.0.0-rc3, fixed broken link to stats script<\/li>\n<li>2016-11-01: Adding Cheatsheet. Publication.<\/li>\n<li>2016-10-31: Feedback by Walter Hop<\/li>\n<li>2016-10-31: Feedback by Manuel Leos Rivas<\/li>\n<li>2016-10-10: Fixing small issues<\/li>\n<li>2016-07-15: Apache 2.4.20 -&gt; 2.4.23<\/li>\n<li>2016-07-15: Apache 2.4.20 -&gt; 2.4.23<\/li>\n<li>2016-04-18: Fixing small issues<\/li>\n<li>2016-03-10: Translated to English<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Including the OWASP CRS What are we doing? We are embedding the OWASP CRS in our Apache web server and eliminating false alarms. Why are we doing this? The ModSecurity Web Application Firewall, as we set up in Tutorial 6, still has barely any rules. The protection only works when you configure an additional rule [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-950","page","type-page","status-publish","czr-hentry"],"_links":{"self":[{"href":"https:\/\/www.netnea.com\/cms\/wp-json\/wp\/v2\/pages\/950","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.netnea.com\/cms\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.netnea.com\/cms\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.netnea.com\/cms\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/www.netnea.com\/cms\/wp-json\/wp\/v2\/comments?post=950"}],"version-history":[{"count":5,"href":"https:\/\/www.netnea.com\/cms\/wp-json\/wp\/v2\/pages\/950\/revisions"}],"predecessor-version":[{"id":2146,"href":"https:\/\/www.netnea.com\/cms\/wp-json\/wp\/v2\/pages\/950\/revisions\/2146"}],"wp:attachment":[{"href":"https:\/\/www.netnea.com\/cms\/wp-json\/wp\/v2\/media?parent=950"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}