ModSecurity for NGINX

ModSecurity for NGINX, also known as ModSecurity-nginx, is a web application firewall module for the NGINX web server. It provides similar functionality to the original ModSecurity module for Apache, but is designed to work specifically with the NGINX web server.

Like the Apache module, ModSecurity-nginx analyzes incoming HTTP traffic and applies a set of predefined security rules to identify and block malicious or suspicious requests. It can also be configured to log request data and perform various other actions, such as blocking specific IP addresses or user agents.

Installation on Ubuntu 18.04.6 LTS Version

ModSecurity is available as a package in the Ubuntu repositories, so you can install it using the package manager.

To install ModSecurity on Ubuntu 18.04.6 LTS, you can follow these steps:

1. Update Packages

Update the package index and upgrade the system packages:

sudo apt-get update
sudo apt-get upgrade

2. Install NGINX

If you do not have NGINX Web Server installed on your server already, install NGINX using the following command. If you have NGINX installed already, you can ignore this step.

sudo  apt  install nginx

3. Install ModSecurity

The next step is to clone mode ModSecurity from github. It’s a good habit to clone installation files to the /opt folder so let’s get ahead and run the command:

cd /opt

Once you are in the /opt folder, proceed by cloning https://github.com/SpiderLabs/ModSecurity from github.

git clone https://github.com/SpiderLabs/ModSecurity

Proceed by navigating inside the newly created folder.

cd ModSecurity

Once you are inside the folder, you have to ensure that all the submodules are inside are initialized and updated. You can do this by running the commands below:

git submodule init && git submodule update

First, you need to install the following dependencies for the build process.

sudo apt-get install libtool m4 automake

Once done, you can now start the build process using the command below:

sh build.sh

Install the following dependencies before proceeding.

apt-get install liblmdb-dev libxml2-dev liblua5.3-dev libcurl4-openssl-dev libpcre3 libpcre3-dev

Once done, you should run the sh configure command and this will show you if you have all the tools and dependencies installed.

sh configure

After everything you can now run the make command.

make

After that, this is the only time you can now really install by running the commands below:

make install

Congratulations! ModSecurity is now setup and installed on your server.

4. Building Modules for ModSecurity

Once again, let’s clone installation files to the /opt folder so let’s get ahead and run the command:

cd /opt

Once you are in the /opt folder, proceed by cloning https://github.com/SpiderLabs/ModSecurity-nginx from github.

git clone https://github.com/SpiderLabs/ModSecurity-nginx

Proceed by navigating inside the newly created folder.

cd ModSecurity-nginx

Before proceeding, we all need to understand that ModSecurity works only on certain number of versions from NGINX. Not having the proper version may result into a failure of installation.

Let’s proceed by checking the version of NGINX currently installed.

nginx -v

You will see a message similar to this:

nginx version: nginx/1.14.0 (Ubuntu)

This means that the current version of NGINX installed on our server is 1.14.0. You need to make sure that you take this down.

This means that you have to download NGINX installation similar to this version. You can proceed by navigating to the /opt folder once again and running the command below:

cd /opt && wget https://nginx.org/download/nginx-1.14.0.tar.gz

Please remember to replace 1.14.0 with the version of NGINX you are using when you’ve execute nginx -v.

To extract the file, you must run

tar -xzvf nginx-1.14.0.tar.gz

Let’s proceed inside that directory.

cd nginx-1.14.0

The next thing to do is to configure ModeSecurity to connect to our NGINX. In order to that, we need get specific configure arguments which will vary depending on your environment.

Install the following dependencies before proceeding

sudo apt-get install libssl-dev zlib1g-dev libxslt-dev libgd-dev libgeoip-dev

You can do that by running the command below:

nginx -V

If you are doing everything right. You will get the following output:

nginx version: nginx/1.14.0 (Ubuntu)
built with OpenSSL 1.1.1  11 Sep 2018
TLS SNI support enabled
configure arguments: --with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-YlUNvj/nginx-1.14.0=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_geoip_module=dynamic --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_sub_module --with-http_xslt_module=dynamic --with-stream=dynamic --with-stream_ssl_module --with-mail=dynamic --with-mail_ssl_module

What you need do is to copy the information that comes after the configure arguments. You can can check the needed information below. Please take note that this will vary depending on the environment.

--with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-YlUNvj/nginx-1.14.0=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_geoip_module=dynamic --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_sub_module --with-http_xslt_module=dynamic --with-stream=dynamic --with-stream_ssl_module --with-mail=dynamic --with-mail_ssl_module

Make sure that you are still in the folder /opt/nginx-1.14.0. You can now proceed on running the code.

sh configure <configure-argument> --add-dynamic-module="../ModSecurity-nginx"

by replacing the <configure-argument> it will become:

sh configure --with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-YlUNvj/nginx-1.14.0=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_geoip_module=dynamic --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_sub_module --with-http_xslt_module=dynamic --with-stream=dynamic --with-stream_ssl_module --with-mail=dynamic --with-mail_ssl_module --add-dynamic-module="../ModSecurity-nginx"

If you encounter this and other errors:

configure: error: SSL modules require the OpenSSL library.
You can either do not enable the modules, or install the OpenSSL library
into the system, or build the OpenSSL library statically from the source
with nginx by using --with-openssl=<path> option.

Once done, you must run sh configure with the other arguments above again. You should get the following message to know that it worked:

Configuration summary
  + using threads
  + using system PCRE library
  + using system OpenSSL library
  + using system zlib library

  nginx path prefix: "/usr/share/nginx"
  nginx binary file: "/usr/share/nginx/sbin/nginx"
  nginx modules path: "/usr/lib/nginx/modules"
  nginx configuration prefix: "/etc/nginx"
  nginx configuration file: "/etc/nginx/nginx.conf"
  nginx pid file: "/run/nginx.pid"
  nginx error log file: "/var/log/nginx/error.log"
  nginx http access log file: "/var/log/nginx/access.log"
  nginx http client request body temporary files: "/var/lib/nginx/body"
  nginx http proxy temporary files: "/var/lib/nginx/proxy"
  nginx http fastcgi temporary files: "/var/lib/nginx/fastcgi"
  nginx http uwsgi temporary files: "/var/lib/nginx/uwsgi"
  nginx http scgi temporary files: "/var/lib/nginx/scgi"

If you get the correct message above without any error. It’s to make the modules. You c an do this by running the command below:

make modules

This will create a module that will facilitate the connection between MODSECURITY and NGINX.

You can view the modules by running ls objs. If you are in the right track, you will see the following output:

root@server-admin:/opt/nginx-1.14.0# ls objs
addon                                   ngx_http_image_filter_module_modules.o  ngx_mail_module_modules.o
autoconf.err                            ngx_http_image_filter_module.so         ngx_mail_module.so
Makefile                                ngx_http_modsecurity_module_modules.c   ngx_modules.c
ngx_auto_config.h                       ngx_http_modsecurity_module_modules.o   ngx_stream_module_modules.c
ngx_auto_headers.h                      ngx_http_modsecurity_module.so          ngx_stream_module_modules.o
ngx_http_geoip_module_modules.c         ngx_http_xslt_filter_module_modules.c   ngx_stream_module.so
ngx_http_geoip_module_modules.o         ngx_http_xslt_filter_module_modules.o   src
ngx_http_geoip_module.so                ngx_http_xslt_filter_module.so
ngx_http_image_filter_module_modules.c  ngx_mail_module_modules.c

5. Connecting NGINX to ModSecurity

Make sure you are on the correct folder path before proceeding:

cd /opt/nginx-1.14.0

Create a folder inside your nginx called _modules.

mkdir /etc/nginx/_modules

Copy ngx_https_modsecurity_module.so to the newly created folder.

cp objs/ngx_http_modsecurity_module.so /etc/nginx/_modules

The next thing to do is to modify your nginx.conf file located on /etc/nginx/nginx.conf.

nano /etc/nginx/nginx.conf

At the beginning you can see the following:

user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
        worker_connections 768;
        # multi_accept on;
}

All you have to to is insert load_module /etc/nginx/_modules/ngx_http_modsecurity_module.so after include /etc/nginx/modules-enabled/*.conf;

The settings will look like this:

user www-data;
worker_processes auto;
pid /run/nginx.pid;

include /etc/nginx/modules-enabled/*.conf;
load_module /etc/nginx/_modules/ngx_http_modsecurity_module.so;

events {
        worker_connections 768;
        # multi_accept on;
}

With this, ModSecurity for NGINX has been loaded.

6. Setting Up Configuration Files

Let’s go back to our /opt folder to setup a ruleset. Once you are on the folder we will clone another git from https://github.com/coreruleset/coreruleset.

cd /opt

You can do it by running the code below on our /opt folder.

git clone https://github.com/coreruleset/coreruleset modsecurity-crs

Get inside the folder by executing:

cd modsecurity-crs

Inside the folder you can the following folder:

CHANGES.md       CONTRIBUTORS.md         docs     KNOWN_BUGS.md  plugins    regex-assembly  SECURITY.md  tests
CONTRIBUTING.md  crs-setup.conf.example  INSTALL  LICENSE        README.md  rules           SPONSORS.md  util

You will have to rename crs-setup.conf.example to crs-setup.conf. You can do it by executing the following commands:

mv crs-setup.conf.example crs-setup.conf

We can now modify the rules. First we will modify the request exclusion rules.

mv rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf.example rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf

This will rename our request exclusion rules.

The next thing to do is to move it to the user local directory. First thing’s first, let’s go back into our /opt.

mv /opt/modsecurity-crs /usr/local

The now have the following folders in your local directory.
/usr/local/modsecurity
/usr/local/modsecurity-crs

Let’s create the folder for ModSecurity Configuration by executing the following commands:

mkdir -p /etc/nginx/modsec

The files that we need for the ModSecurity Configuration are unicode.mapping and mv modsecurity.conf-recommended. We will be replace mv modsecurity.conf-recommended to modsecurity.conf.

cp /opt/ModSecurity/unicode.mapping /etc/nginx/modsec/
mv /opt/ModSecurity/modsecurity.conf-recommended /opt/ModSecurity/modsecurity.conf
cp /opt/ModSecurity/modsecurity.conf /etc/nginx/modsec/

Your /etc/nginx/modsec will not look like this if you use ls.

modsecurity.conf  unicode.mapping

7. Setting Up Rules

Now that we are done with the setup of the files. What you need to understand is that you can configure ModSecurity.

You can see the configuration in /etc/nginx/modsec/modsecurity.conf which is the file that you have created before.

nano /etc/nginx/modsec/modsecurity.conf

The settings thing that you need to change is:

SecRuleEngine DetectionOnly

You have to set this to On therefore it will look like this:

SecRuleEngine On

This enables the security instead of just detecting it.

In addition to ModSecurity File we now need to create a main configuration file. Inside the /etc/nginx/modsec/ create a main configuration file. /etc/nginx/modsec/main.conf.

nano /etc/nginx/modsec/main.conf

Inside this the main configuration file. Add the following:

Include /etc/nginx/modsec/modsecurity.conf
Include /usr/local/modsecurity-crs/crs-setup.conf
Include /usr/local/modsecurity-crs/rules/*.conf

You directory should look like this once your run ls -alps

 4 drwxr-xr-x 2 root root  4096 Mar 17 11:28 ./
 4 drwxr-xr-x 9 root root  4096 Mar 16 23:11 ../
 4 -rw-r--r-- 1 root root   141 Mar 17 11:28 main.conf
12 -rw-r--r-- 1 root root 11187 Mar 17 11:22 modsecurity.conf
52 -rw-r--r-- 1 root root 53146 Mar 16 23:11 unicode.mapping

We are not done setting up all the files that we need.

7. Applying ModSecurity to Your Website

In order to apply ModSecurity to your website, you have to edit the sites-available configuration of your website.

For example we are going to modify our /etc/nginx/sites-available/default.

server {
        listen 50 default_server;
        listen [::]:50 default_server;

        root /var/www/test_bets;
        index index.html index.htm index.nginx-debian.html index.php;

        server_name _;

        location / {
                try_files $uri $uri/ =404;
        }

        location ~ \.php$ {
                include snippets/fastcgi-php.conf;
                fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
        }
}

In between, the root /var/www/test_bets and index index.html index.htm we must add the following:

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

Therefore it will look like this

server {
        listen 50 default_server;
        listen [::]:50 default_server;

        root /var/www/test_bets;
		
        modsecurity on;
		modsecurity_rules_file /etc/nginx/modsec/main.conf;
		
        index index.html index.htm index.nginx-debian.html index.php;

        server_name _;

        location / {
                try_files $uri $uri/ =404;
        }

        location ~ \.php$ {
                include snippets/fastcgi-php.conf;
                fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
        }
}

The last thing to do is to restart nginx and check if everything is working out correctly.

systemctl reload nginx
systemctl restart nginx

8. Additional Fixes

These are list of additional fixes that needs to be done based on experience.

sudo nano +435 /usr/local/modsecurity-crs/rules/REQUEST-932-APPLICATION-ATTACK-RCE.conf
sudo nano +77 /usr/local/modsecurity-crs/rules/RESPONSE-953-DATA-LEAKAGES-PHP.conf

Note: Comment the entire rules on line 435

If you didn’t see any error then everything is working out correctly.

8. How to test?

You can simple test if it’s working, using a simple CURL command.

curl http://<ip-address>/index.php?exec=/bin/bash

If it’s working correctly, you should get:

<html>

<head><title>403 Forbidden</title></head>

<body bgcolor="white">

<center><h1>403 Forbidden</h1></center>

<hr><center>nginx/1.14.0 (Ubuntu)</center>

</body>

</html>

This means that your malicious script was blocked by ModSecurity.

9. What are the use of ModSecurity

The module is configured to protect web applications from various attacks. ModSecurity supports flexible rule engine to perform both simple and complex operations. It comes with a Core Rule Set (CRS) which has various rules for: