mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-08-13 21:36:00 +03:00
6188 lines
243 KiB
XML
6188 lines
243 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
|
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
|
<article>
|
|
<title><trademark class="registered">ModSecurity</trademark> Reference
|
|
Manual</title>
|
|
|
|
<articleinfo>
|
|
<releaseinfo>Version 2.6.0-trunk (Sep 18, 2009)</releaseinfo>
|
|
|
|
<copyright>
|
|
<year>2004-2009</year>
|
|
|
|
<holder>Breach Security, Inc. (<ulink
|
|
url="http://www.breach.com">http://www.breach.com</ulink>)</holder>
|
|
</copyright>
|
|
</articleinfo>
|
|
|
|
<section id="introduction">
|
|
<title>Introduction</title>
|
|
|
|
<para>ModSecurity is a web application firewall (WAF). With over 70% of
|
|
attacks now carried out over the web application level, organisations need
|
|
all the help they can get in making their systems secure. WAFs are
|
|
deployed to establish an increased external security layer to detect
|
|
and/or prevent attacks before they reach web applications. ModSecurity
|
|
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 logging 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,
|
|
ensuring only the relevant data is recorded. As some of the request
|
|
and/or response may contain sensitive data in certain fields,
|
|
ModSecurity can be configured to mask these fields before they are
|
|
written to the audit log.</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. A 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 a positive security model is
|
|
deployed, only requests that are known to be valid are accepted,
|
|
with everything else rejected. This model requires knownledge of the
|
|
web applications you are protecting. Therefore a positive security
|
|
model works best with applications that are heavily used but rarely
|
|
updated so that maintenance of the model is minimized.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Known weaknesses and vulnerabilities. Its rule language makes
|
|
ModSecurity an ideal external patching tool. External patching
|
|
(sometimes referred to as Virtual Patching) is 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 applied to
|
|
the application.</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 is designed to be easy to use, yet flexible:
|
|
common operations are simple while complex operations are possible.
|
|
Certified ModSecurity Rules, included with ModSecurity, contain a
|
|
comprehensive set of rules that implement general-purpose hardening,
|
|
protocol validation and detection of 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 if required.</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>
|
|
</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>
|
|
<title>Portability</title>
|
|
|
|
<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 id="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, ModSecurity Pro, and ModSecurity Core
|
|
Rules are trademarks or registered trademarks of Breach Security,
|
|
Inc.</para>
|
|
</note>
|
|
</section>
|
|
</section>
|
|
|
|
<section>
|
|
<title><trademark>ModSecurity Core Rules</trademark></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.x. Unlike
|
|
intrusion detection and prevention systems, which rely on signatures
|
|
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 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="installation">
|
|
<title>Installation</title>
|
|
|
|
<para>ModSecurity installation requirements:</para>
|
|
|
|
<orderedlist continuation="restarts" inheritnum="ignore">
|
|
<listitem>
|
|
<para>ModSecurity 2.x works only with Apache 2.0.x or higher. Version
|
|
2.2.x is highly recommended.</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>libapr and libapr-util</para>
|
|
|
|
<para><ulink type=""
|
|
url="http://apr.apache.org/">http://apr.apache.org/</ulink></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>libpcre</para>
|
|
|
|
<para><ulink type=""
|
|
url="http://www.pcre.org/">http://www.pcre.org/</ulink></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>libxml2</para>
|
|
|
|
<para><ulink type=""
|
|
url="http://xmlsoft.org/downloads.html">http://xmlsoft.org/downloads.html</ulink></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>liblua v5.1.x</para>
|
|
|
|
<para>This library is optional and only needed if you will be using
|
|
the new Lua engine.</para>
|
|
|
|
<para><ulink type=""
|
|
url="http://www.lua.org/download.html">http://www.lua.org/download.html</ulink></para>
|
|
|
|
<para>Note that ModSecurity requires the dynamic libraries. These are
|
|
not built by default in the source distribution, so the binary
|
|
distribution is recommended.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>libcurl v7.15.1 or higher</para>
|
|
|
|
<para>If you will be using the ModSecurity Log Collector (mlogc) to
|
|
send audit logs to a central repository, then you will also need the
|
|
curl library.</para>
|
|
|
|
<para><ulink type=""
|
|
url="http://curl.haxx.se/libcurl/">http://curl.haxx.se/libcurl/</ulink></para>
|
|
</listitem>
|
|
</orderedlist>
|
|
|
|
<para>ModSecurity installation consists of the following steps:</para>
|
|
|
|
<orderedlist continuation="restarts" inheritnum="ignore">
|
|
<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>
|
|
|
|
<note>
|
|
<para>There are certain configure options that are meant for
|
|
debugging an other development use. If enabled, these
|
|
options can substantially impact performance. These options
|
|
include all <literal>--debug-*</literal> options as well as
|
|
the <literal>--enable-performance-measurements</literal>
|
|
options.</para>
|
|
</note>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Compile with: <literal>make</literal></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Optionally test with: <literal>make
|
|
test</literal></para>
|
|
|
|
<note>
|
|
<para>This is step is still a bit experimental. If you have
|
|
problems, please send the full output and error from the
|
|
build to the support list. Most common issues are related to
|
|
not finding the required headers and/or libraries.</para>
|
|
</note>
|
|
</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 (via the
|
|
<literal>--with-pcre</literal> ModSecurity configure option).</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>
|
|
|
|
<para>Non-gcc compilers may have problems running out-of-the-box as the
|
|
current build system was designed around the gcc compiler and some
|
|
compiler/linker flags may differ. To use a non-gcc compiler you may need
|
|
some manual Makefile tweaks if issues cannot be solved by exporting
|
|
custom CFLAGS and CPPFLAGS environment variables.</para>
|
|
|
|
<para>If you are upgrading from ModSecurity 1.x, please refer to the
|
|
migration matrix at <ulink type=""
|
|
url="http://www.modsecurity.org/documentation/ModSecurity-Migration-Matrix.pdf">http://www.modsecurity.org/documentation/ModSecurity-Migration-Matrix.pdf</ulink></para>
|
|
</note>
|
|
</section>
|
|
|
|
<section id="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. The first version to use a given
|
|
directive is given in the Version 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 evaluated 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,action3</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecAction
|
|
nolog,phase:1,initcol:RESOURCE=%{REQUEST_FILENAME}</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Version:</emphasis> 2.0.0</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>Scope:</emphasis> Main</para>
|
|
|
|
<para><emphasis>Version:</emphasis> 2.0.0</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>Version:</emphasis> 2.0.0</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 ^(?:5|4\d[^4])</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>Version:</emphasis> 2.0.0</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>Version:</emphasis> 2.1.2</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>SecAuditLogDirMode</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Configures the mode
|
|
(permissions) of any directories created for concurrent audit logs using
|
|
an octal mode (as used in chmod). See <literal
|
|
moreinfo="none">SecAuditLogFileMode</literal> for controlling the mode
|
|
of audit log files.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecAuditLogDirMode octal_mode|"default"</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecAuditLogDirMode 02750</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Version:</emphasis> 2.5.10</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> This feature is not
|
|
available on operating systems not supporting octal file modes. The
|
|
default mode (0600) only grants read/write access to the account writing
|
|
the file. If access from another account is needed (using mpm-itk is a
|
|
good example), then this directive may be required. However, 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>
|
|
|
|
<note>
|
|
<para>The process umask may still limit the mode if it is being more
|
|
restrictive than the mode set using this directive.</para>
|
|
</note>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecAuditLogFileMode</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Configures the mode
|
|
(permissions) of any files created for concurrent audit logs using an
|
|
octal mode (as used in chmod). See <literal
|
|
moreinfo="none">SecAuditLogDirMode</literal> for controlling the mode of
|
|
created audit log directories.</para>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecAuditLogFileMode
|
|
octal_mode|"default"</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecAuditLogFileMode 00640</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Version:</emphasis> 2.5.10</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> This feature is not
|
|
available on operating systems not supporting octal file modes. The
|
|
default mode (0600) only grants read/write access to the account writing
|
|
the file. If access from another account is needed (using mpm-itk is a
|
|
good example), then this directive may be required. However, 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>
|
|
|
|
<note>
|
|
<para>The process umask may still limit the mode if it is being more
|
|
restrictive than the mode set using this directive.</para>
|
|
</note>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>SecAuditLogParts</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Defines which part of each
|
|
transaction are going to be recorded in audit log. Each part is assigned
|
|
a single letter. If a letter appears in the list then the equivalent
|
|
part of each transactions will be recorded. See below for the list of
|
|
all parts.</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>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Version:</emphasis> 2.0.0</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>
|
|
|
|
<note>
|
|
<para>Please refer to the ModSecurity Data Formats document for a
|
|
detailed description of every available part.</para>
|
|
</note>
|
|
|
|
<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
|
|
^(?:5|4\d[^4])</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Version:</emphasis> 2.0.0</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>Version:</emphasis> 2.0.0</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>Version:</emphasis> 2.0.0</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>
|
|
(Deprecated/Experimental)</title>
|
|
|
|
<para><emphasis>Description:</emphasis> Controls caching of
|
|
transformations. Caching is off by default starting with 2.5.6, when it
|
|
was deprecated and downgraded back to experimental.</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><emphasis>Version:</emphasis> 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">incremental:on|off</literal> -
|
|
enabling this option will cache every transformation instead of just
|
|
the final transformation. (default: off)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">maxitems:N</literal> - do not allow
|
|
more than N transformations to be cached. The cache will then be
|
|
disabled. A zero value is interpreted as "unlimited". This option
|
|
may be useful to limit caching for a form with a large number of
|
|
ARGS. (default: 512)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal moreinfo="none">minlen:N</literal> - do not cache the
|
|
transformation if the value's length is less than N bytes. (default:
|
|
32)</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: 1024)</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>Version:</emphasis> 2.0.0</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> This feature is not
|
|
available on Windows builds. 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.builds. 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 (reload) 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>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope</emphasis>: Main</para>
|
|
|
|
<para><emphasis>Version</emphasis>: 2.5.0</para>
|
|
|
|
<para><emphasis>Dependencies/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>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope</emphasis>: Any</para>
|
|
|
|
<para><emphasis>Version</emphasis>: 2.5.0</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> N/A</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>Version:</emphasis> 2.0.0</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>Scope:</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>Version:</emphasis> 2.0.0</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>Version:</emphasis> 2.0.0</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</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Version:</emphasis> 2.0.0</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> Rules following a
|
|
<literal>SecDefaultAction</literal> directive will inherit this setting
|
|
unless a specific action is specified for an individual rule or until
|
|
another <literal>SecDefaultAction</literal> 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
|
|
<literal>SecDefaultAction</literal>.</para>
|
|
|
|
<para>The default value is minimal (differing from previous
|
|
versions):</para>
|
|
|
|
<programlisting format="linespecific">SecDefaultAction phase:2,log,auditlog,pass</programlisting>
|
|
|
|
<note>
|
|
<para><literal>SecDefaultAction</literal> must specify a disruptive
|
|
action and a processing phase and cannot contain metadata
|
|
actions.</para>
|
|
</note>
|
|
|
|
<warning>
|
|
<para><literal>SecDefaultAction</literal> is <emphasis>not</emphasis>
|
|
inherited across configuration contexts. (For an example of why this
|
|
may be a problem for you, read the following ModSecurity Blog entry
|
|
<ulink
|
|
url="http://blog.modsecurity.org/2008/07/modsecurity-tri.html">http://blog.modsecurity.org/2008/07/modsecurity-tri.html</ulink>).</para>
|
|
</warning>
|
|
</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>Version:</emphasis> 2.5.0</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> Check out
|
|
<literal>maxmind.com</literal> 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>Version:</emphasis> 2.0.0</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> By default httpd-guardian
|
|
will defend against clients that send more than 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 <literal>skipAfter</literal> action.
|
|
A <literal>SecMarker</literal> directive essentially creates a rule that
|
|
does nothing and whose only purpose it to carry the given ID.</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>Version:</emphasis> 2.5.0</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> None</para>
|
|
|
|
<para><programlisting format="linespecific">SecRule REQUEST_URI "^/$" \
|
|
"chain,t:none,t:urlDecode,t:lowercase,t:normalisePath,<emphasis>skipAfter:99</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:08,severity:4,msg:'Missing a Host Header'"
|
|
SecRule &REQUEST_HEADERS:Accept "@eq 0" \
|
|
"log,deny,log,status:400,id:15,msg:'Request Missing an Accept Header'"
|
|
<emphasis>
|
|
SecMarker 99</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>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecPdfProtect On|Off</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecPdfProtect On</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Version:</emphasis> 2.5.0</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> None</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>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecPdfProtectMethod method</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecPdfProtectMethod TokenRedirection</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Version:</emphasis> 2.5.0</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> None</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>
|
|
|
|
<para><emphasis>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecPdfProtectSecret secret</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecPdfProtectSecret
|
|
MyRandomSecretString</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Version:</emphasis> 2.5.0</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> None</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>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecPdfProtectTimeout timeout</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecPdfProtectTimeout 10</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Version:</emphasis> 2.5.0</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> None</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>Syntax:</emphasis> <literal
|
|
moreinfo="none">SecPdfProtectTokenName name</literal></para>
|
|
|
|
<para><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecPdfProtectTokenName PDFTOKEN</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Version:</emphasis> 2.5.0</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> None</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>Version:</emphasis> 2.0.0</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> This directive is
|
|
required if you plan to inspect <literal>POST_PAYLOAD</literal>. This
|
|
directive must be used along with the "phase:2" processing phase action
|
|
and <literal>REQUEST_BODY</literal> 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>Version:</emphasis> 2.0.0</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>Version:</emphasis> 2.5.0</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>Version:</emphasis> 2.0.0</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>Version:</emphasis> 2.0.0</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>
|
|
|
|
<para><emphasis>Version:</emphasis> 2.5.0</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> None</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>Version:</emphasis> 2.0.0</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>Version:</emphasis> 2.0.0</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>Version:</emphasis> 2.0.0</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><literal>
|
|
"phase:1,t:none,t:urlDecode,t:lowercase,t:normalisePath"</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Version:</emphasis> 2.0.0</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 ARGS dirty</programlisting>
|
|
|
|
<para>Each rule can specify one or more variables:</para>
|
|
|
|
<programlisting format="linespecific">SecRule ARGS|REQUEST_HEADERS:User-Agent 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>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>Collections</title>
|
|
|
|
<para>A variable can contain one or many pieces of data, depending on
|
|
the nature of the variable and the way it is used. We've seen examples
|
|
of both approaches in the previous section. When a variable can
|
|
contain more than one value we refer to it as a
|
|
<emphasis>collection</emphasis>.</para>
|
|
|
|
<para>Collections are always expanded before a rule is run. For
|
|
example, the following rule:</para>
|
|
|
|
<programlisting>SecRule ARGS dirty</programlisting>
|
|
|
|
<para>will be expanded to:</para>
|
|
|
|
<programlisting>SecRule ARGS:p dirty
|
|
SecRule ARGS:q dirty</programlisting>
|
|
|
|
<para>in a requests that has only two parameters, named
|
|
<literal>p</literal> and <literal>q</literal>.</para>
|
|
|
|
<para>Collections come in several flavours:</para>
|
|
|
|
<variablelist>
|
|
<varlistentry>
|
|
<term>Read-only</term>
|
|
|
|
<listitem>
|
|
<para>Created at runtime using transaction data. For example:
|
|
<literal>ARGS</literal> (contains a list of all request
|
|
parameter values) and <literal>REQUEST_HEADERS</literal>
|
|
(contains a list of all request header values).</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term>Transient Read/Write</term>
|
|
|
|
<listitem>
|
|
<para>The <literal>TX</literal> collection is created (empty)
|
|
for every transaction. Rules can read from it and write to it
|
|
(using the <literal>setvar</literal> action, for example), but
|
|
the information stored in this collection will not survive the
|
|
end of transaction.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term>Persistent Read/Write</term>
|
|
|
|
<listitem>
|
|
<para>There are several collections that can be written to, but
|
|
which are persisted to the storage backend. These collections
|
|
are used to track clients across transactions. Examples of
|
|
collections that fall into this type are <literal>IP</literal>,
|
|
<literal>SESSION</literal> and <literal>USER</literal>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
</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> (regular expression) operator.
|
|
You can also explicitly specify the operator you want to use by using
|
|
<literal moreinfo="none">@</literal>, followed by the name of an
|
|
operator, at the beginning of the second <literal>SecRule</literal>
|
|
parameter:</para>
|
|
|
|
<programlisting format="linespecific">SecRule ARGS "@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 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>Operator negation</title>
|
|
|
|
<para>Operator results can be negated by using an exclamation mark at
|
|
the beginning of the second parameter. The following rule matches if
|
|
the word <literal>dirty</literal> does <emphasis>not</emphasis> appear
|
|
in the <literal>User-Agent</literal> request header:</para>
|
|
|
|
<programlisting>SecRule REQUEST_HEADERS:User-Agent !dirty</programlisting>
|
|
|
|
<para>You can use the exclamation mark in combination with any
|
|
parameter. If you do, the exclamation mark needs to go first, followed
|
|
by the explicit operator reference. The following rule has the same
|
|
effect as the previous example:</para>
|
|
|
|
<programlisting>SecRule REQUEST_HEADERS:User-Agent "!@rx dirty"</programlisting>
|
|
|
|
<para>If you need to use negation in a rule that is going to be
|
|
applied to several variables then it may not be immediately clear what
|
|
will happen. Consider the following example:</para>
|
|
|
|
<programlisting>SecRule ARGS:p|ARGS:q !dirty</programlisting>
|
|
|
|
<para>The above rule is identical to:</para>
|
|
|
|
<programlisting>SecRule ARGS:p !dirty
|
|
SecRule ARGS:q !dirty</programlisting>
|
|
|
|
<warning>
|
|
<para>Negation is applied to operations against individual
|
|
operations, not agains the entire variable list.</para>
|
|
</warning>
|
|
</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>Version:</emphasis> 2.0.0</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">SecRuleEngine 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>
|
|
|
|
<note>
|
|
<para>Configuration contexts are an Apache concept. Directives
|
|
<literal><Directory></literal>,
|
|
<literal><Files></literal>,
|
|
<literal><Location></literal> and
|
|
<literal><VirtualHost></literal> are all used to create
|
|
configuration contexts. For more information please go to the
|
|
Apache documentation section <ulink
|
|
url="http://httpd.apache.org/docs/2.0/sections.html">Configuration
|
|
Sections</ulink>.</para>
|
|
</note>
|
|
</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>Version:</emphasis> 2.0.0</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">SecRuleUpdateActionById RULEID
|
|
ACTIONLIST</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>Version:</emphasis> 2.0.0</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>Version:</emphasis> 2.0.0</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><emphasis>Example Usage:</emphasis> <literal
|
|
moreinfo="none">SecRuleScript "/path/to/file.lua"
|
|
"block"</literal></para>
|
|
|
|
<para><emphasis>Processing Phase:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Scope:</emphasis> Any</para>
|
|
|
|
<para><emphasis>Version:</emphasis> 2.5.0</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> None</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("ARGS", "lowercase");
|
|
|
|
-- 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> as
|
|
the way the progamming interface may continue to evolve while we are
|
|
working for the best implementation style. Any user input into the
|
|
programming interface is appreciated.</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>Version:</emphasis> 2.5.0</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>Version:</emphasis> 2.0.0</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>Version:</emphasis> 2.0.0</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>Version:</emphasis> 2.0.0</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 mode (as used in
|
|
chmod).</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>Version:</emphasis> 2.1.6</para>
|
|
|
|
<para><emphasis>Dependencies/Notes:</emphasis> This feature is not
|
|
available on operating systems not supporting octal file modes. The
|
|
default mode (0600) only grants read/write access to the account writing
|
|
the file. If access from another account is needed (using clamd is a
|
|
good example), then this directive may be required. However, 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>
|
|
|
|
<note>
|
|
<para>The process umask may still limit the mode if it is being more
|
|
restrictive than the mode set using this directive.</para>
|
|
</note>
|
|
</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>Version:</emphasis> 2.0.0</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>Version:</emphasis> 2.0.0</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="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 (<literal>REQUEST_HEADERS</literal>)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Request body (<literal>REQUEST_BODY</literal>)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Response headers (<literal>RESPONSE_HEADERS</literal>)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Response body (<literal>RESPONSE_BODY</literal>)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Logging (<literal>LOGGING</literal>)</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
|
|
<para>Below is a diagram of the standard Apache Request Cycle. In the
|
|
diagram, the 5 ModSecurity processing phases are shown.</para>
|
|
|
|
<para><graphic contentwidth="5.5in"
|
|
fileref="apache_request_cycle-modsecurity.jpg" role="" scale=""
|
|
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 or 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 arguments (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 cannot 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="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,t:none,t:lowercase,t:normalisePath"
|
|
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,t:none,t:lowercase,t:normalisePath"
|
|
SecRule<emphasis> ARGS_NAMES</emphasis> "!^(p|a)$" "t:none,t:lowercase"</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 colon). The
|
|
<literal>ENV</literal> 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 results of
|
|
the last <literal moreinfo="none">@geoLookup</literal> operator. The
|
|
collection can be used to match geographical fields looked from an IP
|
|
address or hostname.</para>
|
|
|
|
<para>Available since ModSecurity 2.5.0.</para>
|
|
|
|
<para>Fields:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><emphasis>COUNTRY_CODE:</emphasis> Two character country code.
|
|
EX: US, GB, 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 if supported by the
|
|
database.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>POSTAL_CODE:</emphasis> The postal code if supported
|
|
by the database.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>LATITUDE:</emphasis> The latitude if supported by
|
|
the database.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>LONGITUDE:</emphasis> The longitude if supported by
|
|
the database.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>DMA_CODE:</emphasis> The metropolitan area code if
|
|
supported by the database. (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">SecGeoLookupDb /usr/local/geo/data/GeoLiteCity.dat
|
|
...
|
|
SecRule REMOTE_ADDR "<emphasis>@geoLookup</emphasis>" "chain,drop,msg:'Non-GB IP address'"
|
|
SecRule GEO:COUNTRY_CODE "!@streq GB"</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).</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>REQUEST_BASENAME</emphasis> "^login\.php$" phase:2,t:none,t:lowercase</programlisting>
|
|
|
|
<note>
|
|
<para>Please note that anti-evasion transformations are not applied to
|
|
this variable by default. <literal>REQUEST_BASENAME</literal> will
|
|
recognise both <literal>/</literal> and <literal>\</literal> as path
|
|
separators.</para>
|
|
</note>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">REQUEST_BODY</literal></title>
|
|
|
|
<para>This variable holds the data in the request body (including
|
|
<literal>POST_PAYLOAD</literal> data). <literal>REQUEST_BODY</literal>
|
|
should be used if the original order of the arguments is important
|
|
(<literal>ARGS</literal> 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>
|
|
|
|
<note>
|
|
<para>This variable is only available if the
|
|
<literal>URLENCODED</literal> request body processor parsed a request
|
|
body. This will occur by default when an
|
|
<literal>application/x-www-form-urlencoded</literal> is detected, or
|
|
the <literal>URLENCODED</literal> request body parser is forced. As of
|
|
2.5.7 it is possible to force the presence of the
|
|
<literal>REQUEST_BODY</literal> variable, but only when there is no
|
|
request body processor defined, using the
|
|
<literal>ctl:forceRequestBodyVariable</literal> option in the
|
|
<literal>REQUEST_HEADERS</literal> phase.</para>
|
|
</note>
|
|
</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 <literal>REQUEST_URI</literal>
|
|
minus the <literal>QUERY_STRING</literal> part (e.g. /index.php).
|
|
Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>REQUEST_FILENAME</emphasis> "^/cgi-bin/login\.php$" phase:2,t:none,t:normalisePath</programlisting>
|
|
|
|
<note>
|
|
<para>Please note that anti-evasion transformations are not used on
|
|
<literal>REQUEST_FILENAME</literal> by default.</para>
|
|
</note>
|
|
</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 <literal>REQUEST_HEADERS</literal> as a collection and is
|
|
applying the <literal>validateUrlEncoding</literal> operator against all
|
|
headers.</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>REQUEST_HEADERS</emphasis> "@validateUrlEncoding"</programlisting>
|
|
|
|
<para>Example: the second example is targeting only the
|
|
<literal>Host</literal> 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.</para>
|
|
|
|
<para>The following example will trigger if the request method is either
|
|
<literal>CONNECT</literal> 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
|
|
<literal>QUERY_STRING</literal> data (e.g. /index.php?p=X), however it
|
|
will never contain a domain name, even if it was provided on the request
|
|
line. It also does not include either the
|
|
<literal>REQUEST_METHOD</literal> or the HTTP version info.</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule <emphasis>REQUEST_URI</emphasis> "attack" phase:1,t:none,t:urlDecode,t:lowercase,t:normalisePath</programlisting>
|
|
|
|
<note>
|
|
<para>Please note that anti-evasion transformations are not used on
|
|
<literal>REQUEST_URI</literal> by default.</para>
|
|
</note>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">REQUEST_URI_RAW</literal></title>
|
|
|
|
<para>Same as <literal>REQUEST_URI</literal> but will contain the domain
|
|
name if it was provided on the request line (e.g.
|
|
http://www.example.com/index.php?p=X).</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<programlisting format="linespecific">SecRule<emphasis> REQUEST_URI_RAW</emphasis> "http:/" phase:1,t:none,t:urlDecode,t:lowercase,t:normalisePath</programlisting>
|
|
|
|
<note>
|
|
<para>Please note that anti-evasion transformations are not used on
|
|
<literal>REQUEST_URI_RAW</literal> by default.</para>
|
|
</note>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal moreinfo="none">RESPONSE_BODY</literal></title>
|
|
|
|
<para>This variable holds the data for the response payload.</para>
|
|
|
|
<para>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 as 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$" \
|
|
"phase:2,t:none,t:lowercase,t:normalisePath,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
|
|
<literal>validateDTD</literal> and <literal>validateSchema</literal>) 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="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 ARGS: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 ARGS: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>It converts whitespace characters (32, \f, \t, \n, \r, \v, 160) to
|
|
spaces (ASCII 32) and then compresses multiple consecutive space
|
|
characters into one.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>cssDecode</title>
|
|
|
|
<para>Decodes CSS-encoded characters, as specified at <ulink
|
|
url="http://www.w3.org/TR/REC-CSS2/syndata.html">http://www.w3.org/TR/REC-CSS2/syndata.html</ulink>.
|
|
This function uses only up to two bytes in the decoding process, meaning
|
|
it is useful to uncover ASCII characters (that wouldn't normally be
|
|
encoded) encoded using CSS encoding, or to counter evasion which is a
|
|
combination of a backslash and non-hexadecimal characters (e.g.
|
|
<literal>ja\vascript</literal> is equivalent to
|
|
<literal>javascript</literal>).</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>
|
|
|
|
<para>This function will convert any entity into a single byte only,
|
|
possibly resulting in a loss of information. It is thus useful to
|
|
uncover bytes that would otherwise not need to be encoded, but it cannot
|
|
do anything with the characters from the range above 255.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>jsDecode</literal></title>
|
|
|
|
<para>Decodes JavaScript escape sequences. If a
|
|
<literal>\uHHHH</literal> code is in the range of
|
|
<literal>FF01</literal>-<literal>FF5E</literal> (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
|
|
bytes).</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>lowercase</literal></title>
|
|
|
|
<para>This function 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 into text to
|
|
be usable (for example: <literal>t:md5,t:hexEncode</literal>).</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal><literal>none</literal></literal></title>
|
|
|
|
<para>Not an actual transformation function, but an instruction to
|
|
ModSecurity to remove all transformation functions associated with the
|
|
current rule.</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
|
|
input).</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>normalisePathWin</literal></title>
|
|
|
|
<para>Same as <literal>normalisePath</literal>, but will first convert
|
|
backslash characters to forward slashes.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>parityEven7bit</literal></title>
|
|
|
|
<para>This function calculates even parity of 7-bit data replacing the
|
|
8th bit of each target byte with the calculated parity bit.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>parityOdd7bit</literal></title>
|
|
|
|
<para>This function calculates odd parity of 7-bit data replacing the
|
|
8th bit of each target byte with the calculated parity bit.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>parityZero7bit</literal></title>
|
|
|
|
<para>This function calculates zero parity of 7-bit data replacing the
|
|
8th bit of each target byte with a zero parity bit which allows
|
|
inspection of even/odd parity 7bit data as ASCII7 data.</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 from input.</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 <literal>%xx</literal> like <literal
|
|
moreinfo="none">urlDecode, urlDecodeUni</literal> also decodes <literal
|
|
moreinfo="none">%uXXXX</literal> encoding. If the code is in the range
|
|
of <literal>FF01</literal>-<literal>FF5E</literal> (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
|
|
(for example: <literal>t:sha1,t:hexEncode</literal>).</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="actions">
|
|
<title>Actions</title>
|
|
|
|
<para>Each action belongs to one of five groups:</para>
|
|
|
|
<variablelist>
|
|
<varlistentry>
|
|
<term>Disruptive actions</term>
|
|
|
|
<listitem>
|
|
<para>Cause ModSecurity to do something. In many cases something
|
|
means block transaction, but not in all. For example, the allow
|
|
action is classified as a disruptive action, but it does the
|
|
opposite of blocking. There can only be one disruptive action per
|
|
rule (if there are multiple disruptive actions present, or
|
|
inherited, only the last one will take effect), or rule chain (in a
|
|
chain, a disruptive action can only appear in the first
|
|
rule).</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term>Non-disruptive actions</term>
|
|
|
|
<listitem>
|
|
<para>Do something, but that something does not and cannot affect
|
|
the rule processing flow. Setting a variable, or changing its value
|
|
is an example of a non-disruptive action. Non-disruptive action can
|
|
appear in any rule, including each rule belonging to a chain.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term>Flow actions</term>
|
|
|
|
<listitem>
|
|
<para>These actions affect the rule flow (for example
|
|
<literal>skip</literal> or <literal>skipAfter</literal>).</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term>Meta-data actions</term>
|
|
|
|
<listitem>
|
|
<para>Meta-data actions are used to provide more information about
|
|
rules. Examples include <literal>id</literal>,
|
|
<literal>rev</literal>, <literal>severity</literal> and
|
|
<literal>msg</literal>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term>Data actions</term>
|
|
|
|
<listitem>
|
|
<para>Not really actions, these are mere containers that hold data
|
|
used by other actions. For example, the <literal>status</literal>
|
|
action holds the status that will be used for blocking (if it takes
|
|
place).</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
<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.0 <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>
|
|
|
|
<note>
|
|
<para>While macro expansion is allowed in the additional content, you
|
|
are strongly cautioned against inserting user defined data
|
|
fields.</para>
|
|
</note>
|
|
</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. Do note that
|
|
# this rule should be preceeded by a rule that verifies
|
|
# only valid request methods (e.g. GET, HEAD and POST) are used.
|
|
SecRule REQUEST_METHOD ^POST$<emphasis> chain</emphasis>,t:none
|
|
SecRule REQUEST_HEADERS:Content-Length ^$ t:none</programlisting>
|
|
|
|
<note>
|
|
<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>
|
|
</note>
|
|
</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">forceRequestBodyVariable</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> and <literal moreinfo="none">
|
|
forceRequestBodyVariable</literal>, each configuration option
|
|
corresponds to one configuration directive and the usage is
|
|
identical.</para>
|
|
|
|
<para>The <literal>requestBodyProcessor</literal> 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> bodies,
|
|
respectively. A third processor, <literal>XML</literal>, 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>
|
|
|
|
<para>The <literal>forceRequestBodyVariable</literal> option allows you
|
|
to configure the <literal>REQUEST_BODY</literal> variable to be set when
|
|
there is no request body processor configured. This allows for
|
|
inspection of request bodies of unknown types.</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 phase:1,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 currently not available on Windows based builds.
|
|
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.0, 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" \
|
|
"phase:2,t:none,t:lowercase,t:normalisePath,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>The exec action is executed independently from any disruptive
|
|
actions. External scripts will always be called with no parameters.
|
|
Some transaction information will be placed in environment variables.
|
|
All the usual CGI environment variables will be there. 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" \
|
|
"phase:2,t:none,t:lowercase,t:normalisePath,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> Meta-data</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>phase:1,initcol:ip=%{REMOTE_ADDR}</emphasis>,nolog</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>Normally you will want to use <emphasis>phase:1</emphasis> along
|
|
with <emphasis>initcol</emphasis> so that the collection is available in
|
|
all phases.</para>
|
|
|
|
<para>Collections are loaded into memory when the initcol action is
|
|
encountered. The collection in storage will be persisted (and the
|
|
appropriate counters increased) <emphasis>only</emphasis> if it was
|
|
changed during transaction processing.</para>
|
|
|
|
<para>See the "Persistant Storage" section for further details.</para>
|
|
</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 phase:1,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 a data fragment to be
|
|
logged as part of the alert message.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Non-disruptive</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> Meta-data</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>Example1:</para>
|
|
|
|
<programlisting format="linespecific">SecRule REQUEST_HEADERS:User-Agent "Test" log,<emphasis>pass</emphasis></programlisting>
|
|
|
|
<para>When using <emphasis>pass</emphasis> with SecRule with multiple
|
|
targets, <emphasis>all</emphasis> targets will be processed and
|
|
<emphasis>all</emphasis> non-disruptive actions will trigger for
|
|
<emphasis>every</emphasis> match found. In the second example the
|
|
TX:test target would be incremented by 1 for each matching
|
|
argument.</para>
|
|
|
|
<para>Example2:</para>
|
|
|
|
<programlisting format="linespecific">SecRule ARGS "test" log,<emphasis>pass</emphasis>,setvar:TX.test=+1</programlisting>
|
|
|
|
<para><emphasis>Note</emphasis></para>
|
|
|
|
<para>The transaction will not be interrupted but a log will be
|
|
generated for each matching target (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> Non-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> Meta-data</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>
|
|
|
|
<note>
|
|
<para>While macro expansion is allowed in the additional content, you
|
|
are strongly cautioned against inserting user defined data
|
|
fields.</para>
|
|
</note>
|
|
</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> Meta-data</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> Meta-data</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.0) 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> Flow</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<para><programlisting format="linespecific">SecRule REQUEST_URI "^/$" \
|
|
"phase:2,chain,t:none<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 <literal>SecMarker</literal>) is found.</para>
|
|
|
|
<para><emphasis>Action Group:</emphasis> Flow</para>
|
|
|
|
<para>Example:</para>
|
|
|
|
<para><programlisting format="linespecific">SecRule REQUEST_URI "^/$" "chain,t:none,<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><literal>SkipAfter</literal> 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> Data</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> Meta-data</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" \
|
|
"t:none,t:lowercase,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> Data</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="operators">
|
|
<title>Operators</title>
|
|
|
|
<para>A number of operators can be used in rules, as documented below. The
|
|
operator syntax uses the <literal>@</literal> 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 <literal>%{TX.1}</literal>, 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 in the target data. 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>
|
|
|
|
<note>
|
|
<para>This operator matches and the action is executed on a <emphasis>
|
|
successful</emphasis> lookup. For this reason, you probably want to
|
|
use the <emphasis>pass,nolog</emphasis> actions. This allows for
|
|
<literal moreinfo="none">setvar</literal> and other non-disruptive
|
|
actions to be executed on a match. If you wish to block on a failed
|
|
lookup, then do something like this (look for an empty GEO
|
|
collection):</para>
|
|
|
|
<programlisting format="linespecific">SecGeoLookupDb /usr/local/geo/data/GeoLiteCity.dat
|
|
...
|
|
SecRule REMOTE_ADDR "@geoLookup" "pass,nolog"
|
|
SecRule &GEO "@eq 0" "deny,status:403,msg:'Failed to lookup IP'"</programlisting>
|
|
</note>
|
|
|
|
<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.0, 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.0, 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. The match is case insensitive.</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 ARGS: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> Validates the DOM tree generated
|
|
by the XML request body processor against the supplied DTD.</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>" "deny,id:12345"</programlisting>
|
|
|
|
<note>
|
|
<para>This operator requires request body to be processed as
|
|
XML.</para>
|
|
</note>
|
|
</section>
|
|
|
|
<section>
|
|
<title><literal>validateSchema</literal></title>
|
|
|
|
<para><emphasis>Description:</emphasis> Validates the DOM tree generated
|
|
by the XML request body processor against the supplied XML
|
|
Schema.</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>" "deny,id:12345"</programlisting>
|
|
|
|
<note>
|
|
<para>This operator requires request body to be processed as
|
|
XML.</para>
|
|
</note>
|
|
</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>Macro Expansion</title>
|
|
|
|
<para>Macros allow for using place holders in rules that will be expanded
|
|
out to their values at runtime. Currently only variable expansion is
|
|
supported, however more options may be added in future versions of
|
|
ModSecurity.</para>
|
|
|
|
<para>Format:</para>
|
|
|
|
<programlisting format="linespecific">%{VARIABLE}
|
|
%{COLLECTION.VARIABLE}</programlisting>
|
|
|
|
<para>Macro expansion can be used in actions such as initcol, setsid,
|
|
setuid, setvar, setenv, logdata. Operators that are evaluated at runtime
|
|
support expansion and are noted above. Such operators include @beginsWith,
|
|
@endsWith, @contains, @within and @streq. You cannot use macro expansion
|
|
for operators that are "compiled" such as @pm, @rx, etc. as these
|
|
operators have their values fixed at configure time for efficiency.</para>
|
|
|
|
<para>Some values you may want to expand include: TX, REMOTE_ADDR, USERID,
|
|
HIGHEST_SEVERITY, MATCHED_VAR, MATCHED_VAR_NAME, MULTIPART_STRICT_ERROR,
|
|
RULE, SESSION, USERID, among others.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Persistant Storage</title>
|
|
|
|
<para>At this time it is only possible to have three collections in which
|
|
data is stored persistantly (i.e. data available to multiple requests).
|
|
These are: <literal moreinfo="none">IP</literal>, <literal
|
|
moreinfo="none"> SESSION</literal> and <literal
|
|
moreinfo="none">USER</literal>.</para>
|
|
|
|
<para>Every collection contains several built-in variables that are
|
|
available and are read-only unless otherwise specified:</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). This variable may be set if you wish to specifiy
|
|
an explicit expiration time (default is 3600 seconds).</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>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>. To create a collection to hold client
|
|
address variables (<literal moreinfo="none">IP</literal>) use action
|
|
<literal moreinfo="none">initcol</literal>.</para>
|
|
|
|
<note>
|
|
<para>ModSecurity implements atomic updates of persistent variables only
|
|
for integer variables (counters) 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. Counters are adjusted by
|
|
applying a delta generated by re-reading the persisted data just before
|
|
being persisted. This keeps counter data consistent even if the counter
|
|
was modified and persisted by another thread/process during the
|
|
transaction.</para>
|
|
</note>
|
|
|
|
<note>
|
|
<para>ModSecurity uses a Berkley Database (SDBM) for persistant storage.
|
|
This type of database is generally limited to storing a maximum of 1008
|
|
bytes per key. This may be a limitation if you are attempting to store a
|
|
considerable amount of data in variables for a single key. Some of this
|
|
limitation is planned to be reduced in a future version of
|
|
ModSecurity.</para>
|
|
</note>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Miscellaneous Topics</title>
|
|
|
|
<para></para>
|
|
|
|
<section>
|
|
<title>Impedance Mismatch</title>
|
|
|
|
<para>Web application firewalls 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>
|