Practice
mod_security is a free web application firewall (WAF) for Apache, Nginx, and IIS that provides a flexible rule system for performing operations of varying complexity. In addition, mod_security ships with a base set of filtering rules called the Core Rule Set (or CRS), which includes rules to protect against SQL injection, cross-site scripting, trojans, bots, session hijacking, and many other attacks and exploits. In Apache, mod_security is one of the additional modules, which makes it easy to install and configure.
Note: to follow this guide you first need to have a LAMP stack installed.
ModSecurity can be downloaded from the standard Debian/Ubuntu repositories:
Make sure mod_security has been loaded:
If a module named security2_module (shared) appears on screen, everything went fine.
The ModSecurity installation includes a configuration file that needs to be renamed:
Then restart Apache:
In the Apache log directory you can find a new log file for mod_security.
For mod_security to work correctly, the out-of-the-box installation needs some additional configuration. The default configuration file is set to DetectionOnly, meaning the firewall only logs activity without blocking anything. To change this behavior, edit the modsecurity.conf file:
Find the following line in the file:
And change it to:
Note: when configuring mod_security on a production server, it is recommended to change this directive only after testing all the installed rules.
The next directive that needs editing is SecResponseBodyAccess. It controls buffering of the response body; it's recommended to enable it only if you need to detect and prevent data leaks. Enabling this directive (SecResponseBodyAccess On) will not only use more server resources but will also increase the size of the log file, so it's best to disable it. To do this, find:
And change the value:
Now you need to limit the maximum amount of data that can be sent to the web application. Two directives are responsible for this:
The SecRequestBodyLimit directive sets the maximum size of POST data. If a client sends more data, the server will return a 413 Request Entity Too Large error. If the web application doesn't have a file upload mechanism, this value can be significantly reduced. The configuration file sets the following by default:
Which equals 12.5 megabytes.
The SecRequestBodyNoFilesLimit directive works similarly. The only difference is that this directive limits the size of POST data excluding the size of files.
Note: it is recommended to set this value according to the ALARP principle ("as low as reasonably practicable", i.e., based on an assessment of risk and the resources involved).
By default, the configuration file has:
Which equals 128KB.
This file also contains another parameter that affects server performance — SecRequestBodyInMemoryLimit. This parameter sets the size of the response body data that will be placed in RAM; the rest of the data will be sent to the hard drive (as swap). Since servers typically run on SSDs, this isn't a problem; however, to save RAM, the value can be reduced.
This is the default value (128KB) in the configuration file.
Before defining the firewall policy using rules, you need to create a PHP script vulnerable to SQL injection. Note: this is a basic PHP login script without session handling. Don't forget to replace the MySQL password in the script below with your own password.
This script will display a login form. After entering the correct credentials, the message "A Secret for you" will appear on screen.
You need to add credentials to the database; to do this, create a MySQL database and table:
This will open the mysql> command prompt.
Open a browser and go to http://yourwebsite.com/login.php, then enter the correct login and password.
You will see a message indicating a successful login. Go back and try entering deliberately incorrect data — you'll see the message "Invalid username or password".
As you can see, the script works as intended. Now you need to perform a test SQL injection, attempting to bypass the credential check. In the Username field, enter:
Note: a space is required after the dashes, otherwise the injection won't work.
Leave the Password field empty and click the login button.
A message for authorized users appeared on screen — meaning the injection succeeded.
To protect the server from such attacks, you need to configure the firewall rules.
By default, mod_security ships with a base set of CRS (Core Rule Set) rules, located at:
Documentation can be found at:
To load these ready-made rules, the Apache web server needs to read the directories listed above. To do this, edit the mod-security.conf file:
Inside <IfModule security2_module> </IfModule> add the following parameters:
The activated_rules directory is similar to Apache's mods-enabled directory. Rules are available in the following directories:
To activate rules, you need to create symbolic links in the activated_rules directory. Create a rule to protect against SQL injection.
For the new rules to take effect, restart Apache.
Now go back to the login page you created earlier and try performing the test SQL injection again. If the SecRuleEngine directive was enabled, you'll see a 403 Forbidden error message. If the DetectionOnly value wasn't changed, the injection will succeed, but it will be logged in the modsec_audit.log file.
This section covers creating rule chains.
First, create a rule that blocks HTML requests containing various spam words. To do this, you need to create a PHP script that displays the data entered in a text field.
Custom rules can be added to any module configuration file or placed in the mod_security directories. Create a new file for the rules.
Add the following code to this file:
Save the file and restart Apache.
Open http://yourwebsite.com/form.php in your browser and enter any of these words: pills, insurance, rolex.
You'll get either a 403 error page along with a log entry, or just a log entry (this depends on the SecRuleEngine setting).
The SecRule syntax looks like this:
In this case, the chain action (i.e., [ACTIONS]) is used to match against the REQUEST_FILENAME and form.php variables, REQUEST_METHOD and POST, and REQUEST_BODY against the string "@rx (?i:(pills|insurance|rolex))". The ?i: combination is used for case-insensitive matching. If a match is found, the deny and log actions are executed, and the message "Spam detected" appears on screen. The chain action means "AND", meaning all three listed rules must match simultaneously.
Sometimes it's necessary to disable the firewall for certain directories or domains (for example, mod_security blocks SQL queries to phpMyAdmin).
Note: it's recommended to exclude CMS application back-ends.
To disable mod_security for an entire virtual host, add the following inside the <VirtualHost> section:
To disable mod_security for a specific directory:
To avoid disabling mod_security entirely, use the SecRuleRemoveById parameter to exclude a specific rule or rule chain by specifying its ID.
For more detailed information on how mod_security works, refer to the firewall's official documentation.
Comments