ModSecurity configuration directives are added to your configuration
file (typically
)
directly. When it is not always certain whether module will be enabled or
disabled on web server start it is customary to enclose its configuration
directives in a <httpd.conf
IfModule
> container tag. This
allows Apache to ignore the configuration directives when the module is
not active.
<IfModule mod_security.c> # mod_security configuration directives # ... </IfModule>
Since Apache allows configuration data to exist in more than one
file it is possible to group ModSecurity configuration directives in a
single file (e.g.
) and include it
from modsecurity.conf
with the Include
directive:httpd.conf
Include conf/modsecurity.conf
The filtering engine is disabled by default. To start monitoring requests add the following to your configuration file:
SecFilterEngine On
Supported parameter values for this parameter are:
On
– analyse every request
Off
– do nothing
DynamicOnly
– analyse only requests
generated dynamically at runtime. Using this option will prevent
your web server from using the precious CPU cycles to check requests
for static files. To understand how ModSecurity decides what is a
dynamically generated request read the section "Choosing what to log".
Request body payload (or POST payload) scanning is disabled by default. To use it, you need to turn it on:
SecFilterScanPOST On
mod_security supports two encoding types for the request body:
application/x-www-form-urlencoded
- used to
transfer form data
multipart/form-data
– used for file
transfers
Other encodings are not used by most web applications. To make sure that only requests with these two encoding types are accepted by the web server, add the following line to your configuration file:
SecFilterSelective HTTP_Content-Type \ "!(^$|^application/x-www-form-urlencoded$|^multipart/form-data;)"
It is possible to turn POST
payload scanning
off on per-request basis. If ModSecurity sees that an environment
variable MODSEC_NOPOSTBUFFERING
is defined it will
not perform POST
payload buffering. For example, to
turn POST
payload buffering off for file uploads use
the following:
SetEnvIfNoCase Content-Type \ "^multipart/form-data;" "MODSEC_NOPOSTBUFFERING=Do not buffer file uploads"
The value assigned to the
MODSEC_NOPOSTBUFFERING
variable will be written to
the debug log, so you can put in there something that will tell you why
was buffering turned off.
It is also possible to enable or disable ModSecurity on the
per-request basis. This is done via the MODSEC_ENABLE
environment variable, in combination with the
SetEnvIf
and SetEnvIfNoCase
directives. If MODSEC_ENABLE
is not set the
configuration specified with SecFilterEngine will be used. If
MODSEC_ENABLE
is set the value of
SecFilterEngine
will be ignored. To values for
MODSEC_ENABLE
are the same as for the
SecFilterEngine
directive: On
,
Off
, or DynamicOnly
.
The HTTP
protocol supports a method of request
transfer where the size of the payload is not known in advance. The body
of the request is delivered in chunks. Hence the name chunked transfer
encoding. ModSecurity does not support chunked requests at this time;
when a request is made with chunked encoding it will ignore the body of
the request. As far as I am aware no browser uses chunked encoding to
send requests. Although Apache does support this encoding for some
operations most modules (e.g. the PHP module with Apache 1.3.x)
don't.
Left unattended this may present an opportunity for an attacker to sneak malicious payload. Add the following line to your configuration to prevent attackers to exploit this weakness:
SecFilterSelective HTTP_Transfer-Encoding "!^$"
This will not affect your ability to send responses using the chunked transfer encoding.
Whenever a rule is matched against a request, one or more actions
are performed. Individual filters can each have their own actions but it
is easier to define a default set of actions for all filters. (You can
always have per-rule actions if you want.) You define default actions
with the configuration directive
SecFilterDefaultAction
. For example, the following
will configure the engine to log each rule match, and reject the request
with status code 404:
SecFilterDefaultAction "deny,log,status:404"
The SecFilterDefaultAction
directive accepts
only one parameter, a comma-separated list of actions separated. The
actions you specify here will be performed on every filter match, except
for rules that have their own action lists.
As of 1.8.6, if you specify a non-fatal default action list (a
list that will not cause the request to be rejected, for example
log,pass
) such action list will be ignored during
the initialisation phase. The initialisation phase is designed to
gather information about the request. Allowing non-fatal actions would
cause some pieces of the request to be missing. Since this information
is required for internal processing such actions cannot be allowed. If
you want ModSecurity to operate in a "detect-only" mode you need to
disable all implicit validations (URL encoding validation, Unicode
encoding validation, cookie format validation, and byte range
restrictions).
Some actions cannot appear in the default list. These are:
id
, rev
,
skipnext
, chain
,
chained
.
As of 1.8.6 implicit request validation (if configured) will be performed only at the beginning of request processing. Implicit validation consists of the checks of the request line, and the headers.
As of 1.9dev4 Unicode encoding validation is not applied to the
contents of the Referer
header when part of the
initial implicit request validation. This is because this header often
contains information from other web sites, and their encoding usually
differs from the encoding used on the protected web site.
Filters defined in parent folders are normally inherited by nested
Apache configuration contexts. This is behaviour is acceptable (and
required) in most cases, but not all the time. Sometimes you need to
relax checks in some part of the site. By using the
SecFilterInheritance
directive:
SecFilterInheritance Off
you can instruct ModSecurity to disregard parent filters so that you can start with rules from the scratch. This directive affects rules only. The configuration is always inherited from the parent context but you can override it as you are pleased using the appropriate configuration directives.
Configuration and rule inheritance is always enabled by default. If you have a configuration context beneath one that has had inheritance disabled you will have to explicitly disable inheritance again if that is what you need.
When you choose not to inherit the rules from the parent context you can either write new rules for the new context, or simply use the Include directive to include the same rules into many different contexts.
Sometimes only a small change to the rule set is required in the child context. In such cases you may choose to use the selective inheritance option. You can do this with the help of the following two directives:
SecFilterImport
– import a single rule from
the parent context. This directive is useful when you want to start
from scratch in the child context and only import selected rules
from the parent context.
SecFilterRemove
– remove a rule from the
current context. This directive is useful when you want to start
with the same rule set as in the parent context, removing selected
rules only.
The SecFilterImport
and
SecFilterRemove
directives both accept a list rule
IDs. The target rules must have IDs associated with them (this is done
using the id action). The directives will be executed in the order they
appear in the configuration file. Therefore, it is possible to remove a
rule with SecFilterRemove
and then add it again with
SecFilterImport
. Below you can find two examples that
arrive at the same rule configuration, but take different routes to get
there.
If a target rule ID refers to a rule that is part of a chain, the import and remove directives will affect the whole chain, and not only the rule the ID refers to.
Example 1: the rules from the parent context are not inherited, but a single rule is imported.
SecFilter XXX id:1001 SecFilter YYY id:1002 SecFilter ZZZ id:1003 <Location /subcontext/> SecFilterInheritance Off SecFilterImport 1003 </Location>
Example 2: the rules from the parent context are inherited, with two rules removed.
SecFilter XXX id:1001 SecFilter YYY id:1002 SecFilter ZZZ id:1003 <Location /subcontext/> SecFilterRemove 1001 1002 </Location>
The Apache web server supports many different types of context
(e.g. <Directory>
,
<Location>
, <Files>
,
...). The order in which contexts are merged is significant. You
should try not to mix inheritance and different-type contexts. If you
have to, make sure you test the configuration to make sure it works as
intended, and read the Apache context merging documentation carefully:
http://httpd.apache.org/docs-2.0/sections.html#mergin.
When you are deploying ModSecurity in multi-user environments, and
your users are allowed to use the rules in their
.htaccess
files, you may not wish to allow them to
not inherit the rules from the parent context. There are two ways to
achieve this.
If you do not trust your users (e.g. running in a web hosting
environment) then you should never allow them access to ModSecurity.
The .htaccess
facility is useful for limited
administration control decentralisation, keeping ModSecurity
configuration with the application code. But it is not meant to be
used in situations when the users may want to subvert the
configuration. If you are running a hostile environment you should
turn off the .htaccess
facility completely by
custom-compiling ModSecurity with the
-DDISABLE_HTACCESS_CONFIG
switch.
First, you can mark certain rules mandatory using the mandatory action. Such rules will always be inherited in the child context.
The other way is to use the
SecFilterInheritanceMandatory
directive to simply
make all rules in the context mandatory for all child contexts.
SecFilterInheritanceMandatory On
Just like SecFilterInheritance
is always
enabled in a context, SecFilterInheritanceMandatory
is always disabled in a context, no matter of the value used in the
parent context.
You may be wondering what happens in a situation like this one:
SecFilter XXX id:1001 SecFilterInheritanceMandatory On <Location /subcontext/> SecFilterInheritance Off SecFilter YYY id:1002 SecFilter ZZZ id:1003,mandatory </Location> <Location /subcontext/another/> SecFilterRemove 1001 1002 1003 SecFilter QQQ id:1004 </Location>
Since rule inheritance is mandatory in the main context, the
/
context will inherit
rule 1001 in spite of an attempt not to (using
subcontext
/SecFilterInheritance Off
). This subcontext will first
run rule 1001, followed by the rules 1002 and 1003.
The mandatory rule 1001 from the main context will also propagate
to context /subcontext/another/
, in spite of an
attempt to remove it. This is also true for the rule 1003, which was
made mandatory for inheritance using the mandatory action. The
SecFilterRemove
1001 1002 1003 directive will,
however, succeed in removing rule 1002 because inheritance was not
mandatory in /subcontext/
. This context will
therefore first run rule 1001 and 1003, followed by the rule
1004.
You should avoid importing and removing rules that makes use of
the skip
action. Unless you are very careful you
may end up with a configuration that does something other than what
you intended.
Special characters need to be encoded before they can be
transmitted in the URL. Any character can be replaced using the three
character combination %XY
, where XY represents an
hexadecimal character code (see http://www.rfc-editor.org/rfc/rfc1738.txt
for more details). Hexadecimal numbers only allow letters A to F, but
attackers sometimes use other letters in order to trick the decoding
algorithm. ModSecurity checks all supplied encodings in order to verify
they are valid.
You can turn URL encoding validation on with the following line:
SecFilterCheckURLEncoding On
This directive does not check encoding in a
POST
payload when the
multipart/form-data
encoding (file upload) is used.
It is not necessary to do so because URL encoding is not used for this
encoding.
Like many other features Unicode encoding validation is disabled by default. You should turn it on if your application or the underlying operating system accept/understand Unicode.
More information on Unicode and UTF-8 encoding can be found in RFC 2279 (http://www.ietf.org/rfc/rfc2279.txt).
SecFilterCheckUnicodeEncoding On
This feature will assume UTF-8 encoding and check for three types of errors:
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.
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.
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).
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). To only allow bytes from 32 to 126 (inclusive), use the following directive:
SecFilterForceByteRange 32 126
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
multipart/form-data
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.
Prior to 1.9 ModSecurity supported the
SecServerResponseToken
directive. When used, this
directive exposed the presence of the module (with the version) in the
web server signature. This directive no longer works in 1.9. If used, it
will emit a warning message to the error log.