Integrating ModSecurity with Nginx on Debian 9

Posted on 13-04-2019 by Nadir Latif

Introduction

ModSecurity is a an open source Web Application Firewall (WAF). It can detect as well as prevent attacks to web applications. Initiallly released as an Apache web server module, ModSecurity now supports all major Web Servers including IIS, Nginx and Apache.

It also provides a standalone library called Libmodsecurity that can be used in external applications. Connectors are used to allow external applications to use the Libmodsecurity library. The connectors serve as interfaces between external applications and Libmodsecurity. For example Nginx uses Libmodsecurity through the ModSecurity-nginx connector. In this article I will describe how to install ModSecurity and integrate it with Nginx on Debian Stretch using the ModSecurity-nginx connector.

Installation

ModSecurity can be integrated with Nginx web server using the ModSecurity-nginx connector. The ModSecurity-nginx connector is a Nginx module which uses the Libmodsecurity library. ModSecurity can be enabled for the following contexts: server, http and location. the main Nginx directives provided by the ModSecurity are: modsecurity on | off and modsecurity_rules_file [path to rules file]. Once enabled it checks each request and compares it with the OWASP ModSecurity Core Rule Set (CRS).

The OWASP ModSecurity Core Rule Set (CRS) is a set of attack detection rules which aims to protect Web Applications from a wide range of attacks including the OWASP Top Ten list. The CRS is intended for ModSecurity but may be used by other applications.

ModSecurity may be configured in detection mode or in prevention mode. In detection mode, ModSecurity simply logs the error message to a log file. In prevention mode, the error is not only logged, but the request is blocked and an error response is sent to the sender of the request.

I followed the steps given in the article: ModSecurity and nginx. The article is useful and covers all the steps, but has some short commings. The guide: ModSecurity 3.0 and NGINX: Quick Start Guide, provided by the Nginx website is a comprehensive guide which may be regarded as the official documentation for integrating ModSecurity with Nginx. The main steps involved in integrating ModSecurity with Nginx are on Debian 9 (Stretch) are:

Install Nginx

The installation of Nginx on Debian is documented on the Nginx website. The main steps are:


# Add the repository url to the apt sources list
echo "deb http://nginx.org/packages/debian `lsb_release -cs` nginx" | sudo tee /etc/apt/sources.list.d/nginx.list
# Add the package signing key
curl -fsSL https://nginx.org/keys/nginx_signing.key | sudo apt-key add -
# Verify the package signing key
apt-key fingerprint ABF5BD827BD9BF62
# Update system package list
sudo apt-get update
# Install Nginx
sudo apt-get install nginx
# Verify the Nginx version
nginx -v

Compile the Libmodsecurity

To compile the Libmodsecurity library, we need to first install the dependencies. Next we need to download and compile the Libmodsecurity source code.

Install the dependencies

Use the following command to install the packages required by Libmodsecurity library:

apt-get install libtool autoconf build-essential libpcre3-dev zlib1g-dev libssl-dev libxml2-dev libgeoip-dev liblmdb-dev libyajl-dev libcurl4-openssl-dev libpcre++-dev pkgconf libxslt1-dev libgd-dev
Download the code

Use the following commands to download the correct version of Libmodsecurity source code. Note that the command given in the ModSecurity and nginx article mentions the old source code. Use the command which is mentioned in the ModSecurity 3.0 and NGINX: Quick Start Guide


cd /opt/
# The correct command for downloading the latest Libmodsecurity source code
git clone --depth 100 -b v3/master --single-branch https://github.com/SpiderLabs/ModSecurity
cd ModSecurity
git submodule init
git submodule update

Compile the code

Use the following command to compile the Libmodsecurity source code:


# Generate configure file
sh build.sh
# Pre compilation step. Checks for dependencies
./configure
# Compiles the source code
make
# Installs the Libmodsecurity to /usr/local/modsecurity/lib/libmodsecurity.so
make install

Compile the connector

It requires downloading the Nginx source code and the source code for ModSecurity-nginx connector. When downloading the Nginx source code, make sure the version matches the currently installed Nginx version. Even though we just need to compile the ModSecurity-nginx connector, we need the Nginx source code. The following steps are involved:


# Fetch the Nginx source code. See the directory: http://nginx.org/download/ for all versions of Nginx
wget http://nginx.org/download/nginx-1.14.2.tar.gz
# Extract the downloaded source code
tar -xvzf nginx-1.14.2.tar.gz        
# Fetch the source code for ModSecurity-nginx connector
git clone https://github.com/SpiderLabs/ModSecurity-nginx
# Change directory to the Nginx source code
cd nginx-1.14.2/
# Note the compile time flags used to generate the current Nginx binary
nginx -V
# Compile the Nginx using the compile time flags noted above. Exclude the add-dynamic-module options since we only need to compile the ModSecurity-nginx module
./configure [your-compile-time-options noted above] --add-dynamic-module=[path-to-ModSecurity-nginx connector source code]
# Generate the module
make modules
# Copy the module to the Nginx module directory
cp objs/ngx_http_modsecurity_module.so /etc/nginx/modules/

Configure the connector

To configure and enable the ModSecurity-nginx connector, we need to first load the ModSecurity Nginx module. Next we need to download the ModSecurity rules. After that we need to configure the ModSecurity-nginx connector.

Load the module

Add following line to /etc/nginx/nginx.conf:


load_module modules/ngx_http_modsecurity_module.so;
Download the rules
        
# Create the modsec folder in the Nginx configuration folder. It will contain the ModSec rules
mkdir /etc/nginx/modsec
# Change directory
cd /etc/nginx/modsec
# Download the rules
git clone https://github.com/SpiderLabs/owasp-modsecurity-crs.git
# Rename the default ModSecurity rules configuration file
mv /etc/nginx/modsec/owasp-modsecurity-crs/crs-setup.conf.example /etc/nginx/modsec/owasp-modsecurity-crs/crs-setup.conf
Configure the connector

# Copy the default ModSecurity configuration file to the modesec folder
cp /opt/ModSecurity/modsecurity.conf-recommended /etc/nginx/modsec/modsecurity.conf
# Create a configuration file that will be loaded by Nginx. This file will load the ModSec rules configuration file and the ModSec configuration file
vi /etc/nginx/modsec/main.conf
# Add following lines to the file
Include /etc/nginx/modsec/modsecurity.conf
Include /etc/nginx/modsec/owasp-modsecurity-crs/crs-setup.conf
Include /etc/nginx/modsec/owasp-modsecurity-crs/rules/*.conf
# Restart Nginx
service nginx restart
# If you see an error that mentions missing unicode.mapping file, then copy the file to the mod sec folder
cp /opt/ModSecurity/unicode.mapping /etc/nginx/modsec            

Testing the ModSecurity

To test the ModSecurity Nginx integration, we need to enable the Nginx ModSecurity module for the default virtual host. Add the following 2 lines to /etc/nginx/conf.d/default.conf. The lines should be added under the server_name line:


modsecurity on;
modsecurity_rules_file /etc/nginx/modsec/main.conf;

Next we need to restart the Nginx server using service nginx restart. We can test the ModSecurity by sending a suspicious request to the Nginx web server. The following command sends a curl request containing a banned user agent: curl -H "User-Agent: masscan" http://localhost/. The following should be logged to the ModSecurity log file which is /var/log/modsec_audit.log:


ModSecurity: Warning. Matched "Operator `PmFromFile' with parameter `scanners-user-agents.data' against &rarrhkk;variable `REQUEST_HEADERS:User-Agent' (Value: `masscan' )

This indicates that ModSecurity successfully detected the suspicious request. However the request was allowed to pass through to Nginx. This is because ModSecurity operations in detection mode by default, which means it only logs the suspicious requests. To enable ModSecurity to block requests, we need to edit the ModSecurity configuration file: /etc/nginx/modsec/modsecurity.conf and change: SecRuleEngine DetectionOnly to SecRuleEngine On. Next we need to restart Nginx. After that the previous curl command should fail with a 403 error message, indicating that ModSecurity has successfully intercepted and blocked the request. The blocked request will also be logged.

Conclusion

ModSecurity is a very useful tool which allows protecting web applications from malicious attacks. Although it can stop most attacks, it cannot stop attacks that resemble normal user requests. For example spam attacks on WordPress websites may not be stopped by ModSecurity alone. To stop such attacks we can use a tool such as Fail2Ban or a WordPress security plugin like the All In One WP Security & Firewall


Leave a Comment:

Martin Garmendia

Thank you very much for this detailed guide, very good work. I've followed it for debian buster (10) with success. I have only some errors executing ModSecurity's build.sh:


root@waf:/opt/ModSecurity# sh build.sh
libtoolize: putting auxiliary files in '.'.
libtoolize: copying file './ltmain.sh'
libtoolize: putting macros in AC_CONFIG_MACRO_DIRS, 'build'.
libtoolize: copying file 'build/libtool.m4'
libtoolize: copying file 'build/ltoptions.m4'
libtoolize: copying file 'build/ltsugar.m4'
libtoolize: copying file 'build/ltversion.m4'
libtoolize: copying file 'build/lt~obsolete.m4'
fatal: No names found, cannot describe anything.
fatal: No names found, cannot describe anything.
fatal: No names found, cannot describe anything.
fatal: No names found, cannot describe anything.
fatal: No names found, cannot describe anything.
fatal: No names found, cannot describe anything.
configure.ac:50: installing './ar-lib'
configure.ac:50: installing './compile'
configure.ac:139: installing './config.guess'
configure.ac:139: installing './config.sub'
configure.ac:45: installing './install-sh'
configure.ac:45: installing './missing'
parallel-tests: installing './test-driver'
examples/multiprocess_c/Makefile.am: installing './depcomp'
configure.ac: installing './ylwrap'
fatal: No names found, cannot describe anything.
Anyway, make has worked fine and everithing else worked fine. Regards

Posted on: 11-09-2019 13:39
Nadir Latif

@Martin Garmendia. Use this command to clone the libmodsecurity repository:

git clone --depth 100 -b v3/master --single-branch 
https://github.com/SpiderLabs/ModSecurity.

This was suggested on: https://github.com/SickChill/SickChill/issues/4143

Posted on: 11-09-2019 14:44
Anonymous

When restarting the nginx service it fails: "/etc/nginx/modules/ngx_http_modsecurity_module.so" failed (libmodsecurity.so.3: cannot open shared object file: No such file or directory) in /etc/nginx/nginx.conf:8 The object file exists everything went fine until i restarted the service mv /etc/nginx/modules/ngx_http_modsecurity_module.so /etc/nginx/modules/ngx_http_modsecurity_module.so mv: '/etc/nginx/modules/ngx_http_modsecurity_module.so' and '/etc/nginx/modules/ngx_http_modsecurity_module.so' are the same file

Posted on: 12-10-2019 08:55
Nadir Latif

@Anonymous. In order to generate the ModSecurity module, you need to compile the Nginx source code with the ModSecurity source code. Make sure that the Nginx source code has same version as the Nginx binary. When compiling the Nginx source code, you need to use the same command line parameters that were used to generate the current Nginx binary. The command line parameters can be obtained using the command: nginx -V

Posted on: 12-10-2019 17:35
Anonymous

thanks for replying, yes i have compiled the module using the flags as you said in the "Compile the connector section" "# Note the compile time flags used to generate the current Nginx binary" I used nginx -v and copied everything when compiling. I will try again. Is there any other solution besides this one? Thanks in advance.

Posted on: 13-10-2019 01:25
Anonymous

And as i said, the module was properly compiled and it exists on the proper folder. Everything is on its place but when i restart it fails. As i said i have compiled the module using the flags as you said. Is there anything else that could be the problem?

Posted on: 13-10-2019 01:27
Anonymous

update: i got it working now. I did everything again from scratch and i got different errors this time around. The error was a version mismatch, so i downloaded the same version on the step to wget the nginx. Instead of "wget http://nginx.org/download/nginx-1.14.2.tar.gz " i changed the version to the one that is on "nginx -V".

Posted on: 13-10-2019 04:35
Nadir Latif

@Anonymous. Good to know you got it to work

Posted on: 13-10-2019 07:36