mod_unique_id
installed.
mod_unique_id is packaged with Apache httpd.
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.
http://curl.haxx.se/libcurl/
The following few pages will give you more information on benefits of choosing one method over another.
If you want to access the latest version of the module you need to get it from the svn repository. The list of changes made since the last stable release is normally available on the web site (and in the file CHANGES). The SVN repository for ModSecurity is hosted by SourceForge (http://www.sf.net). You can access it directly or view if through web using this address: http://mod-security.svn.sourceforge.net/viewvc/mod-security/
To download the lastest TRUNK source code to your computer you need to execute the following command:
git
$git svn clone --prefix=svn/ https://mod-security.svn.sourceforge.net/svnroot/mod-security/m2/trunksvn
svn co https://mod-security.svn.sourceforge.net/svnroot/mod-security/m2/trunk modsecurity
For v2.6.0 and above, the installation process has changed. Follow these steps:
$cd modsecurity
$./autogen.sh
$./configure
$make
$make install
$cp /usr/local/modsecurity/lib/mod_security2.so /usr/local/apache/modules/
./configureOptions are available for more customization (use ./configure --help for a full list), but typically you will only need to specify the location of the apxs command installed by Apache httpd with the --with-apxs option.
./configure --with-apxs=/path/to/httpd-2.x.y/bin/apxs
makeOptionally test with:
make CFLAGS=-DMSC_TEST test
make mlogcOptionally install mlogc: Review the INSTALL file included in the apache2/mlogc-src directory in the distribution. Install the ModSecurity module with:
make install
nmake -f Makefile.win
Install the ModSecurity module with: nmake -f Makefile.win install
Copy the libxml2.dll and lua5.1.dll to the Apache bin directory. Alternatively you can follow the step below for using LoadFile to load these libraries.
LoadFile /usr/lib/libxml2.so LoadFile /usr/lib/liblua5.1.soLoad the ModSecurity module with:
LoadModule security2_module modules/mod_security2.so
~/mod_security$ ./configure --enable-standalone-module ~/mod_security$ make
2 - Once the standalone library is built successfully, one can follow with building the nginx server, following the steps from the nginx build tutorial:
~/nginx-1.2.0$ ./configure --add-module=../mod_security/nginx/modsecurity ~/nginx-1.2.0$ make ~/nginx-1.2.0$ sudo make installThe last command performs server installation on the local machine, which can be either customized or omitted with built binaries packaged or moved to alternative server.
appcmd.exe install module /name:ModSecurityIIS /image:%windir%\system32\inetsrv\modsecurityiis.dll
iisschema.exe /install ModSecurity.xml
<modules> <remove name="ModSecurityIIS" /> </modules>
<?xml version="1.0" encoding="UTF-8"?> <configuration> <system.webServer> <ModSecurity enabled="true" configFile="c:\inetpub\wwwroot\xss.conf" /> </system.webserver> </configuration>
Log Name: Application Source: Microsoft-Windows-IIS-W3SVC-WP Event ID: 2280 Task Category: None Level: Error Keywords: Classic User: N/A Description: The Module DLL C:\Windows\system32\inetsrv\modsecurityiis.dll failed to load. The data is the error.
most likely it means that the installation process has failed and the ModSecurityIIS.dll module is missing one or more libraries that it depends on. Repeating installation of the prerequisites and the module files should fix the problem. The dependency walker tool:
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 - modsecurity_crs_15_customrules.conf 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.
SecRule
.
Syntax: SecAction "action1,action2,action3,...“
Scope: Any
Version: 2.0.0
This directive is commonly used to set variables and initialize persistent collections using the initcol action. For example:
SecAction nolog,phase:1,initcol:RESOURCE=%{REQUEST_FILENAME}
Syntax: SecArgumentSeparator character
Default: &
Scope: Main(
Version: 2.0.0
This directive is needed if a backend web application is using a nonstandard argument separator. Applications are sometimes (very rarely) written to use a semicolon separator. You should not change the default setting unless you establish that the application you are working with requires a different 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.
Syntax: SecAuditEngine RelevantOnly
Default: Off
Scope: Any
Version: 2.0.0
The SecAuditEngine directive is used to configure the audit engine, which logs complete transactions. ModSecurity is currently able to log most, but not all transactions. Transactions involving errors (e.g., 400 and 404 transactions) use a different execution path, which ModSecurity does not support.
The possible values for the audit log engine are as follows:
SecAuditEngine RelevantOnly SecAuditLog logs/audit/audit.log SecAuditLogParts ABCFHZ SecAuditLogType concurrent SecAuditLogStorageDir logs/audit SecAuditLogRelevantStatus ^(?:5|4(?!04))
Syntax: SecAuditLog /path/to/audit.log
Scope: Any Version: 2.0.0
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 to send your audit log data off to a remote server you will need to deploy the ModSecurity Log Collector (mlogc), like this:
SecAuditLog "|/path/to/mlogc /path/to/mlogc.conf"
Syntax: SecAuditLog2 /path/to/audit.log
Scope: Any
Version: 2.1.2
The purpose of SecAuditLog2 is to make logging to two remote servers possible, which is typically achieved by running two instances of the mlogc tool, each with a different configuration (in addition, one of the instances will need to be instructed not to delete the files it submits). This directive can be used only if SecAuditLog was previously configured and only if concurrent logging format is used.
Syntax: SecAuditLogDirMode octal_mode|"default"
Default: 0600
Scope: Any
Version: 2.5.10
The default mode for new audit log directories (0600) only grants read/write access to the owner (typically the account under which Apache is running, for example apache). If access from other accounts is needed (e.g., for use with mpm-itk), then you may use this directive to grant additional read and/or write privileges. You should use this directive with caution to avoid exposing potentially sensitive data to unauthorized users. Using the value default as parameter reverts the configuration back to the default setting. This feature is not available on operating systems not supporting octal file modes.
Example:
SecAuditLogDirMode 02750
Syntax: SecAuditLogFileMode octal_mode|"default"
Default: 0600
Scope: Any
Version: 2.5.10
Example Usage: SecAuditLogFileMode 00640
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.
Syntax: SecAuditLogParts PARTLETTERS
Example Usage: SecAuditLogParts ABCFHZ
Scope: Any Version: 2.0.0
Default: ABCFHZ Note
The format of the audit log format is documented in detail in the Audit Log Data Format Documentation.
Available audit log parts:
Syntax: SecAuditLogRelevantStatus REGEX
Example Usage: SecAuditLogRelevantStatus "^(?:5|4(?!04))"
Scope: Any
Version: 2.0.0
Dependencies/Notes: Must have SecAuditEngine set to RelevantOnly.
The main purpose of this directive is to allow you to configure audit logging for only the transactions that have the status code that matches the supplied regular expression. The example provided would log all 5xx and 4xx level status codes, except for 404s. Although you could achieve the same effect with a rule in phase 5, SecAuditLogRelevantStatus is sometimes better, because it continues to work even when SecRuleEngine is disabled.
Syntax: SecAuditLogStorageDir /path/to/storage/dir
Example Usage: SecAuditLogStorageDir /usr/local/apache/logs/audit
Scope: Any
Version: 2.0.0
This directive is only needed when concurrent audit logging is used. The directory must already exist and must be writable by the web server user. Audit log entries are created at runtime, after Apache switches to a non-root account. As with all logging mechanisms, ensure that you specify a file system location that has adequate disk space and is not on the main system partition.
Syntax: SecAuditLogType Serial|Concurrent
Example Usage: SecAuditLogType Serial
Scope: Any
Version: 2.0.0
The possible values are:
Syntax: SecCacheTransformations On|Off [options]
Example Usage: SecCacheTransformations On "minlen:64,maxlen:0"
Scope: Any
Version: 2.5.0; deprecated in 2.5.6.
The first directive parameter can be one of the following:
Syntax: SecChrootDir /path/to/chroot/dir
Example Usage: SecChrootDir /chroot
Scope: Main
Version: 2.0.0
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 only static files, or running applications using built-in modules. Some problems you might encounter with more complex setups:
Syntax: SecComponentSignature "COMPONENT_NAME/X.Y.Z (COMMENT)"
Example usage: SecComponentSignature "core ruleset/2.1.3"
Scope: Main
Version: 2.5.0
This directive should be used to make the presence of significant rule sets known. The entire signature will be recorded in the transaction audit log.
Syntax: SecContentInjection On|Off
Example Usage: SecContentInjection On
Scope: Any
Version: 2.5.0
This directive provides an easy way to control content injection, no matter what the rules want to do. It is not necessary to have response body buffering enabled in order to use content injection.
Syntax: SecCookieFormat 0|1
Example Usage: SecCookieFormat 0
Scope: Any
Version: 2.0.0
The possible values are:
Syntax: SecDataDir /path/to/dir
Example Usage: SecDataDir /usr/local/apache/logs/data
Scope: Main
Version: 2.0.0
This directive must be provided before initcol, setsid, and setuid can be used. The directory to which the directive points must be writable by the web server user.
Syntax: SecDebugLog /path/to/modsec-debug.log
Example Usage: SecDebugLog /usr/local/apache/logs/modsec-debug.log
Scope: Any
Version: 2.0.0
Syntax: SecDebugLogLevel 0|1|2|3|4|5|6|7|8|9
Example Usage: SecDebugLogLevel 4
Scope: Any
Version: 2.0.0
Messages at levels 1–3 are always copied to the Apache error log. Therefore you can always use level 0 as the default logging level in production if you are very concerned with performance. Having said that, the best value to use is 3. Higher logging levels are not recommended in production, because the heavy logging affects performance adversely.
The possible values for the debug log level are:
Syntax: SecDefaultAction "action1,action2,action3“
Example Usage: SecDefaultAction "phase:2,log,auditlog,deny,status:403“
Scope: Any
Version: 2.0.0
Default: phase:2,log,auditlog,pass
Every rule following a previous SecDefaultAction
directive in the same configuration context will inherit its settings unless more specific actions are used. Every SecDefaultAction
directive must specify a disruptive action and a processing phase and cannot contain metadata actions.
SecDefaultAction
is not inherited across configuration contexts. (For an example of why this may be a problem, read the following ModSecurity Blog entry http://blog.spiderlabs.com/2008/07/three-modsecurity-rule-language-annoyances.html.)
Syntax: SecDisableBackendCompression On|Off
Scope: Any
Version: 2.6.0
Default: Off
This directive is necessary in reverse proxy mode when the backend servers support response compression, but you wish to inspect response bodies. Unless you disable backend compression, ModSecurity will only see compressed content, which is not very useful. This directive is not necessary in embedded mode, because ModSecurity performs inspection before response compression takes place.
Syntax: SecHashEngine On|Off
Example Usage: SecHashEngine On
Scope: Any
Version: 2.7.1
Default: Off
The possible values are:
Syntax: SecHashKey rand|TEXT KeyOnly|SessionID|RemoteIP
Example Usage: SecHashKey "this_is_my_key" KeyOnly
Scope: Any
Version: 2.7.1
ModSecurity hash engine will append, if specified, the user's session id or remote ip to the key before the MAC operation. If the first parameter is "rand" then a random key will be generated and used by the engine.
Syntax: SecHashParam TEXT
Example Usage: SecHashKey "hmac"
Scope: Any
Version: 2.7.1
ModSecurity hash engine will add a new parameter to protected HTML elements containing the MAC hash.
Syntax: SecHashMethodRx TYPE REGEX
Example Usage: SecHashMethodRx HashHref "product_info|list_product"
Scope: Any
Version: 2.7.1
As a initial support is possible to protect HREF, FRAME, IFRAME and FORM ACTION html elements as well response Location header when http redirect code are sent.
The possible values for TYPE are:
Syntax: SecHashMethodRx TYPE "string1 string2 string3..."
Example Usage: SecHashMethodRx HashHref "product_info list_product"
Scope: Any
Version: 2.7.1
As a initial support is possible to protect HREF, FRAME, IFRAME and FORM ACTION html elements as well response Location header when http redirect code are sent.
The possible values for TYPE are:
Syntax: SecGeoLookupDb /path/to/db
Example Usage: SecGeoLookupDb /path/to/GeoLiteCity.dat
Scope: Any
Version: 2.5.0
ModSecurity relies on the free geolocation databases (GeoLite City and GeoLite Country) that can be obtained from MaxMind http://www.maxmind.com.
Syntax: SecGsbLookupDb /path/to/db
Example Usage: SecGsbLookupDb /path/to/GsbMalware.dat
Scope: Any
Version: 2.6.0
ModSecurity relies on the free Google Safe Browsing database that can be obtained from the Google GSB API http://code.google.com/apis/safebrowsing/.
wget http://sb.google.com/safebrowsing/update?client=api&apikey=KEY&version=goog-malware-hash:1:-1
Syntax: SecGuardianLog |/path/to/httpd-guardian
Example Usage: SecGuardianLog |/usr/local/apache/bin/httpd-guardian
Scope: Main
Version: 2.0.0
Guardian logging is designed to send the information about every request to an external program. Because Apache is typically deployed in a multiprocess fashion, which makes information sharing between processes difficult, the idea is to deploy a single external process to observe all requests in a stateful manner, providing additional protection.
Currently the only tool known to work with guardian logging is httpd-guardian, which is part of the Apache httpd tools project http://apache-tools.cvs.sourceforge.net/viewvc/apache-tools/apache-tools/. The httpd-guardian tool is designed to defend against denial of service attacks. It uses the blacklist tool (from the same project) to interact with an iptables-based (on a Linux system) or pf-based (on a BSD system) 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:
SecGuardianLog |/path/to/httpd-guardian
Syntax: SecHttpBlKey [12 char access key]
Example Usage: SecHttpBlKey whdkfieyhtnf
Scope: Main
Version: 2.7.0
If the @rbl operator uses the dnsbl.httpbl.org RBL (http://www.projecthoneypot.org/httpbl_api.php) you must provide an API key. This key is registered to individual users and is included within the RBL DNS requests.
Syntax: SecInterceptOnError On|Off
Example Usage: SecInterceptOnError On
Scope: Main
Version: 2.6
When an operator execution fails (ie returns
Syntax: SecMarker ID|TEXT
Example Usage: SecMarker 9999
Scope: Any
Version: 2.5.0
The value can be either a number or a text string. The SecMarker directive is available to allow you to choose the best way to implement a skip-over. Here is an example used from the Core Rule Set:
SecMarker BEGIN_HOST_CHECK SecRule &REQUEST_HEADERS:Host "@eq 0" \ "skipAfter:END_HOST_CHECK,phase:2,rev:'2.1.1',t:none,block,msg:'Request Missing a Host Header',id:'960008',tag:'PROTOCOL_VIOLATION/MISSING_HEADER_HOST',tag:'WASCTC/WASC-21',tag:'OWASP_TOP_10/A7',tag:'PCI/6.5.10',severity:'5',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},setvar:tx.protocol_violation_score=+%{tx.notice_anomaly_score},setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/MISSING_HEADER-%{matched_var_name}=%{matched_var}" SecRule REQUEST_HEADERS:Host "^$" \ "phase:2,rev:'2.1.1',t:none,block,msg:'Request Missing a Host Header',id:'960008',tag:'PROTOCOL_VIOLATION/MISSING_HEADER_HOST',tag:'WASCTC/WASC-21',tag:'OWASP_TOP_10/A7',tag:'PCI/6.5.10',severity:'5',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},setvar:tx.protocol_violation_score=+%{tx.notice_anomaly_score},setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/MISSING_HEADER-%{matched_var_name}=%{matched_var}" SecMarker END_HOST_CHECK
Syntax: SecPcreMatchLimit value
Example Usage: SecPcreMatchLimit 1500
Scope: Main
Version: 2.5.12
Default: 1500
The default can be changed when ModSecurity is prepared for compilation: the --enable-pcre-match-limit=val configure option will set a custom default and the --disable-pcre-match-limit option will revert back to the default of the PCRE library. For more information, refer to the pcre_extra field in the pcreapi man page.
Syntax: SecPcreMatchLimitRecursion value
Example Usage: SecPcreMatchLimitRecursion 1500
Scope: Main
Version: 2.5.12
Default: 1500
The default can be changed when ModSecurity is prepared for compilation: the --enable-pcre-match-limit-recursion=val configure option will set a custom default and the --disable-pcre-match-limit-recursion option will revert back to the default of the PCRE library. For more information, refer to the pcre_extra field in the pcreapi man page.
Syntax: SecPdfProtect On|Off
Example Usage: SecPdfProtect On
Scope: Any
Version: 2.5.0; removed from trunk
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 .pdf extension in the request URI.
Syntax: SecPdfProtectMethod method
Example Usage: SecPdfProtectMethod TokenRedirection
Scope: Any
Version: 2.5.0; removed from trunk
Default: TokenRedirection
Possible values are TokenRedirection and ForcedDownload. The token redirection approach will attempt to redirect with tokens where possible. This allows PDF files to continue to be opened inline but works only 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!”).
Syntax: SecPdfProtectSecret secret
Example Usage: SecPdfProtectSecret MyRandomSecretString
Scope: Any
Version: 2.5.0; removed from trunk
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.
Syntax: SecPdfProtectTimeout timeout
Example Usage: SecPdfProtectTimeout 10
Scope: Any
Version: 2.5.0; removed from trunk
Default: 10
After token expires, it can no longer be used to allow access to a PDF file. Request will be allowed through but the PDF will be delivered as an attachment.
Syntax: SecPdfProtectTokenName name
Example Usage: SecPdfProtectTokenName PDFTOKEN
Scope: Any
Version: 2.5.0; removed from trunk
Default: PDFTOKEN
The only reason you would want to change the name of the token is if you wanted to hide the fact that 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.
Syntax: SecReadStateLimit LIMIT
Example Usage: SecReadStateLimit 50
Scope: Main
Version: 2.5.13
Default: 0 (no limit)
This measure is effective against Slowloris-style attacks from a single IP address, but it may not be as good against modified attacks that work by slowly sending request body content. This is because Apache to switches state to SERVER_BUSY_WRITE once request headers have been read. As an alternative, consider mod_reqtimeout (part of Apache as of 2.2.15), which is expected be effective against both attack types. See Blog post on mitigating slow DoS attacks - http://blog.spiderlabs.com/2010/11/advanced-topic-of-the-week-mitigating-slow-http-dos-attacks.html
Syntax: SecSensorId TEXT
Example Usage: SecSensorId WAFSensor01
Scope: Main
Version: 2.7.0
Syntax: SecWriteStateLimit LIMIT
Example Usage: SecWriteStateLimit 50
Scope: Main
Version: 2.6.0
Default: 0 (no limit)
This measure is effective against Slow DoS request body attacks.
Syntax: SecRequestBodyAccess On|Off
Example Usage: SecRequestBodyAccess On
Scope: Any
Version: 2.0.0
This directive is required if you want to inspect the data transported request bodies (e.g., POST parameters). Request buffering is also required in order to make reliable blocking possible. The possible values are:
Syntax: SecRequestBodyInMemoryLimit LIMIT_IN_BYTES
Example Usage: SecRequestBodyInMemoryLimit 131072
Scope: Any
Version: 2.0.0
Default: 131072 (128 KB)
When a multipart/form-data request is being processed, once the in-memory limit is reached, the request body will start to be streamed into a temporary file on disk.
Syntax: SecRequestBodyLimit LIMIT_IN_BYTES
Example Usage: SecRequestBodyLimit 134217728
Scope: Any
Version: 2.0.0
Default: 134217728 (131072 KB)
Anything over the limit will be rejected with status code 413 (Request Entity Too Large). There is a hard limit of 1 GB.
Syntax: SecRequestBodyNoFilesLimit NUMBER_IN_BYTES
Example Usage: SecRequestBodyLimit 131072
Scope: Any
Version: 2.5.0
Default: 1048576 (1 MB)
Generally speaking, the default value is not small enough. 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 413 (Request Entity Too Large). There is a hard limit of 1 GB.
Syntax: SecRequestBodyLimitAction Reject|ProcessPartial
Example Usage: SecRequestBodyLimitAction ProcessPartial
Scope: Any
Version: 2.6.0
By default, ModSecurity will reject a request body that is longer than specified. This is problematic especially when ModSecurity is being run in DetectionOnly mode and the intent is to be totally passive and not take any disruptive actions against the transaction. With the ability to choose what happens once a limit is reached, site administrators can choose to inspect only the first part of the request, the part that can fit into the desired limit, and let the rest through. This is not ideal from a possible evasion issue perspective, however it may be acceptable under certain circumstances.
Syntax: SecResponseBodyLimit LIMIT_IN_BYTES
Example Usage: SecResponseBodyLimit 524228
Scope: Any
Version: 2.0.0
Default: 524288 (512 KB)
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 selected for buffering. There is a hard limit of 1 GB.
Syntax: SecResponseBodyLimitAction Reject|ProcessPartial
Example Usage: SecResponseBodyLimitAction ProcessPartial
Scope: Any
Version: 2.5.0
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 applies only to cases in which 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.
Syntax: SecResponseBodyMimeType MIMETYPE MIMETYPE ...
Example Usage: SecResponseBodyMimeType text/plain text/html text/xml
Scope: Any
Version: 2.0.0
Default: text/plain text/html
Multiple SecResponseBodyMimeType directives can be used to add MIME types. Use SecResponseBodyMimeTypesClear to clear previously configured MIME types and start over.
Syntax: SecResponseBodyMimeTypesClear
Example Usage: SecResponseBodyMimeTypesClear
Scope: Any
Version: 2.0.0
Syntax: SecResponseBodyAccess On|Off
Example Usage: SecResponseBodyAccess On
Scope: Any
Version: 2.0.0
Default: Off
This directive is required if you plan to inspect HTML responses and implement response blocking. Possible values are:
Syntax: SecRule VARIABLES OPERATOR [ACTIONS]
Example Usage: SecRule ARGS "@rx attack" "phase:1,log,deny,id:1"
Scope: Any
Version: 2.0.0
Every rule must provide one or more variables along with the operator that should be used to inspect them. If no actions are provided, the default list will be used. (There is always a default list, even if one was not explicitly set with SecDefaultAction.) If there are actions specified in a rule, they will be merged with the default list to form the final actions that will be used. (The actions in the rule will overwrite those in the default list.) Refer to SecDefaultAction for more information.
Syntax: SecRuleInheritance On|Off
Example Usage: SecRuleInheritance Off
Scope: Any
Version: 2.0.0
Default: On
Sometimes when you create a more specific configuration context (for example using the container), you may wish to use a different set of rules than those used in the parent context. By setting SecRuleInheritance to Off, you prevent the parent rules to be inherited, which allows you to start from scratch. In ModSecurity 2.5.x it is not possible to override phase 1 rules from a configuration context. There are no limitations in that respect in the current development version (and there won’t be in the next major version).
The possible values are:
Syntax: SecRuleEngine On|Off|DetectionOnly
Example Usage: SecRuleEngine On
Scope: Any
Version: 2.0.0
Default: Off
The possible values are:
Syntax: SecRulePerfTime USECS
Example Usage: SecRulePerfTime 1000
Scope: Any
Version: 2.7
Syntax: SecRuleRemoveById ID ID RANGE ...
Example Usage: SecRuleRemoveByID 1 2 "9000-9010"
Scope: Any
Version: 2.0.0
This directive supports multiple parameters, each of which can be a rule ID or a range. Parameters that contain spaces must be delimited using double quotes.
Syntax: SecRuleRemoveByMsg REGEX
Example Usage: SecRuleRemoveByMsg "FAIL"
Scope: Any
Version: 2.0.0
Normally, you would use SecRuleRemoveById to remove rules, but that requires the rules to have IDs defined. If they don’t, then you can remove them with SecRuleRemoveByMsg, which matches a regular expression against rule messages.
Syntax: SecRuleRemoveByTab REGEX
Example Usage: SecRuleRemoveByTag "WEB_ATTACK/XSS"
Scope: Any
Version: 2.6
Normally, you would use SecRuleRemoveById to remove rules, but that requires the rules to have IDs defined. If they don’t, then you can remove them with SecRuleRemoveByTag, which matches a regular expression against rule tag data. This is useful if you want to disable entire groups of rules based on tag data. Example tags used in the OWASP ModSecurity CRS include:
Syntax: SecRuleScript /path/to/script.lua [ACTIONS]
Example Usage: SecRuleScript "/path/to/file.lua" "block"
Scope: Any
Version: 2.5.0
-- Your script must define the main 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 must contain the name -- of the variable where the problem is located. -- return "Variable ARGS:p looks suspicious!" -- Otherwise, simply return nil. return nil; end
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.
Example showing use of m.getvars() to retrieve many variables at once:
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
Syntax: SecRuleUpdateActionById RULEID[:offset] ACTIONLIST
Example Usage: SecRuleUpdateActionById 12345 "deny,status:403"
Scope: Any
Version: 2.6.0
This directive will overwrite the action list of the specified rule with the actions provided in the second parameter. It has two limitations: it cannot be used to change the ID or phase of a rule. Only the actions that can appear only once are overwritten. The actions that are allowed to appear multiple times in a list, will be appended to the end of the list.
SecRule ARGS attack "phase:2,id:12345,t:lowercase,log,pass,msg:'Message text'" SecRuleUpdateActionById 12345 "t:none,t:compressWhitespace,deny,status:403,msg:'New message text'"The effective resulting rule in the previous example will be as follows:
SecRule ARGS attack "phase:2,id:12345,t:lowercase,t:none,t:compressWhitespace,deny,status:403,msg:'New Message text'"The addition of t:none will neutralize any previous transformation functions specified (t:lowercase, in the example).
Syntax: SecRuleUpdateTargetById RULEID TARGET1[,TARGET2,TARGET3] REPLACED_TARGET
Example Usage: SecRuleUpdateTargetById 12345 "!ARGS:foo"
Scope: Any
Version: 2.6
This directive will append (or replace) variables to the current target list of the specified rule with the targets provided in the second parameter. Starting with 2.7.0 this feature supports id range.
Explicitly Appending Targets
This is useful for implementing exceptions where you want to externally update a target list to exclude inspection of specific variable(s).
SecRule REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/* "[\;\|\`]\W*?\bmail\b" \ "phase:2,rev:'2.1.1',capture,t:none,t:htmlEntityDecode,t:compressWhitespace,t:lowercase,ctl:auditLogParts=+E,block,msg:'System Command Injection',id:'958895',tag:'WEB_ATTACK/COMMAND_INJECTION',tag:'WASCTC/WASC-31',tag:'OWASP_TOP_10/A1',tag:'PCI/6.5.2',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.command_injection_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=% {tx.0}" SecRuleUpdateTargetById 958895 !ARGS:email
The effective resulting rule in the previous example will append the target to the end of the variable list as follows:
SecRule REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/*|!ARGS:email "[\;\|\`]\W*?\bmail\b" \ "phase:2,rev:'2.1.1',capture,t:none,t:htmlEntityDecode,t:compressWhitespace,t:lowercase,ctl:auditLogParts=+E,block,msg:'System Command Injection',id:'958895',tag:'WEB_ATTACK/COMMAND_INJECTION',tag:'WASCTC/WASC-31',tag:'OWASP_TOP_10/A1',tag:'PCI/6.5.2',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.command_injection_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=% {tx.0}""Explicitly Replacing Targets
You can also entirely replace the target list to something more appropriate for your environment. For example, lets say you want to inspect REQUEST_URI instead of REQUEST_FILENAME, you could do this:
SecRule REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/* "[\;\|\`]\W*?\bmail\b" \ "phase:2,rev:'2.1.1',capture,t:none,t:htmlEntityDecode,t:compressWhitespace,t:lowercase,ctl:auditLogParts=+E,block,msg:'System Command Injection',id:'958895',tag:'WEB_ATTACK/COMMAND_INJECTION',tag:'WASCTC/WASC-31',tag:'OWASP_TOP_10/A1',tag:'PCI/6.5.2',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.command_injection_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=% {tx.0}" SecRuleUpdateTargetById 958895 REQUEST_URI REQUEST_FILENAME
The effective resulting rule in the previous example will append the target to the end of the variable list as follows:
SecRule REQUEST_URI|ARGS_NAMES|ARGS|XML:/* "[\;\|\`]\W*?\bmail\b" \ "phase:2,rev:'2.1.1',capture,t:none,t:htmlEntityDecode,t:compressWhitespace,t:lowercase,ctl:auditLogParts=+E,block,msg:'System Command Injection',id:'958895',tag:'WEB_ATTACK/COMMAND_INJECTION',tag:'WASCTC/WASC-31',tag:'OWASP_TOP_10/A1',tag:'PCI/6.5.2',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.command_injection_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=% {tx.0}""Conditionally Appending Targets
You could also do the same by using the ctl action. This is useful if you want to only update the targets for a particular URL
SecRule REQUEST_FILENAME "@streq /path/to/file.php" "phase:1,id:2,t:none,nolog,pass,ctl:ruleUpdateTargetById=958895;!ARGS:email"
Conditionally Replacing Targets
You could also replace targets using the ctl action. For example, lets say you want to only inspect ARGS for a particular URL:
SecRule REQUEST_FILENAME "@streq /path/to/file.php" "phase:1,id:3,t:none,nolog,pass,ctl:ruleUpdateTargetById=958895;REQUEST_URI;REQUEST_FILENAME"
Syntax: SecRuleUpdateTargetByMsg TEXT TARGET1[,TARGET2,TARGET3] REPLACED_TARGET
Example Usage: SecRuleUpdateTargetByMsg "Cross-site Scripting (XSS) Attack" "!ARGS:foo"
Scope: Any
Version: 2.7
This directive will append (or replace) variables to the current target list of the specified rule with the targets provided in the second parameter.
Explicitly Appending Targets
This is useful for implementing exceptions where you want to externally update a target list to exclude inspection of specific variable(s).
SecRule REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/* "[\;\|\`]\W*?\bmail\b" \ "phase:2,rev:'2.1.1',capture,t:none,t:htmlEntityDecode,t:compressWhitespace,t:lowercase,ctl:auditLogParts=+E,block,msg:'System Command Injection',id:'958895',tag:'WEB_ATTACK/COMMAND_INJECTION',tag:'WASCTC/WASC-31',tag:'OWASP_TOP_10/A1',tag:'PCI/6.5.2',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.command_injection_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=% {tx.0}" SecRuleUpdateTargetByMsg "System Command Injection" !ARGS:email
The effective resulting rule in the previous example will append the target to the end of the variable list as follows:
SecRule REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/*|!ARGS:email "[\;\|\`]\W*?\bmail\b" \ "phase:2,rev:'2.1.1',capture,t:none,t:htmlEntityDecode,t:compressWhitespace,t:lowercase,ctl:auditLogParts=+E,block,msg:'System Command Injection',id:'958895',tag:'WEB_ATTACK/COMMAND_INJECTION',tag:'WASCTC/WASC-31',tag:'OWASP_TOP_10/A1',tag:'PCI/6.5.2',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.command_injection_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=% {tx.0}""Explicitly Replacing Targets
You can also entirely replace the target list to something more appropriate for your environment. For example, lets say you want to inspect REQUEST_URI instead of REQUEST_FILENAME, you could do this:
SecRule REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/* "[\;\|\`]\W*?\bmail\b" \ "phase:2,rev:'2.1.1',capture,t:none,t:htmlEntityDecode,t:compressWhitespace,t:lowercase,ctl:auditLogParts=+E,block,msg:'System Command Injection',id:'958895',tag:'WEB_ATTACK/COMMAND_INJECTION',tag:'WASCTC/WASC-31',tag:'OWASP_TOP_10/A1',tag:'PCI/6.5.2',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.command_injection_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=% {tx.0}" SecRuleUpdateTargetByMsg "System Command Injection" REQUEST_URI REQUEST_FILENAME
The effective resulting rule in the previous example will append the target to the end of the variable list as follows:
SecRule REQUEST_URI|ARGS_NAMES|ARGS|XML:/* "[\;\|\`]\W*?\bmail\b" \ "phase:2,rev:'2.1.1',capture,t:none,t:htmlEntityDecode,t:compressWhitespace,t:lowercase,ctl:auditLogParts=+E,block,msg:'System Command Injection',id:'958895',tag:'WEB_ATTACK/COMMAND_INJECTION',tag:'WASCTC/WASC-31',tag:'OWASP_TOP_10/A1',tag:'PCI/6.5.2',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.command_injection_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=% {tx.0}""
Syntax: SecRuleUpdateTargetByTag TEXT TARGET1[,TARGET2,TARGET3] REPLACED_TARGET
Example Usage: SecRuleUpdateTargetByTag "WEB_ATTACK/XSS" "!ARGS:foo"
Scope: Any
Version: 2.7
This directive will append (or replace) variables to the current target list of the specified rule with the targets provided in the second parameter.
Explicitly Appending Targets
This is useful for implementing exceptions where you want to externally update a target list to exclude inspection of specific variable(s).
SecRule REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/* "[\;\|\`]\W*?\bmail\b" \ "phase:2,rev:'2.1.1',capture,t:none,t:htmlEntityDecode,t:compressWhitespace,t:lowercase,ctl:auditLogParts=+E,block,msg:'System Command Injection',id:'958895',tag:'WEB_ATTACK/COMMAND_INJECTION',tag:'WASCTC/WASC-31',tag:'OWASP_TOP_10/A1',tag:'PCI/6.5.2',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.command_injection_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=% {tx.0}" SecRuleUpdateTargetByTag "WASCTC/WASC-31" !ARGS:email
The effective resulting rule in the previous example will append the target to the end of the variable list as follows:
SecRule REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/*|!ARGS:email "[\;\|\`]\W*?\bmail\b" \ "phase:2,rev:'2.1.1',capture,t:none,t:htmlEntityDecode,t:compressWhitespace,t:lowercase,ctl:auditLogParts=+E,block,msg:'System Command Injection',id:'958895',tag:'WEB_ATTACK/COMMAND_INJECTION',tag:'WASCTC/WASC-31',tag:'OWASP_TOP_10/A1',tag:'PCI/6.5.2',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.command_injection_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=% {tx.0}""Explicitly Replacing Targets
You can also entirely replace the target list to something more appropriate for your environment. For example, lets say you want to inspect REQUEST_URI instead of REQUEST_FILENAME, you could do this:
SecRule REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/* "[\;\|\`]\W*?\bmail\b" \ "phase:2,rev:'2.1.1',capture,t:none,t:htmlEntityDecode,t:compressWhitespace,t:lowercase,ctl:auditLogParts=+E,block,msg:'System Command Injection',id:'958895',tag:'WEB_ATTACK/COMMAND_INJECTION',tag:'WASCTC/WASC-31',tag:'OWASP_TOP_10/A1',tag:'PCI/6.5.2',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.command_injection_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=% {tx.0}" SecRuleUpdateTargetByTag "WASCTC/WASC-31" REQUEST_URI REQUEST_FILENAME
The effective resulting rule in the previous example will append the target to the end of the variable list as follows:
SecRule REQUEST_URI|ARGS_NAMES|ARGS|XML:/* "[\;\|\`]\W*?\bmail\b" \ "phase:2,rev:'2.1.1',capture,t:none,t:htmlEntityDecode,t:compressWhitespace,t:lowercase,ctl:auditLogParts=+E,block,msg:'System Command Injection',id:'958895',tag:'WEB_ATTACK/COMMAND_INJECTION',tag:'WASCTC/WASC-31',tag:'OWASP_TOP_10/A1',tag:'PCI/6.5.2',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.command_injection_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=% {tx.0}""
Syntax: SecServerSignature "WEB SERVER SOFTWARE"
Example Usage: SecServerSignature "Microsoft-IIS/6.0"
Scope: Main
Version: 2.0.0
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.
Syntax: SecStreamInBodyInspection On|Off
Example Usage: SecStreamInBodyInspection On
Scope: Any
Version: 2.6.0
Default: Off
This feature enables the creation of the STREAM_INPUT_BODY variable and is useful for data modification or to match data in raw data for any content-types.
Syntax: SecStreamOutBodyInspection On|Off
Example Usage: SecStreamOutBodyInspection On
Scope: Any
Version: 2.6.0
Default: Off
This feature enables the creation of the STREAM_OUTPUT_BODY variable and is useful when you need to do data modification into response body.
Syntax: SecTmpDir /path/to/dir
Example Usage: SecTmpDir /tmp
Scope: Any
Version: 2.0.0
The location specified needs to be writable by the Apache user process. This is the directory location where ModSecurity will swap data to disk if it runs out of memory (more data than what was specified in the SecRequestBodyInMemoryLimit directive) during inspection.
Syntax: SecUnicodeMapFile /path/to/unicode.mapping
Example Usage: SecUnicodeMapFile /usr/local/apache/conf/crs/unicode.mapping
Scope: Any
Version: 2.6.1
Syntax: SecUnicodeCodePage XXXXX
Example Usage: SecUnicodeCodePage 20127
Scope: Any
Version: 2.6.1
Syntax: SecUploadDir /path/to/dir
Example Usage: SecUploadDir /tmp
Scope: Any
Version: 2.0.0
This directory must be on the same filesystem as the temporary directory defined with SecTmpDir. This directive is used with SecUploadKeepFiles.
Syntax: SecUploadFileLimit number
Example Usage: SecUploadFileLimit 10
Scope: Any
Version: 2.5.12
The default is set to 100 files, but you are encouraged to reduce this value. Any file over the limit will not be extracted and the MULTIPART_FILE_LIMIT_EXCEEDED and MULTIPART_STRICT_ERROR flags will be set. To prevent bypassing any file checks, you must check for one of these flags.
Syntax: SecUploadFileMode octal_mode|"default"
Example Usage: SecUploadFileMode 0640
Scope: Any
Version: 2.1.6
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.
Syntax: SecUploadKeepFiles On|Off|RelevantOnly
Example Usage: SecUploadKeepFiles On
Scope: Any
Version: 2.0.0
This directive requires the storage directory to be defined (using SecUploadDir).
Possible values are:
Syntax: SecWebAppId "NAME"
Example Usage: SecWebAppId "WebApp1"
Scope: Any
Version: 2.0.0
Default: default
Application namespaces are used to avoid collisions between session IDs and user IDs when multiple applications are deployed on the same server. If it isn’t used, a collision between session IDs might occur.
<VirtualHost *:80> ServerName app1.example.com SecWebAppId "App1" ... </virtualhost> <VirtualHost *:80> ServerName app2.example.com SecWebAppId "App2" ... </virtualhost>
In the two examples configurations shown, SecWebAppId is being used in conjunction with the Apache VirtualHost directives. Applications namespace information is also recorded in the audit logs (using the WebApp-Info header of the H part).
This directive is used to set collections timeout. For example:
SecCollectionTimeout 500
Syntax: SecCollectionTimeout seconds
Default: 3600
Scope: Any
Version: 2.6.3
See modsecurity_diagram_apache_request_cycle.jpg
In order to select the phase a rule executes during, use the phase action either directly in the rule or in using the SecDefaultAction directive:
SecDefaultAction "log,pass,phase:2,id:4" SecRule REQUEST_HEADERS:Host "!^$" "deny,phase:1,id:5"
Some variables are actually collections, which are expanded into more variables at runtime. The following example will examine all request arguments:
SecRule ARGS dirty "id:7"
Sometimes, however, you will want to look only at parts of a collection. This can be achieved with the help of the selection operator(colon). The following example will only look at the arguments named p (do note that, in general, requests can contain multiple arguments with the same name):
SecRule ARGS:p dirty "id:8"
It is also possible to specify exclusions. The following will examine all request arguments for the word dirty, except the ones named z (again, there can be zero or more arguments named z):
SecRule ARGS|!ARGS:z dirty "id:9"
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):
SecRule &ARGS !^0$ "id:10"
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 id_:
SecRule ARGS:/^id_/ dirty "id:11"
SecRule ARGS_COMBINED_SIZE "@gt 2500" "id:12"
SecRule ARGS_NAMES "!^(p|a)$" "id:13"
SecRule AUTH_TYPE "Basic" "id:14"
# Set environment variable SecRule REQUEST_FILENAME "printenv" \ "phase:2,id:15,pass,setenv:tag=suspicious" # Inspect environment variable SecRule ENV:tag "suspicious" "id:16"
SecRule FILES "@rx \.conf$" "id:17"
SecRule FILES_COMBINED_SIZE "@gt 100000" "id:18"
SecRule FILES_NAMES "^upfile$" "id:19"
SecRule FILES_SIZES "@gt 100" "id:20"
SecRule FILES_TMPNAMES "@inspectFile /path/to/inspect_script.pl" "id:21"
Available since ModSecurity 2.5.0.
Fields:
SecGeoLookupDb /usr/local/geo/data/GeoLiteCity.dat ... SecRule REMOTE_ADDR "@geoLookup" "chain,id:22,drop,msg:'Non-GB IP address'" SecRule GEO:COUNTRY_CODE "!@streq GB"
SecRule HIGHEST_SEVERITY "@le 2" "phase:2,id:23,deny,status:500,msg:'severity %{HIGHEST_SEVERITY}'"
The best way to use this variable is as in the example below:
SecRule INBOUND_DATA_ERROR "@eq 1" "phase:1,id:24,t:none,log,pass,msg:'Request Body Larger than SecRequestBodyLimit Setting'"
SecRule ARGS pattern chain,deny,id:25 SecRule MATCHED_VAR "further scrutiny"
SecRule ARGS pattern "chain,deny,id:26" SecRule MATCHED_VARS "@eq ARGS:param"
SecRule ARGS pattern "chain,deny,id:27" SecRule MATCHED_VAR_NAME "@eq ARGS:param"
SecRule ARGS pattern "chain,deny,id:28" SecRule MATCHED_VARS_NAMES "@eq ARGS:param"
SecRule MODSEC_BUILD "!@ge 02050102" "skipAfter:12345,id:29" SecRule ARGS "@pm some key words" "id:12345,deny,status:500"
The best way to use this variable is as in the example below:
SecRule MULTIPART_STRICT_ERROR "!@eq 0" \ "phase:2,id:30,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_MISSING_SEMICOLON}, \ IQ %{MULTIPART_INVALID_QUOTING}, \ IQ %{MULTIPART_INVALID_HEADER_FOLDING}, \ FE %{MULTIPART_FILE_LIMIT_EXCEEDED}'"The multipart/form-data 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 MULTIPART_STRICT_ERROR 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.
The best way to use this variable is as in the example below:
SecRule MULTIPART_UNMATCHED_BOUNDARY "!@eq 0" \ "phase:2,id:31,t:none,log,deny,msg:'Multipart parser detected a possible unmatched boundary.'"Change the rule from blocking to logging-only if many false positives are encountered.
The best way to use this variable is as in the example below:
SecRule OUTBOUND_DATA_ERROR "@eq 1" "phase:1,id:32,t:none,log,pass,msg:'Response Body Larger than SecResponseBodyLimit Setting'"
SecRule PATH_INFO "^/(bin|etc|sbin|opt|usr)" "id:33"
SecRule PERF_RULES "@gt 1000" "id:12345,phase:5"
SecRule QUERY_STRING "attack" "id:34"
SecRule REMOTE_ADDR "@ipMatch 192.168.1.101" "id:35"
SecRule REMOTE_HOST "\.evil\.network\org$" "id:36"
In the following example, we are evaluating to see whether the REMOTE_PORT is less than 1024, which would indicate that the user is a privileged user:
SecRule REMOTE_PORT "@lt 1024" "id:37"
SecRule REMOTE_USER "^admin$" "id:38"
SecRule REQBODY_ERROR "@eq 1" deny,phase:2,id:39
SecRule REQBODY_ERROR_MSG "failed to parse" "id:40"
SecRule REQBODY_PROCESSOR "^XML$ chain,id:41 SecRule XML "@validateDTD /opt/apache-frontend/conf/xml.dtd"
SecRule REQUEST_BASENAME "^login\.php$" phase:2,id:42,t:none,t:lowercase
SecRule REQUEST_BODY "^username=\w{25,}\&password=\w{25,}\&Submit\=login$" "id:43"
As of 2.5.7, it is possible to force the presence of the REQUEST_BODY variable, but only when there is no request body processor defined using the ctl:forceRequestBodyVariable option in the REQUEST_HEADERS phase.
SecRule &REQUEST_COOKIES "@eq 0" "id:44"
SecRule &REQUEST_COOKIES_NAMES:JSESSIONID "@eq 0" "id:45"
SecRule REQUEST_FILENAME "^/cgi-bin/login\.php$" phase:2,id:46,t:none,t:normalizePath
SecRule REQUEST_HEADERS:Host "^[\d\.]+$" "deny,id:47,log,status:400,msg:'Host header is a numeric IP address'"
SecRule REQUEST_HEADERS_NAMES "^x-forwarded-for" "log,deny,id:48,status:403,t:lowercase,msg:'Proxy Server Used'"
# Allow only POST, GET and HEAD request methods, as well as only # the valid protocol versions SecRule REQUEST_LINE "!(^((?:(?:POS|GE)T|HEAD))|HTTP/(0\.9|1\.0|1\.1)$)" "phase:1,id:49,log,block,t:none"
SecRule REQUEST_METHOD "^(?:CONNECT|TRACE)$" "id:50,t:none"
SecRule REQUEST_PROTOCOL "!^HTTP/(0\.9|1\.0|1\.1)$" "id:51"
SecRule REQUEST_URI "attack" "phase:1,id:52,t:none,t:urlDecode,t:lowercase,t:normalizePath"
SecRule REQUEST_URI_RAW "http:/" "phase:1,id:53,t:none,t:urlDecode,t:lowercase,t:normalizePath"
SecRule RESPONSE_BODY "ODBC Error Code" "phase:4,id:54,t:none"
SecRule RESPONSE_HEADERS:X-Cache "MISS" "id:55"
This variable may not have access to some headers when running in embedded mode. Headers such as Server, Date, Connection, and Content-Type could be added just prior to sending the data to the client. This data should be available in phase 5 or when deployed in proxy mode.
SecRule RESPONSE_HEADERS_NAMES "Set-Cookie" "phase:3,id:56,t:none"
The same limitations apply as the ones discussed in RESPONSE_HEADERS.
SecRule RESPONSE_PROTOCOL "^HTTP\/0\.9" "phase:3,id:57,t:none"
SecRule RESPONSE_STATUS "^[45]" "phase:3,id:58,t:none"
This variable may not work as expected in embedded mode, as Apache sometimes handles certain requests differently, and without invoking ModSecurity (all other modules).
SecRule &REQUEST_HEADERS:Host "@eq 0" "log,deny,id:59,setvar:tx.varname=%{RULE.id}"
SecRule SCRIPT_BASENAME "^login\.php$" "id:60"
SecRule SCRIPT_FILENAME "^/usr/local/apache/cgi-bin/login\.php$" "id:61"
SecRule SCRIPT_GID "!^46$" "id:62"
SecRule SCRIPT_GROUPNAME "!^apache$" "id:63"
# Do not allow scripts that can be written to SecRule SCRIPT_MODE "^(2|3|6|7)$" "id:64"
# Do not run any scripts that are owned # by Apache (Apache's user id is 46) SecRule SCRIPT_UID "!^46$" "id:65"
# Do not run any scripts owned by Apache SecRule SCRIPT_USERNAME "^apache$" "id:66"
SecRule SERVER_ADDR "@ipMatch 192.168.1.100" "id:67"
SecRule SERVER_NAME "hostname\.com$" "id:68"
SecRule SERVER_PORT "^80$" "id:69"
The following example shows how to initialize SESSION using 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:
# Initialize session storage SecRule REQUEST_COOKIES:PHPSESSID !^$ "phase:2,id:70,nolog,pass,setsid:%{REQUEST_COOKIES.PHPSESSID}" # Increment session score on attack SecRule REQUEST_URI "^/cgi-bin/finger$" "phase:2,id:71,t:none,t:lowercase,t:normalizePath,pass,setvar:SESSION.score=+10" # Detect too many attacks in a session SecRule SESSION:score "@gt 50" "phase:2,id:72,pass,setvar:SESSION.blocked=1" # Enforce session block SecRule SESSION:blocked "@eq 1" "phase:2,id:73,deny,status:403"
SecRule TIME "^(([1](8|9))|([2](0|1|2|3))):\d{2}:\d{2}$" "id:74"
SecRule TIME_DAY "^(([1](0|1|2|3|4|5|6|7|8|9))|20)$" "id:75"
SecRule TIME_HOUR "^(0|1|2|3|4|5|6|[1](8|9)|[2](0|1|2|3))$" "id:76"
SecRule TIME_MIN "^(3|4|5)" "id:77"
SecRule TIME_MON "^1" "id:78"
SecRule TIME_SEC "@gt 30" "id:79"
SecRule TIME_WDAY "^(0|6)$" "id:80"
SecRule TIME_YEAR "^2006$" "id:81"
# Increment transaction attack score on attack SecRule ARGS attack "phase:2,id:82,nolog,pass,setvar:TX.score=+5" # Block the transactions whose scores are too high SecRule TX:SCORE "@gt 20" "phase:2,id:83,log,deny"
Some variable names in the TX collection are reserved and cannot be used:
# Initialize user tracking SecAction "nolog,id:84,pass,setuid:%{REMOTE_USER}" # Is the current user the administrator? SecRule USERID "admin" "id:85"
SecRule WEBSERVER_ERROR_LOG "File does not exist" "phase:5,id:86,t:none,nolog,pass,setvar:TX.score=+5"
SecDefaultAction log,deny,status:403,phase:2,id:90 SecRule REQUEST_HEADERS:Content-Type ^text/xml$ "phase:1,id:87,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML" SecRule REQBODY_PROCESSOR "!^XML$" skipAfter:12345,id:88 SecRule XML:/employees/employee/name/text() Fred "id:89" SecRule XML:/xq:employees/employee/name/text() Fred "id:12345,xmlns:xq=http://www.example.com/employees"
The first XPath expression does not use namespaces. It would match against payload such as this one:
<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>
The second XPath expression does use namespaces. It would match the following payload:
<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>
Note the different namespace used in the second example.
SecRule ARGS "xp_cmdshell" "t:lowercase,id:91"
Multiple transformation actions can be used in the same rule, forming a transformation pipeline. The transformations will be performed in the order in which they appear in the rule.
In most cases, the order in which transformations are performed is very important. In the following example, a series of transformation functions is performed to counter evasion. Performing the transformations in any other order would allow a skillful attacker to evade detection:
SecRule ARGS "(asfunction|javascript|vbscript|data|mocha|livescript):" "id:92,t:none,t:htmlEntityDecode,t:lowercase,t:removeNulls,t:removeWhitespace"
SecRule REQUEST_HEADERS:Authorization "^Basic ([a-zA-Z0-9]+=*)$" "phase:1,id:93,capture,chain,logdata:%{TX.1}" SecRule TX:1 ^(\w+): t:base64Decode,capture,chain SecRule TX:1 ^(admin|root|backup)$
See blog post on Base64Decoding evasion issues on PHP sites - http://blog.spiderlabs.com/2010/04/impedance-mismatch-and-base64.html
SecRule ARGS "(?:command(?:.com)?|cmd(?:.exe)?)(?:/.*)?/[ck]" "phase:2,id:94,t:none, t:cmdLine"
Action Group: Meta-data
Version: 2.7
Example:
SecRule REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/* "\bgetparentfolder\b" \ "phase:2,ver:'CRS/2.2.4,accuracy:'9',maturity:'9',capture,t:none,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,msg:'Cross-site Scripting (XSS) Attack',id:'958016',tag:'WEB_ATTACK/XSS',tag:'WASCTC/WASC-8',tag:'WASCTC/WASC-22',tag:'OWASP_TOP_10/A2',tag:'OWASP_AppSensor/IE1',tag:'PCI/6.5.1',logdata:'% \ {TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+%{tx.critical_anomaly_score},setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{tx.0}"
Action Group: Disruptive
Example:
# Allow unrestricted access from 192.168.1.100 SecRule REMOTE_ADDR "^192\.168\.1\.100$" phase:1,id:95,nolog,allow
Prior to ModSecurity 2.5 the allow action would only affect the current phase. An allow 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 allow was enhanced to allow for fine-grained control of what is done. The following rules now apply:
# Do not process request but process response. SecAction phase:1,allow:request,id:96 # Do not process transaction (request and response). SecAction phase:1,allow,id:97
If you want to allow a response through, put a rule in phase RESPONSE_HEADERS and simply use allow on its own:
# Allow response through. SecAction phase:3,allow,id:98
Action Group: Non-disruptive
Processing Phases: 3 and 4.
Example:
SecRule RESPONSE_CONTENT_TYPE "^text/html" "nolog,id:99,pass,append:'<hr>Footer'"
Action Group: Non-disruptive
Example:
SecRule REMOTE_ADDR "^192\.168\.1\.100$" auditlog,phase:1,id:100,allow
Action Group: Disruptive
This action is essentially a placeholder that is intended to be used by rule writers to request a blocking action, but without specifying how the blocking is to be done. The idea is that such decisions are best left to rule users, as well as to allow users, to override blocking if they so desire. In future versions of ModSecurity, more control and functionality will be added to define "how" to block.
Examples:
# Specify how blocking is to be done SecDefaultAction phase:2,deny,id:101,status:403,log,auditlog # Detect attacks where we want to block SecRule ARGS attack1 phase:2,block,id:102 # Detect attacks where we want only to warn SecRule ARGS attack2 phase:2,pass,id:103
It is possible to use the SecRuleUpdateActionById directive to override how a rule handles blocking. This is useful in three cases:
# Specify how blocking is to be done SecDefaultAction phase:2,deny,status:403,log,auditlog,id:104 # Detect attacks and block SecRule ARGS attack1 phase:2,id:1,deny # Change how rule ID 1 blocks SecRuleUpdateActionById 1 block
Action Group: Non-disruptive
Example:
SecRule REQUEST_BODY "^username=(\w{25,})" phase:2,capture,t:none,chain,id:105 SecRule TX:1 "(?:(?:a(dmin|nonymous)))"
Up to 10 captures will be copied on a successful pattern match, each with a name consisting of a digit from 0 to 9. The TX.0 variable always contains the entire area that the regular expression matched. All the other variables contain the captured values, in the order in which the capturing parentheses appear in the regular expression.
Action Group: Flow
Example:
# Refuse to accept POST requests that do not contain Content-Length header. # (Do note that this rule should be preceded by a rule # that verifies only valid request methods are used.) SecRule REQUEST_METHOD "^POST$" phase:1,chain,t:none,id:105 SecRule &REQUEST_HEADERS:Content-Length "@eq 0" t:none
Action Group: Non-disruptive
Example:
# Parse requests with Content-Type "text/xml" as XML SecRule REQUEST_CONTENT_TYPE ^text/xml "nolog,pass,id:106,ctl:requestBodyProcessor=XML" # white-list the user parameter for rule #981260 when the REQUEST_URI is /index.php SecRule REQUEST_URI "@beginsWith /index.php" "phase:1,t:none,pass, \ nolog,ctl:ruleRemoveTargetById=981260;ARGS:user
The following configuration options are supported:
The requestBodyProcessor option allows you to configure the request body processor. By default, ModSecurity will use the URLENCODED and MULTIPART processors to process an application/x-www-form-urlencoded and a multipart/form-data body, respectively. A third processor, XML, is also supported, but it is never used implicitly. Instead, you must tell ModSecurity to use it by placing a few rules in the REQUEST_HEADERS processing phase. After the request body is processed as XML, you will be able to use the XML-related features to inspect it.
Request body processors will not interrupt a transaction if an error occurs during parsing. Instead, they will set the variables REQBODY_PROCESSOR_ERROR and REQBODY_PROCESSOR_ERROR_MSG. These variables should be inspected in the REQUEST_BODY phase and an appropriate action taken. The forceRequestBodyVariable option allows you to configure the REQUEST_BODY variable to be set when there is no request body processor configured. This allows for inspection of request bodies of unknown types.
Action Group: Disruptive
Example:
SecRule REQUEST_HEADERS:User-Agent "nikto" "log,deny,id:107,msg:'Nikto Scanners Identified'"
Action Group: Non-Disruptive
Example: The following example will decrement the counter by 60 every 300 seconds.
SecAction phase:5,id:108,nolog,pass,deprecatevar:SESSION.score=60/300
Counter values are always positive, meaning that the value will never go below zero. Unlike expirevar, the deprecate action must be executed on every request.
Action Group: Disruptive
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.
SecAction phase:1,id:109,initcol:ip=%{REMOTE_ADDR},nolog SecRule ARGS:login "!^$" "nolog,phase:1,id:110,setvar:ip.auth_attempt=+1,deprecatevar:ip.auth_attempt=20/120" SecRule IP:AUTH_ATTEMPT "@gt 25" "log,drop,phase:1,id:111,msg:'Possible Brute Force Attack'"
Action Group: Non-disruptive
Example:
# Run external program on rule match SecRule REQUEST_URI "^/cgi-bin/script\.pl" "phase:2,id:112,t:none,t:lowercase,t:normalizePath,block,\ exec:/usr/local/apache/bin/test.sh" # Run Lua script on rule match SecRule ARGS:p attack "phase:2,id:113,block,exec:/usr/local/apache/conf/exec.lua"
The exec action is executed independently from any disruptive actions specified. 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 a multithreaded deployment. The script you execute must write something (anything) to stdout; if it doesn’t, ModSecurity will assume that the script failed, and will record the failure.
Action Group: Non-disruptive
Example:
SecRule REQUEST_COOKIES:JSESSIONID "!^$" "nolog,phase:1,id:114,pass,setsid:%{REQUEST_COOKIES:JSESSIONID}" SecRule REQUEST_URI "^/cgi-bin/script\.pl" "phase:2,id:115,t:none,t:lowercase,t:normalisePath,log,allow,setvar:session.suspicious=1,expirevar:session.suspicious=3600,phase:1"
You should use the 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 will be reset.
Action Group: Meta-data
Example:
SecRule &REQUEST_HEADERS:Host "@eq 0" "log,id:60008,severity:2,msg:'Request Missing a Host Header'"
Action Group: Non-disruptive
Example: The following example initiates IP address tracking, which is best done in phase 1:
SecAction phase:1,id:116,nolog,pass,initcol:ip=%{REMOTE_ADDR}
Collections are loaded into memory on-demand, when the initcol action is executed. A collection will be persisted only if a change was made to it in the course of transaction processing.
See the "Persistant Storage" section for further details.
Action Group: Non-disruptive
Example:
SecAction phase:1,id:117,pass,initcol:ip=%{REMOTE_ADDR},log
This action will log matches to the Apache error log file and the ModSecurity audit log.
Action Group: Non-disruptive
Example:
SecRule ARGS:p "@rx <script>" "phase:2,id:118,log,pass,logdata:%{MATCHED_VAR}"
The logdata information appears in the error and/or audit log files. Macro expansion is performed, so you may use variable names such as %{TX.0} or %{MATCHED_VAR}. The information is properly escaped for use with logging of binary data.
Action Group: Meta-data
Version: 2.7
Example:
SecRule REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/* "\bgetparentfolder\b" \ "phase:2,ver:'CRS/2.2.4,accuracy:'9',maturity:'9',capture,t:none,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,msg:'Cross-site Scripting (XSS) Attack',id:'958016',tag:'WEB_ATTACK/XSS',tag:'WASCTC/WASC-8',tag:'WASCTC/WASC-22',tag:'OWASP_TOP_10/A2',tag:'OWASP_AppSensor/IE1',tag:'PCI/6.5.1',logdata:'% \ {TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+%{tx.critical_anomaly_score},setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{tx.0}"
Action Group: Meta-data
Example:
SecRule &REQUEST_HEADERS:Host "@eq 0" "log,id:60008,severity:2,msg:'Request Missing a Host Header'"
Action Group: Non-disruptive
Example:
SecRule ARGS "attack" "phase1,log,deny,id:119,t:removeNulls,t:lowercase,multiMatch"
Normally, variables are inspected only once per rule, and only after all transformation functions have been completed. With multiMatch, variables are checked against the operator before and after every transformation function that changes the input.
Action Group: Non-disruptive
Example:
SecRule REQUEST_HEADERS:User-Agent "Test" allow,noauditlog,id:120
If the SecAuditEngine is set to On, all of the transactions will be logged. If it is set to RelevantOnly, then you can control the logging with the noauditlog action.
The noauditlog action affects only the current rule. If you prevent audit logging in one rule only, a match in another rule will still cause audit logging to take place. If you want to prevent audit logging from taking place, regardless of whether any rule matches, use ctl:auditEngine=Off.
Action Group: Non-disruptive
Example:
SecRule REQUEST_HEADERS:User-Agent "Test" allow,nolog,id:121
Although nolog implies noauditlog, you can override the former by using nolog,auditlog.
Action Group: Disruptive
Example:
SecRule REQUEST_HEADERS:User-Agent "Test" "log,pass,id:122"
When using pass with a SecRule with multiple targets, all variables will be inspected and all non-disruptive actions trigger for every match. In the following example, the TX.test variable will be incremented once for every request parameter:
# Set TX.test to zero SecAction "phase:2,nolog,pass,setvar:TX.test=0,id:123" # Increment TX.test for every request parameter SecRule ARGS "test" "phase:2,log,pass,setvar:TX.test=+1,id:124"
Action Group: Disruptive
Example:
SecRule REQUEST_HEADERS:User-Agent "Test" "log,pause:5000,id:125"
Action Group: Meta-data
Example:
# Initialize IP address tracking in phase 1 SecAction phase:1,nolog,pass,id:126,initcol:IP=%{REMOTE_ADDR}
Starting in ModSecurity version v2.7 there are aliases for some phase numbers:
SecRule REQUEST_HEADERS:User-Agent "Test" "phase:request,log,deny,id:127"
Action Group: Non-disruptive
Processing Phases: 3 and 4.
Example:
SecRule RESPONSE_CONTENT_TYPE ^text/html \ "phase:3,nolog,pass,id:128,prepend:'Header<br>'"
Action Group: Disruptive
Example:
SecRule REQUEST_HEADERS:User-Agent "Test" log,id:129,proxy:http://honeypothost/
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 web server, and especially in combination with IP address or session tracking.
Action Group: Disruptive
Example:
SecRule REQUEST_HEADERS:User-Agent "Test" "phase:1,id:130,log,redirect:http://www.example.com/failed.html"
If the status action is present on the same rule, and its value can be used for a redirection (i.e., is one of the following: 301, 302, 303, or 307), the value will be used for the redirection status code. Otherwise, status code 302 will be used.
Action Group: Meta-data
Example:
SecRule REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/* "(?:(?:[\;\|\`]\W*?\bcc|\b(wget|curl))\b|\/cc(?:[\'\"\|\;\`\-\s]|$))" \ "phase:2,rev:'2.1.3',capture,t:none,t:normalisePath,t:lowercase,ctl:auditLogParts=+E,block,msg:'System Command Injection',id:'950907',tag:'WEB_ATTACK/COMMAND_INJECTION',tag:'WASCTC/WASC-31',tag:'OWASP_TOP_10/A1',tag:'PCI/6.5.2',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.command_injection_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{tx.0},skipAfter:END_COMMAND_INJECTION1"
Action Group: Non-disruptive
Example:
# Never log passwords SecAction "nolog,phase:2,id:131,sanitiseArg:password,sanitiseArg:newPassword,sanitiseArg:oldPassword"
Action Group: Non-disruptive
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 password in the name.
SecRule ARGS_NAMES password nolog,pass,id:132,sanitiseMatched
Action Group: Non-disruptive
Example: This action can be used to sanitise arbitrary transaction elements when they match a condition. For example, the example below will sanitise the credit card number.
# Detect credit card numbers in parameters and # prevent them from being logged to audit log SecRule ARGS "@verifyCC \d{13,16}" "phase:2,id:133,nolog,capture,pass,msg:'Potential credit card number in request',sanitiseMatchedBytes" SecRule RESPONSE_BODY "@verifyCC \d{13,16}" "phase:4,id:134,t:none,log,capture,block,msg:'Potential credit card number is response body',sanitiseMatchedBytes:0/4"
Action Group: Non-disruptive
Example: This will sanitise the data in the Authorization header.
SecAction "phase:1,nolog,pass,id:135,sanitiseRequestHeader:Authorization"
Action Group: Non-disruptive
Example: This will sanitise the Set-Cookie data sent to the client.
SecAction "phase:3,nolog,pass,id:136,sanitiseResponseHeader:Set-Cookie"
Action Group: Meta-data
Example:
SecRule REQUEST_METHOD "^PUT$" "id:340002,rev:1,severity:CRITICAL,msg:'Restricted HTTP function'"
Severity values in ModSecurity follows the numeric scale of syslog (where 0 is the most severe). The data below is used by the OWASP ModSecurity Core Rule Set (CRS):
Action Group: Non-disruptive
Example:
SecRule ARGS:username ".*" "phase:2,id:137,t:none,pass,nolog,noauditlog,capture,setvar:session.username=%{TX.0},setuid:%{TX.0}"
After initialization takes place, the variable USERID will be available for use in the subsequent rules. This action understands application namespaces (configured using SecWebAppId), and will use one if it is configured.
Action Group: Non-disruptive
Example:
SecAction "phase:1,pass,id:3,log,setrsc:'abcd1234'"
This action understands application namespaces (configured using SecWebAppId), and will use one if it is configured.
Action Group: Non-disruptive
Example:
# Initialise session variables using the session cookie value SecRule REQUEST_COOKIES:PHPSESSID !^$ "nolog,pass,id:138,setsid:%{REQUEST_COOKIES.PHPSESSID}"Note
After the initialization takes place, the variable SESSIONID will be available for use in the subsequent rules. This action understands application namespaces (configured using SecWebAppId), and will use one if it is configured.
Action Group: Non-disruptive
Examples:
SecRule RESPONSE_HEADERS:/Set-Cookie2?/ "(?i:(j?sessionid|(php)?sessid|(asp|jserv|jw)?session[-_]?(id)?|cf(id|token)|sid))" "phase:3,t:none,pass,id:139,nolog,setvar:tx.sessionid=%{matched_var}" SecRule TX:SESSIONID "!(?i:\;? ?httponly;?)" "phase:3,id:140,t:none,setenv:httponly_cookie=%{matched_var},pass,log,auditlog,msg:'AppDefect: Missing HttpOnly Cookie Flag.'" Header set Set-Cookie "%{httponly_cookie}e; HTTPOnly" env=httponly_cookie
Action Group: Non-disruptive
Examples:
To create a variable and set its value to 1 (usually used for setting flags), use: setvar:TX.score
To create a variable and initialize it at the same time, use: setvar:TX.score=10
To remove a variable prefix the name with exclamation mark, use: setvar:!TX.score
To increase or decrease variable value, use + and - characters in front of a numerical value: setvar:TX.score=+5
Example from OWASP CRS:
SecRule REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/* "\bsys\.user_catalog\b" \ "phase:2,rev:'2.1.3',capture,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase,t:replaceComments,t:compressWhiteSpace,ctl:auditLogParts=+E, \ block,msg:'Blind SQL Injection Attack',id:'959517',tag:'WEB_ATTACK/SQL_INJECTION',tag:'WASCTC/WASC-19',tag:'OWASP_TOP_10/A1',tag:'OWASP_AppSensor/CIE1', \ tag:'PCI/6.5.2',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sql_injection_score=+%{tx.critical_anomaly_score}, \ setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{tx.0}"
Action Group: Flow
Example:
# Require Accept header, but not from access from the localhost SecRule REMOTE_ADDR "^127\.0\.0\.1$" "phase:1,skip:1,id:141" # This rule will be skipped over when REMOTE_ADDR is 127.0.0.1 SecRule &REQUEST_HEADERS:Accept "@eq 0" "phase:1,id:142,deny,msg:'Request Missing an Accept Header'"
The skip action works only within the current processing phase and not necessarily in the order in which the rules appear in the configuration file. If you place a phase 2 rule after a phase 1 rule that uses skip, it will not skip over the phase 2 rule. It will skip over the next phase 1 rule that follows it in the phase.
Action Group: Flow
Example: The following rules implement the same logic as the skip example, but using skipAfter:
# Require Accept header, but not from access from the localhost SecRule REMOTE_ADDR "^127\.0\.0\.1$" "phase:1,id:143,skipAfter:IGNORE_LOCALHOST" # This rule will be skipped over when REMOTE_ADDR is 127.0.0.1 SecRule &REQUEST_HEADERS:Accept "@eq 0" "phase:1,deny,id:144,msg:'Request Missing an Accept Header'" SecMarker IGNORE_LOCALHOST
Example from the OWASP ModSecurity CRS:
SecMarker BEGIN_HOST_CHECK SecRule &REQUEST_HEADERS:Host "@eq 0" \ "skipAfter:END_HOST_CHECK,phase:2,rev:'2.1.3',t:none,block,msg:'Request Missing a Host Header',id:'960008',tag:'PROTOCOL_VIOLATION/MISSING_HEADER_HOST',tag:'WASCTC/WASC-21', \ tag:'OWASP_TOP_10/A7',tag:'PCI/6.5.10',severity:'5',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.notice_anomaly_score}, \ setvar:tx.protocol_violation_score=+%{tx.notice_anomaly_score},setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/MISSING_HEADER-%{matched_var_name}=%{matched_var}" SecRule REQUEST_HEADERS:Host "^$" \ "phase:2,rev:'2.1.3',t:none,block,msg:'Request Missing a Host Header',id:'960008',tag:'PROTOCOL_VIOLATION/MISSING_HEADER_HOST',tag:'WASCTC/WASC-21',tag:'OWASP_TOP_10/A7', \ tag:'PCI/6.5.10',severity:'5',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},setvar:tx.protocol_violation_score=+%{tx.notice_anomaly_score}, \ setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/MISSING_HEADER-%{matched_var_name}=%{matched_var}" SecMarker END_HOST_CHECK
The skipAfter action works only within the current processing phase and not necessarily the order in which the rules appear in the configuration file. If you place a phase 2 rule after a phase 1 rule that uses skip, it will not skip over the phase 2 rule. It will skip over the next phase 1 rule that follows it in the phase.
Action Group: Data
Example:
# Deny with status 403 SecDefaultAction "phase:1,log,deny,id:145,status:403"
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.
Action Group: Non-disruptive
Example:
SecRule ARGS "(asfunction|javascript|vbscript|data|mocha|livescript):" "id:146,t:none,t:htmlEntityDecode,t:lowercase,t:removeNulls,t:removeWhitespace"
Any transformation functions that you specify in a SecRule will be added to the previous ones specified in SecDefaultAction. It is recommended that you always use t:none in your rules, which prevents them depending on the default configuration.
Action Group: Meta-data
Example:
SecRule REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/* "\bgetparentfolder\b" \ "phase:2,rev:'2.1.3',capture,t:none,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,msg:'Cross-site Scripting (XSS) Attack',id:'958016',tag:'WEB_ATTACK/XSS',tag:'WASCTC/WASC-8',tag:'WASCTC/WASC-22',tag:'OWASP_TOP_10/A2',tag:'OWASP_AppSensor/IE1',tag:'PCI/6.5.1',logdata:'% \ {TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+%{tx.critical_anomaly_score},setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{tx.0}"
The tag information appears along with other rule metadata. The purpose of the tagging mechanism to allow easy automated categorization of events. Multiple tags can be specified on the same rule. Use forward slashes to create a hierarchy of categories (as in the example). Since ModSecurity 2.6.0 tag supports macro expansion.
Action Group: Meta-data
Version: 2.7
Example:
SecRule REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/* "\bgetparentfolder\b" \ "phase:2,ver:'CRS/2.2.4,capture,t:none,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,msg:'Cross-site Scripting (XSS) Attack',id:'958016',tag:'WEB_ATTACK/XSS',tag:'WASCTC/WASC-8',tag:'WASCTC/WASC-22',tag:'OWASP_TOP_10/A2',tag:'OWASP_AppSensor/IE1',tag:'PCI/6.5.1',logdata:'% \ {TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+%{tx.critical_anomaly_score},setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{tx.0}"
Action Group: Data
Example:
SecRule REQUEST_HEADERS:Content-Type "text/xml" "phase:1,id:147,pass,ctl:requestBodyProcessor=XML,ctl:requestBodyAccess=On, \ xmlns:xsd="http://www.w3.org/2001/XMLSchema" SecRule XML:/soap:Envelope/soap:Body/q1:getInput/id() "123" phase:2,deny,id:148
Example:
# Detect request line that does not begin with "GET" SecRule REQUEST_LINE "!@beginsWith GET" "id:149"
Example:
# Detect ".php" anywhere in the request line SecRule REQUEST_LINE "@contains .php" "id:150"
Example:
# Detect "select" anywhere in ARGS SecRule ARGS "@containsWord select" "id:151"
Would match on -
-1 union select BENCHMARK(2142500,MD5(CHAR(115,113,108,109,97,112))) FROM wp_users WHERE ID=1 and (ascii(substr(user_login,1,1))&0x01=0) from wp_users where ID=1--
But not on -
Your site has a wide selection of computers.
Example:
# Detect request line that does not end with "HTTP/1.1" SecRule REQUEST_LINE "!@endsWith HTTP/1.1" "id:152"
Example:
# Detect exactly 15 request headers SecRule &REQUEST_HEADERS_NAMES "@eq 15" "id:153"
Example:
# Detect 15 or more request headers SecRule &REQUEST_HEADERS_NAMES "@ge 15" "id:154"
Example: The geoLookup operator matches on success and is thus best used in combination with nolog,pass. If you wish to block on a failed lookup (which may be over the top, depending on how accurate the geolocation database is), the following example demonstrates how best to do it:
# Configure geolocation database SecGeoLookupDb /path/to/GeoLiteCity.dat ... # Lookup IP address SecRule REMOTE_ADDR "@geoLookup" "phase:1,id:155,nolog,pass" # Block IP address for which geolocation failed SecRule &GEO "@eq 0" "phase:1,id:156,deny,msg:'Failed to lookup IP'"
See the GEO variable for an example and more information on various fields available.
Syntax: SecRule TARGET "@gsbLookup REGEX" ACTIONS
Version: 2.6
Example: The gsbLookup operator matches on success and is thus best used in combination with a block or redirect action. If you wish to block on successful lookups, the following example demonstrates how best to do it:
# Configure Google Safe Browsing database SecGsbLookupDb /path/to/GsbMalware.dat ... # Check response bodies for malicious links SecRule RESPONSE_BODY "@gsbLookup =\"https?\:\/\/(.*?)\"" "phase:4,id:157,capture,log,block,msg:'Bad url detected in RESPONSE_BODY (Google Safe Browsing Check)',logdata:'http://www.google.com/safebrowsing/diagnostic?site=%{tx.0}'"
Example:
# Detect more than 15 headers in a request SecRule &REQUEST_HEADERS_NAMES "@gt 15" "id:158"
The @inspectFile operator was initially designed for file inspection (hence the name), but it can also be used in any situation that requires decision making using external logic.
The OWASP ModSecurity Core Rule Set (CRS) includes a utility script in the /util directory called runav.pl http://mod-security.svn.sourceforge.net/viewvc/mod-security/crs/trunk/util/ that allows the file approval mechanism to integrate with the ClamAV virus scanner. This is especially handy to prevent viruses and exploits from entering the web server through file upload.
#!/usr/bin/perl # # runav.pl # Copyright (c) 2004-2011 Trustwave # # This script is an interface between ModSecurity and its # ability to intercept files being uploaded through the # web server, and ClamAV $CLAMSCAN = "clamscan"; if ($#ARGV != 0) { print "Usage: modsec-clamscan.pl <filename>\n"; exit; } my ($FILE) = shift @ARGV; $cmd = "$CLAMSCAN --stdout --disable-summary $FILE"; $input = `$cmd`; $input =~ m/^(.+)/; $error_message = $1; $output = "0 Unable to parse clamscan output [$1]"; if ($error_message =~ m/: Empty file\.?$/) { $output = "1 empty file"; } elsif ($error_message =~ m/: (.+) ERROR$/) { $output = "0 clamscan: $1"; } elsif ($error_message =~ m/: (.+) FOUND$/) { $output = "0 clamscan: $1"; } elsif ($error_message =~ m/: OK$/) { $output = "1 clamscan: OK"; } print "$output\n";
Example: Using the runav.pl script:
# Execute external program to validate uploaded files SecRule FILES_TMPNAMES "@inspectFile /path/to/util/runav.pl" "id:159"
Example of using Lua script (placed in the same directory as the configuration file):
SecRule FILES_TMPNANMES "@inspectFile inspect.lua" "id:160"
The contents of inspect.lua:
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
Examples:
Individual Address:
SecRule REMOTE_ADDR "@ipMatch 192.168.1.100" "id:161"Multiple Addresses w/network block:
SecRule REMOTE_ADDR "@ipMatch 192.168.1.100,192.168.1.50,10.10.50.0/24" "id:162"
Version: 2.7
Examples:
SecRule REMOTE_ADDR "@ipMatch ips.txt" "id:163"
The file ips.txt may contain:
192.168.0.1 172.16.0.0/16 10.0.0.0/8
Example:
# Detect 15 or fewer headers in a request SecRule &REQUEST_HEADERS_NAMES "@le 15" "id:164"
Example:
# Detect fewer than 15 headers in a request SecRule &REQUEST_HEADERS_NAMES "@lt 15" "id:165"
Example:
# Detect suspicious client by looking at the user agent identification SecRule REQUEST_HEADERS:User-Agent "@pm WebZIP WebCopier Webster WebStripper ... SiteSnagger ProWebWalker CheeseBot" "id:166"
This operator is the same as @pm, 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.
Example:
# Detect suspicious user agents using the keywords in # the files /path/to/blacklist1 and blacklist2 (the latter # must be placed in the same folder as the configuration file) SecRule REQUEST_HEADERS:User-Agent "@pmFromFile /path/to/blacklist1 blacklist2" "id:167"
Notes:
# Prepare custom REMOTE_ADDR variable SecAction "phase:1,id:168,nolog,pass,setvar:tx.REMOTE_ADDR=/%{REMOTE_ADDR}/" # Check if REMOTE_ADDR is blacklisted SecRule TX:REMOTE_ADDR "@pmFromFile blacklist.txt" "phase:1,id:169,deny,msg:'Blacklisted IP address'"
The file blacklist.txt may contain:
# ip-blacklist.txt contents: # NOTE: All IPs must be prefixed/suffixed with "/" as the rules # will add in this character as a boundary to ensure # the entire IP is matched. # SecAction "phase:1,id:170,pass,nolog,setvar:tx.remote_addr='/%{REMOTE_ADDR}/'" /1.2.3.4/ /5.6.7.8/
Example:
SecRule REMOTE_ADDR "@rbl sbl-xbl.spamhaus.org" "phase:1,id:171,t:none,pass,nolog,auditlog,msg:'RBL Match for SPAM Source',tag:'AUTOMATION/MALICIOUS',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.automation_score=+%{tx.warning_anomaly_score},setvar:tx.anomaly_score=+%{tx.warning_anomaly_score}, \ setvar:tx.%{rule.id}-AUTOMATION/MALICIOUS-%{matched_var_name}=%{matched_var},setvar:ip.spammer=1,expirevar:ip.spammer=86400,setvar:ip.previous_rbl_check=1,expirevar:ip.previous_rbl_check=86400,skipAfter:END_RBL_CHECK"
Syntax: @rsub s/regex/str/[id]
Examples: Removing HTML Comments from response bodies:
SecStreamOutBodyInspection On SecRule STREAM_OUTPUT_BODY "@rsub s// /" "phase:4,id:172,t:none,nolog,pass"
Examples:
# Detect Nikto SecRule REQUEST_HEADERS:User-Agent "@rx nikto" phase:1,id:173,t:lowercase # Detect Nikto with a case-insensitive pattern SecRule REQUEST_HEADERS:User-Agent "@rx (?i)nikto" phase:1,id:174,t:none # Detect Nikto with a case-insensitive pattern SecRule REQUEST_HEADERS:User-Agent "(?i)nikto" "id:175"
Regular expressions are handled by the PCRE library http://www.pcre.org. ModSecurity compiles its regular expressions with the following settings:
Example:
# Detect request parameters "foo" that do not # contain "bar", exactly. SecRule ARGS:foo "!@streq bar" "id:176"
Example:
# Detect suspicious client by looking at the user agent identification SecRule REQUEST_HEADERS:User-Agent "@strmatch WebZIP" "id:177"
Example:
# Enforce very strict byte range for request parameters (only # works for the applications that do not use the languages other # than English). SecRule ARGS "@validateByteRange 10, 13, 32-126" "id:178"
The validateByteRange is most useful when used to detect the presence of NUL bytes, which don’t have a legitimate use, but which are often used as an evasion technique.
# Do not allow NUL bytes SecRule ARGS "@validateByteRange 1-255" "id:179"
Example:
# Parse the request bodies that contain XML SecRule REQUEST_HEADERS:Content-Type ^text/xml$ "phase:1,id:180,nolog,pass,t:lowercase,ctl:requestBodyProcessor=XML" # Validate XML payload against DTD SecRule XML "@validateDTD /path/to/xml.dtd" "phase:2,id:181,deny,msg:'Failed DTD validation'"
Example:
# Validates requested URI that matches a regular expression. SecRule REQUEST_URI "@validatehash "product_info|product_list" "phase:1,deny,id:123456"
Example:
# Parse the request bodies that contain XML SecRule REQUEST_HEADERS:Content-Type ^text/xml$ "phase:1,id:190,nolog,pass,t:lowercase,ctl:requestBodyProcessor=XML" # Validate XML payload against DTD SecRule XML "@validateSchema /path/to/xml.xsd" "phase:2,id:191,deny,msg:'Failed DTD validation'"
Example:
# Validate URL-encoded characters in the request URI SecRule REQUEST_URI_RAW "@validateUrlEncoding" "id:192"
ModSecurity will automatically decode the URL-encoded characters in request parameters, which means that there is little sense in applying the @validateUrlEncoding operator to them —that is, unless you know that some of the request parameters were URL-encoded more than once. Use this operator against raw input, or against the input that you know is URL-encoded. For example, some applications will URL-encode cookies, although that’s not in the standard. Because it is not in the standard, ModSecurity will neither validate nor decode such encodings.
Example:
# Make sure all request parameters contain only valid UTF-8 SecRule ARGS "@validateUtf8Encoding" "id:193"
The @validateUtf8Encoding operator detects the following problems:
Example:
# Detect credit card numbers in parameters and # prevent them from being logged to audit log SecRule ARGS "@verifyCC \d{13,16}" "phase:2,id:194,nolog,pass,msg:'Potential credit card number',sanitiseMatched"
Example:
# Detect CPF numbers in parameters and # prevent them from being logged to audit log SecRule ARGS "@verifyCPF /^([0-9]{3}\.){2}[0-9]{3}-[0-9]{2}$/" "phase:2,id:195,nolog,pass,msg:'Potential CPF number',sanitiseMatched"
Example:
# Detect social security numbers in parameters and # prevent them from being logged to audit log SecRule ARGS "@verifySSN \d{3}-?\d{2}-?\d{4}" "phase:2,id:196,nolog,pass,msg:'Potential social security number',sanitiseMatched"
Version: 2.6
SSN Format:
A Social Security number is broken up into 3 sections:
Example:
# Detect request methods other than GET, POST and HEAD SecRule REQUEST_METHOD "!@within GET,POST,HEAD"
Format:
%{VARIABLE} %{COLLECTION.VARIABLE}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.
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.
Every collection contains several built-in variables that are available and are read-only unless otherwise specified:
# -- Rule engine initialization ---------------------------------------------- # Enable ModSecurity, attaching it to every transaction. Use detection # only to start with, because that minimises the chances of post-installation # disruption. # SecRuleEngine DetectionOnly # -- Request body handling --------------------------------------------------- # Allow ModSecurity to access request bodies. If you don't, ModSecurity # won't be able to see any POST parameters, which opens a large security # hole for attackers to exploit. # SecRequestBodyAccess On # Enable XML request body parser. # Initiate XML Processor in case of xml content-type # SecRule REQUEST_HEADERS:Content-Type "text/xml" \ "id:'200000',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML" # Maximum request body size we will accept for buffering. If you support # file uploads then the value given on the first line has to be as large # as the largest file you are willing to accept. The second value refers # to the size of data, with files excluded. You want to keep that value as # low as practical. # SecRequestBodyLimit 13107200 SecRequestBodyNoFilesLimit 131072 # Store up to 128 KB of request body data in memory. When the multipart # parser reachers this limit, it will start using your hard disk for # storage. That is slow, but unavoidable. # SecRequestBodyInMemoryLimit 131072 # What to do if the request body size is above our configured limit. # Keep in mind that this setting will automatically be set to ProcessPartial # when SecRuleEngine is set to DetectionOnly mode in order to minimize # disruptions when initially deploying ModSecurity. # SecRequestBodyLimitAction Reject # Verify that we've correctly processed the request body. # As a rule of thumb, when failing to process a request body # you should reject the request (when deployed in blocking mode) # or log a high-severity alert (when deployed in detection-only mode). # SecRule REQBODY_ERROR "!@eq 0" "id:'200001', phase:2,t:none,log,deny, \ status:400,msg:'Failed to parse request body.',logdata:'%{reqbody_error_msg}',severity:2" # By default be strict with what we accept in the multipart/form-data # request body. If the rule below proves to be too strict for your # environment consider changing it to detection-only. You are encouraged # _not_ to remove it altogether. # SecRule MULTIPART_STRICT_ERROR "!@eq 0" \ "id:'200002',phase:2,t:none,log,deny,status:400, \ 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_MISSING_SEMICOLON}, \ IQ %{MULTIPART_INVALID_QUOTING}, \ IP %{MULTIPART_INVALID_PART}, \ IH %{MULTIPART_INVALID_HEADER_FOLDING}, \ FL %{MULTIPART_FILE_LIMIT_EXCEEDED}'" # Did we see anything that might be a boundary? # SecRule MULTIPART_UNMATCHED_BOUNDARY "!@eq 0" "id:'200003',phase:2,t:none,log,deny, \ status:400,msg:'Multipart parser detected a possible unmatched boundary.'" # PCRE Tuning # We want to avoid a potential RegEx DoS condition # SecPcreMatchLimit 1000 SecPcreMatchLimitRecursion 1000 # Some internal errors will set flags in TX and we will need to look for these. # All of these are prefixed with "MSC_". The following flags currently exist: # # MSC_PCRE_LIMITS_EXCEEDED: PCRE match limits were exceeded. # SecRule TX:/^MSC_/ "!@streq 0" \ "id:'200004',phase:2,t:none,deny,msg:'ModSecurity internal error flagged: %{MATCHED_VAR_NAME}'" # -- Response body handling -------------------------------------------------- # Allow ModSecurity to access response bodies. # You should have this directive enabled in order to identify errors # and data leakage issues. # # Do keep in mind that enabling this directive does increases both # memory consumption and response latency. # SecResponseBodyAccess On # Which response MIME types do you want to inspect? You should adjust the # configuration below to catch documents but avoid static files # (e.g., images and archives). # SecResponseBodyMimeType text/plain text/html text/xml # Buffer response bodies of up to 512 KB in length. SecResponseBodyLimit 524288 # What happens when we encounter a response body larger than the configured # limit? By default, we process what we have and let the rest through. # That's somewhat less secure, but does not break any legitimate pages. # SecResponseBodyLimitAction ProcessPartial # -- Filesystem configuration ------------------------------------------------ # The location where ModSecurity stores temporary files (for example, when # it needs to handle a file upload that is larger than the configured limit). # # This default setting is chosen due to all systems have /tmp available however, # this is less than ideal. It is recommended that you specify a location that's private. # SecTmpDir /tmp/ # The location where ModSecurity will keep its persistent data. This default setting # is chosen due to all systems have /tmp available however, it # too should be updated to a place that other users can't access. # SecDataDir /tmp/ # -- File uploads handling configuration ------------------------------------- # The location where ModSecurity stores intercepted uploaded files. This # location must be private to ModSecurity. You don't want other users on # the server to access the files, do you? # #SecUploadDir /opt/modsecurity/var/upload/ # By default, only keep the files that were determined to be unusual # in some way (by an external inspection script). For this to work you # will also need at least one file inspection rule. # #SecUploadKeepFiles RelevantOnly # Uploaded files are by default created with permissions that do not allow # any other user to access them. You may need to relax that if you want to # interface ModSecurity to an external program (e.g., an anti-virus). # #SecUploadFileMode 0600 # -- Debug log configuration ------------------------------------------------- # The default debug log configuration is to duplicate the error, warning # and notice messages from the error log. # #SecDebugLog /opt/modsecurity/var/log/debug.log #SecDebugLogLevel 3 # -- Audit log configuration ------------------------------------------------- # Log the transactions that are marked by a rule, as well as those that # trigger a server error (determined by a 5xx or 4xx, excluding 404, # level response status codes). # SecAuditEngine RelevantOnly SecAuditLogRelevantStatus "^(?:5|4(?!04))" # Log everything we know about a transaction. SecAuditLogParts ABIJDEFHZ # Use a single file for logging. This is much easier to look at, but # assumes that you will use the audit log only occasionally. # SecAuditLogType Serial SecAuditLog /var/log/modsec_audit.log # Use concurrent logging #SecAuditLogType Concurrent #SecAuditLog "|/opt/modsecurity/bin/mlogc /opt/modsecurity/etc/mlogc.conf" # Specify the path for concurrent audit logging. #SecAuditLogStorageDir /opt/modsecurity/var/audit/ # -- Miscellaneous ----------------------------------------------------------- # Use the most commonly used application/x-www-form-urlencoded parameter # separator. There's probably only one application somewhere that uses # something else so don't expect to change this value. # SecArgumentSeparator & # Settle on version 0 (zero) cookies, as that is what most applications # use. Using an incorrect cookie version may open your installation to # evasion attacks (against the rules that examine named cookies). # SecCookieFormat 0 # Specify your Unicode Code Point. # This mapping is used by the t:urlDecodeUni transformation function # to properly map encoded data to your language. Properly setting # these directives helps to reduce false positives and negatives. # #SecUnicodeCodePage 20127 #SecUnicodeMapFile unicode.mapping
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.
Headers
# This is an <h1> tag ## This is an <h2> tag ###### This is an <h6> tag
Text styles
*This text will be italic* _This will also be italic_ **This text will be bold** __This will also be bold__ *You **can** combine them*
Unordered
* Item 1 * Item 2 * Item 2a * Item 2b
Ordered
1. Item 1 2. Item 2 3. Item 3 * Item 3a * Item 3b
Images
 Format: 
Links
http://github.com - automatic! [GitHub](http://github.com)
Blockquotes
As Kanye West said: > We're living the future so > the present is our past.
Syntax highlighting with GFM
```javascript function fancyAlert(arg) { if(arg) { $.facebox({div:'#foo'}) } } ```
Or, indent your code 4 spaces
Here is a Python code example without syntax highlighting: def foo: if not bar: return true
Inline code for comments
I think you should use an `<addr>` element here instead.