ModSecurity is a powerful open-source Web Application Firewall (WAF) designed to enhance security and protect websites from various cyber threats. However, protection is not provided by the service alone. It needs a set of regulations in order to operate properly.
One well-known and reliable WAF ruleset is the OWASP CRS (Core Rule Set). OWASP, which stands for Open Web Application Security Project, is a globally recognized nonprofit organization that focuses on improving the security of web applications.
These regulations are adept at spotting possible attacks and averting them, serving as a strong defense against the majority of modern online threats.
The following documentation describes the process of implementing Nginx with ModSecurity and OWASP CRS on Debian 13 (trixie) servers, how to create a Whitelist for ModSecurity and the process of updating each component individually.
Table of contents:
- Installation
- 1. Installing NGINX and the required packages
- 2. Importing NGINX Source Code
- 3. Installing libmodsecurity3
- 4. Installing ModSecurity-nginx Connector
- 5. Installing ModSecurity 3 Dynamic Module
- 6. Enabling ModSecurity-nginx Connector
- 7. Installing OWASP CRS within ModSecurity
- 8. Verifying the Configuration and Rebooting Nginx
- 9. Setting up Logs Rotation for ModSecurity
- ModSecurity Whitelists
- Updating Nginx
- Updating ModSecurity
- Updating OWASP CRS
- Bibliography
Installation
Notes:
Before proceeding with the documentation, the system should be updated.
The following commands should be executed by the root user.
If Nginx is already installed on the server, it is recommended to remove it before installing the latest version from the official Nginx Linux packages.
1. Installing NGINX and the required packages
The process begins with the installation of the following required packages.
apt install curl gnupg2 ca-certificates lsb-release debian-archive-keyring -y
Next, the following commands should be run to import the official Nginx APT repository.
curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor | tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
printf "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] https://nginx.org/packages/mainline/debian trixie nginx\ndeb-src [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] https://nginx.org/packages/mainline/debian trixie nginx" | tee /etc/apt/sources.list.d/nginx.list
echo -e "Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n" | tee /etc/apt/preferences.d/99nginx
The last command sets a higher priority for the Nginx packages from nginx.org, ensuring they are preferred over the default Debian repository packages.
Next, the APT sources should be modernized, the APT cache should be refreshed, and Nginx along with the remaining required packages should be installed.
apt modernize-sources -y
apt update
apt install nginx dpkg-dev gcc make build-essential autoconf automake libtool libcurl4-openssl-dev liblua5.3-dev libfuzzy-dev ssdeep gettext pkg-config libxml2 libxml2-dev libcurl4 libgeoip-dev libyajl-dev doxygen libpcre2-16-0 libpcre2-dev libpcre2-posix3 -y
If Nginx was previously installed on the server, during installation, a prompt asking to replace or keep the current /etc/nginx/nginx.conf configuration file may appear. It’s advised to save the current configuration file by pressing n in order to prevent any unplanned disruptions.
2. Importing NGINX Source Code
For ModSecurity and Nginx to be perfectly integrated, the ModSecurity dynamic module must be compiled using the Nginx source code. The following commands should be executed to create the directory that will store the Nginx source code and to download the code.
mkdir /usr/local/src/nginx
cd /usr/local/src/nginx
apt source nginx
To make sure the source code downloaded matches the current Nginx version installed on the server, the following commands should be executed.
ls
nginx -v
It is essential that both versions are the same in order to compile the ModSecurity module.
3. Installing libmodsecurity3
libmodsecurity3 serves as the foundation of ModSecurity’s powerful WAF. The source code for libmodsecurity3 should be downloaded from its GitHub repository [1] using Git.
git clone --depth 1 -b v3/master --single-branch https://github.com/owasp-modsecurity/ModSecurity /usr/local/src/ModSecurity/
cd /usr/local/src/ModSecurity/
Next, the following commands should be executed to initialize and update the Git submodules and to build/configure the ModSecurity environment.
git submodule init
git submodule update
./build.sh
./configure
An error message saying fatal: No names found, cannot describe anything may appear during the configuration. This error message can be ignored.
Lastly, the following commands should be executed to compile the source code and to install it.
make -j $(nproc)
make install
4. Installing ModSecurity-nginx Connector
ModSecurity-nginx is the essential mediator between ModSecurity and the widely-used Nginx web server. The following command should be executed to clone the ModSecurity-nginx repository [2].
git clone --depth 1 https://github.com/owasp-modsecurity/ModSecurity-nginx.git /usr/local/src/ModSecurity-nginx/
Next, it is necessary to navigate to the Nginx source directory and execute the following commands to install the required dependencies for the ModSecurity-nginx connector.
cd /usr/local/src/nginx/nginx-1.*.*
apt build-dep nginx -y
apt install uuid-dev -y
To build the ModSecurity-nginx connector environment and generate the dynamic modules, the following commands must be executed.
./configure --with-compat --add-dynamic-module=/usr/local/src/ModSecurity-nginx
make modules
5. Installing ModSecurity 3 Dynamic Module
The final step of the setup process is to move the dynamic module generated by the previous steps into the /etc/nginx/modules/ directory.
mkdir -p /etc/nginx/modules/
cp objs/ngx_http_modsecurity_module.so /etc/nginx/modules/
6. Enabling ModSecurity-nginx Connector
After the successful configuration of the ModSecurity-nginx connector, the next step is to load it into Nginx. In order to do so, the file /etc/nginx/nginx.conf must be edited. Ensure it contains the following configuration.
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /run/nginx.pid;
load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;
events {
worker_connections 1024;
}
http {
modsecurity on;
modsecurity_rules_file /etc/nginx/modsec/modsec-config.conf;
sendfile on;
tcp_nopush on;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
ssl_protocols TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
access_log /var/log/nginx/access.log;
gzip on;
gzip_proxied any;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Referrer-Policy "strict-origin";
add_header X-XSS-Protection "1; mode=block" always;
add_header Content-Security-Policy "default-src 'self'" always;
include /etc/nginx/conf.d/*.conf;
}
The ModSecurity-nginx connector is loaded via the following directive.
load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;
Inside the http block, these directives enable ModSecurity and specify the location of its rules file.
modsecurity on;
modsecurity_rules_file /etc/nginx/modsec/modsec-config.conf;
Next, it’s required to create a dedicated directory in order to hold the configuration files and rules.
mkdir /etc/nginx/modsec/
The example of ModSecurity configuration file should be copied into the newly created directory from the cloned ModSecurity Git repository.
cp /usr/local/src/ModSecurity/modsecurity.conf-recommended /etc/nginx/modsec/modsecurity.conf
Next, the /etc/nginx/modsec/modsecurity.conf file should be edited in order to modify the ModSecurity rules.
By default, the ModSecurity rule engine operates in DetectionOnly mode, which logs malicious activity without blocking it. To change this behavior, the line starting with SecRuleEngine should be located, and DetectionOnly should be replaced with On.
After that, the SecAuditLogParts line should be identified.
SecAuditLogParts ABIJDEFHZ
The line should be adjusted as follows:.
SecAuditLogParts ABCEFHJKZ
Save and exit the file.
The next step is to create the /etc/nginx/modsec/modsec-config.conf file. This file will contain the modsecurity.conf file along with additional rulesets like the OWASP CRS.
The following content must be copied into the file.
Include /etc/nginx/modsec/modsecurity.conf
Include /etc/nginx/modsec/coreruleset-4.23.0/crs-setup.conf
Include /etc/nginx/modsec/coreruleset-4.23.0/rules/*.conf
Lastly, replicate ModSecurity’s unicode.mapping file.
cp /usr/local/src/ModSecurity/unicode.mapping /etc/nginx/modsec/
7. Installing OWASP CRS within ModSecurity
The following commands should be executed in order to apply the OWASP CRS for ModSecurity to strengthen the security of the web server.
cd /etc/nginx/modsec
wget https://github.com/coreruleset/coreruleset/archive/refs/tags/v4.23.0.tar.gz
tar -xvf v4.23.0.tar.gz
rm -r v4.23.0.tar.gz
cp /etc/nginx/modsec/coreruleset-4.23.0/crs-setup.conf.example /etc/nginx/modsec/coreruleset-4.23.0/crs-setup.conf
8. Verifying the Configuration and Rebooting Nginx
The following commands must be executed to verify the configuration and to enable/restart Nginx.
nginx -t
systemctl enable nginx
systemctl restart nginx
Expected output:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
9. Setting up Logs Rotation for ModSecurity
In order to implement log rotation mechanism for ModSecurity the file /etc/logrotate.d/modsec must be created and the following content added into it.
/var/log/modsec_audit.log
{
rotate 31
daily
missingok
compress
delaycompress
notifempty
}
Then, the following command needs to be executed to validate the logs rotation.
logrotate -d /etc/logrotate.d/modsec
ModSecurity Whitelists
In ModSecurity, a whitelist (also known as an allowlist) is a list of approved exceptions. These exceptions are normally defined when false positives are being generated by the rulesets, affecting the expected behavior of the website.
In order to create a whitelist, the Nginx and ModSecurity logs should be analyzed to identify the rule IDs responsible for false positives and the corresponding affected request paths.
Then, a new file with the .conf extension should be created in the /etc/nginx/modsec/ directory.
Inside the file, the previously created ModSecurity rule file should be included in order to load the default ModSecurity and OWASP rule set, and a new custom rule with an ID greater than 1000000 should be defined. The rule will instruct ModSecurity to disable specific rules that generate false positives for the paths identified in the analysis.
An example of this can be seen in the following code.
Include /etc/nginx/modsec/modsec-config.conf
SecRule REQUEST_URI "@contains /wp-admin/" \
"id:1000200,phase:1,nolog,pass,\
ctl:ruleRemoveById=920350,\
ctl:ruleRemoveById=920280"
Once the whitelist has been created, it can be implemented for the entire web server or only for a specific vhost (Virtual Host).
To implement the whitelist for the entire web server, the file /etc/nginx/nginx.conf must be edited and the following line located.
modsecurity_rules_file /etc/nginx/modsec/modsec-config.conf;
The line should be changed to include the whitelist, ensuring that the file name is updated accordingly.
modsecurity_rules_file /etc/nginx/modsec/<filename>.conf;
To implement the whitelist for a specific vhost, inside /etc/nginx/nginx.conf, the original ModSecurity rule file should be removed.
Then, for the specific vhost, the whitelist should be added inside the corresponding server block.
An example of this can be seen in the following code.
server {
...
modsecurity_rules_file /etc/nginx/modsec/<filename>.conf;
...
}
For the remaining vhost, inside their respective server block, the original ModSecurity rule file should be added.
The whitelist can also be implemented on specific location blocks.
Instead of defining the modsecurity_rules_file in the server block, it should be defined inside the respective location block. For the remaining locations, the original ModSecurity rule file should be added.
An example of this can be seen in the following code.
server {
...
location /a/ {
modsecurity_rules_file /etc/nginx/modsec/modsec-config.conf;
...
}
location /b/ {
modsecurity_rules_file /etc/nginx/modsec/<filename>.conf;
...
}
}
Lastly, restart Nginx to implement the changes.
systemctl restart nginx.service
Updating Nginx
In order to implement ModSecurity with Nginx, it’s necessary to compile the ModSecurity-nginx Connector for the version of Nginx installed on the system. When updates are available for Nginx, it is necessary to recompile the Connector afther the upgrade.
To ensure that no errors are triggered during the update, the /etc/nginx/nginx.conf file must be edited, and all lines referencing modsecurity should be commented out.
The service should be restarted, and the system update should be carried out. Once the update is complete, the following commands should be executed.
rm -r /usr/local/src/nginx
rm -r /usr/local/src/ModSecurity-nginx/
Next, steps 2, 4, 5 and 6 should be executed to recompile the ModSecurity-nginx Connector.
Finally, the Nginx service should be restarted.
systemctl restart nginx.service
Updating ModSecurity
In order to update ModSecurity, the following commands must be executed. The process should begin by removing the currently installed version of libmodsecurity3 from the system.
rm -r /usr/local/src/ModSecurity/
Then, step 3 should be re-executed to install the updated ModSecurity environment. Next, the following command should be executed to copy the example ModSecurity configuration file into the /etc/nginx/modsec/ directory.
cp /usr/local/src/ModSecurity/modsecurity.conf-recommended /etc/nginx/modsec/modsecurity.conf
The ModSecurity unicode.mapping file should be replicated.
cp /usr/local/src/ModSecurity/unicode.mapping /etc/nginx/modsec/
Finally, Nginx should be restarted.
systemctl restart nginx.service
Updating OWASP CRS
The official OWASP CRS GitHub repository [3] should be consulted to check whether a new release is available. If a new release is available, the following commands should be executed to delete the current ruleset used by ModSecurity on the system.
cd /etc/nginx/modsec/
rm -r coreruleset-*
Step 7 should be re-executed to download the new release. The commands must be updated to reflect the new release version.
Next, the /etc/nginx/modsec/modsec-config.conf file should be edited to update the release version accordingly.
Include /etc/nginx/modsec/coreruleset-x.y.z/crs-setup.conf
Include /etc/nginx/modsec/coreruleset-x.y.z/rules/*.conf
Finally, Nginx must be restarted in order to load the updated ruleset.
systemctl restart nginx.service