ModSecurity — based WAF implementation for Nginx
The following tutorial describes step-by-step how to deploy a Web Application Firewall based on ModSecurity, which has recently become available for Nginx. Note specifically that the procedure described here works for Nginx installed directly from the Ubuntu 20.04.4 LTS system repositories. Most tutorials are based on Nginx Plus, compiled Nginx or Nginx available from the official nginx repositories (not to be confused with the official system repositories).
- Install the required packages:
apt-get install -y apt-utils autoconf automake build-essential git libcurl4-openssl-dev libgeoip-dev liblmdb-dev libpcre++-dev libtool libxml2-dev libyajl-dev pkgconf wget zlib1g-dev
2. Clone ModSecurity repository:
cd ~
git clone --depth 1 -b v3/master --single-branch https://github.com/SpiderLabs/ModSecurity
3. Enter the Modsecurity directory and do source code compilation (this step can take around 20 minutes):
cd ModSecurity
git submodule init
git submodule update
./build.sh
./configure
make
make install
Ignore the warnings appearing during the compilation process:
fatal: No names found, cannot describe anything.
4. Clone ModSecurity Nginx Connector repository, which will be used as a dynamic module for Nginx:
git clone --depth 1 https://github.com/SpiderLabs/ModSecurity-nginx.git
5. Verify version of the currently installed Nginx:
nginx -v
In my case returned value is:
nginx version: nginx/1.18.0 (Ubuntu)
6. Download and extract the source code from here related with Nginx version installed on the server:
wget https://nginx.org/download/nginx-1.18.0.tar.gz
tar zxvf nginx-1.18.0.tar.gz
7. Enter the archive extracted in the step above and compile dynamic module:
cd nginx-1.18.0
./configure --with-compat --add-dynamic-module=../ModSecurity-nginx
make modules
8. When the compilation process will end, in the directory nginx-1.18.0/objs appears module with the extension “.so” → ngx_http_modsecurity_module.so.
9. Copy ngx_http_modsecurity_module.so to the path /usr/lib/nginx/modules and change it’s privileges from 755 to 644:
cp objs/ngx_http_modsecurity_module.so /usr/lib/nginx/modules
cd /usr/lib/nginx/modules
chmod 644 ngx_http_modsecurity_module.so
10. In the path /usr/share/nginx/modules-available create a file mod-http-modsecurity.conf add the appropriate line in it:
cd /usr/share/nginx/modules-available
echo "load_module modules/ngx_http_modsecurity_module.so;" > mod-http-modsecurity.conf
11. In the path /etc/nginx/modules-enabled create a symbolic link to the config file available in /usr/share/nginx/modules-available:
ln -s /usr/share/nginx/modules-available/mod-http-modsecurity.conf /etc/nginx/modules-enabled/50-mod-http-modsecurity.conf
12. Create a modsec directory in the path /etc/nginx/conf.d and place in it the configuration file found in the ModSecurity repo downloaded at the very beginning (you can also download it with the wget command directly from the repo as described below):
mkdir -p /etc/nginx/conf.d/modsec
wget -P /etc/nginx/conf.d/modsec https://raw.githubusercontent.com/SpiderLabs/ModSecurity/v3/master/modsecurity.conf-recommended
13. Rename the downloaded file by deleting the “-recommended” suffix:
mv /etc/nginx/conf.d/modsec/modsecurity.conf-recommended /etc/nginx/conf.d/modsec/modsecurity.conf
14. To ensure that ModSecurity is able to find the unicode.mapping file, copy it to the modsec folder we created earlier:
cp ~/ModSecurity/unicode.mapping /etc/nginx/conf.d/modsec
15. Change the detection mode to block unwanted traffic (the command finds the phrase “SecRuleEngine DetectionOnly” and changes it to “SecRuleEngine On” in the file given as a parameter):
sed -i 's/SecRuleEngine DetectionOnly/SecRuleEngine On/' /etc/nginx/conf.d/modsec/modsecurity.conf
16. On a production server, use the OWASP package. Download and extract it:
wget https://github.com/coreruleset/coreruleset/archive/refs/tags/v3.3.2.tar.gz
tar zxvf v3.3.2.tar.gz
17. Move the rules package to the ModSecurity configuration directory and create the crs-setup.conf file as a copy of crs-setup.conf.example:
mv coreruleset-3.3.2/ /etc/nginx/conf.d/modsec/
cd /etc/nginx/conf.d/modsec/coreruleset-3.3.2
cp crs-setup.conf.example crs-setup.conf
18. Enter to /etc/nginx/conf.d/modsec/coreruleset-3.3.2/rules and change the names for two rules (remove the “.example” suffix):
cd /etc/nginx/conf.d/modsec/coreruleset-3.3.2/rules
mv REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf.example REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf
mv RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf.example RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf
19. In the /etc/nginx/conf.d/modsec/main.conf file, add the following directives (deployment on the server with Prestashop and Wordpress):
# OWASP CRS v3 rules
# https://coreruleset.org/installation/Include /etc/nginx/conf.d/modsec/modsecurity.conf
Include /etc/nginx/conf.d/modsec/coreruleset-3.3.2/crs-setup.conf
Include /etc/nginx/conf.d/modsec/coreruleset-3.3.2/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf
Include /etc/nginx/conf.d/modsec/coreruleset-3.3.2/rules/REQUEST-901-INITIALIZATION.conf
Include /etc/nginx/conf.d/modsec/coreruleset-3.3.2/rules/REQUEST-903.9002-WORDPRESS-EXCLUSION-RULES.conf
Include /etc/nginx/conf.d/modsec/coreruleset-3.3.2/rules/REQUEST-905-COMMON-EXCEPTIONS.conf
Include /etc/nginx/conf.d/modsec/coreruleset-3.3.2/rules/REQUEST-910-IP-REPUTATION.conf
Include /etc/nginx/conf.d/modsec/coreruleset-3.3.2/rules/REQUEST-911-METHOD-ENFORCEMENT.conf
Include /etc/nginx/conf.d/modsec/coreruleset-3.3.2/rules/REQUEST-912-DOS-PROTECTION.conf
Include /etc/nginx/conf.d/modsec/coreruleset-3.3.2/rules/REQUEST-913-SCANNER-DETECTION.conf
Include /etc/nginx/conf.d/modsec/coreruleset-3.3.2/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf
Include /etc/nginx/conf.d/modsec/coreruleset-3.3.2/rules/REQUEST-921-PROTOCOL-ATTACK.conf
Include /etc/nginx/conf.d/modsec/coreruleset-3.3.2/rules/REQUEST-930-APPLICATION-ATTACK-LFI.conf
Include /etc/nginx/conf.d/modsec/coreruleset-3.3.2/rules/REQUEST-931-APPLICATION-ATTACK-RFI.conf
Include /etc/nginx/conf.d/modsec/coreruleset-3.3.2/rules/REQUEST-932-APPLICATION-ATTACK-RCE.conf
Include /etc/nginx/conf.d/modsec/coreruleset-3.3.2/rules/REQUEST-933-APPLICATION-ATTACK-PHP.conf
Include /etc/nginx/conf.d/modsec/coreruleset-3.3.2/rules/REQUEST-934-APPLICATION-ATTACK-NODEJS.conf
Include /etc/nginx/conf.d/modsec/coreruleset-3.3.2/rules/REQUEST-941-APPLICATION-ATTACK-XSS.conf
Include /etc/nginx/conf.d/modsec/coreruleset-3.3.2/rules/REQUEST-942-APPLICATION-ATTACK-SQLI.conf
Include /etc/nginx/conf.d/modsec/coreruleset-3.3.2/rules/REQUEST-943-APPLICATION-ATTACK-SESSION-FIXATION.conf
Include /etc/nginx/conf.d/modsec/coreruleset-3.3.2/rules/REQUEST-949-BLOCKING-EVALUATION.conf
Include /etc/nginx/conf.d/modsec/coreruleset-3.3.2/rules/RESPONSE-950-DATA-LEAKAGES.conf
Include /etc/nginx/conf.d/modsec/coreruleset-3.3.2/rules/RESPONSE-951-DATA-LEAKAGES-SQL.conf
Include /etc/nginx/conf.d/modsec/coreruleset-3.3.2/rules/RESPONSE-952-DATA-LEAKAGES-JAVA.conf
Include /etc/nginx/conf.d/modsec/coreruleset-3.3.2/rules/RESPONSE-953-DATA-LEAKAGES-PHP.conf
Include /etc/nginx/conf.d/modsec/coreruleset-3.3.2/rules/RESPONSE-954-DATA-LEAKAGES-IIS.conf
Include /etc/nginx/conf.d/modsec/coreruleset-3.3.2/rules/RESPONSE-959-BLOCKING-EVALUATION.conf
Include /etc/nginx/conf.d/modsec/coreruleset-3.3.2/rules/RESPONSE-980-CORRELATION.conf
Include /etc/nginx/conf.d/modsec/coreruleset-3.3.2/rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf
20. In the rule file REQUEST-941-APPLICATION-ATTACK-XSS.conf, add REQUEST_URI in rules with id 941160 and 941320 as shown below:
SecRule REQUEST_URI|REQUEST_COOKIES|!REQUEST_COOKIES [..]
21. Create snippet /etc/nginx/snippets/waf.conf and put inside:
modsecurity on;
modsecurity_rules_file /etc/nginx/conf.d/modsec/main.conf;
22. Include above snippet in the http {} block in /etc/nginx/nginx.conf using (put “modsecurity off;” inside specific vhost file in the server {} block if you want to disable WAF for this vhost):
http {
# ...
include snippets/waf.conf;
}
23. Check and reload Nginx config:
nginx -t
systemctl reload nginx.service
24. A line similar to the following will appear in the log file:
2022/10/05 10:52:10 [notice] 4070583#4070583: ModSecurity-nginx v1.0.3 (rules loaded inline/local/remote: 0/728/0)
25. Finally, delete repositories and downloaded files that are no longer needed:
rm -r ~/ModSecurity
rm -r ~/ModSecurity-nginx
rm -r ~/nginx-1.18.0
rm ~/nginx-1.18.0.tar.gz
26. Above step is the last step in case of general configuration, but it can be required adjusting the rules. For example Prestashop, to be fully operable from frontend and backoffice, requires some modification in the file /etc/nginx/conf.d/modsec/coreruleset-3.3.2/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf:
SecRule REQUEST_FILENAME "@beginsWith /admin-directory/index.php" \
"id:1004,\
phase:2,\
pass,\
nolog,\
ctl:ruleRemoveById=921110,\
ctl:ruleRemoveById=932100,\
ctl:ruleRemoveById=932105,\
ctl:ruleRemoveById=932110,\
ctl:ruleRemoveById=932130,\
ctl:ruleRemoveById=932150,\
ctl:ruleRemoveById=941100,\
ctl:ruleRemoveById=941130,\
ctl:ruleRemoveById=941160,\
ctl:ruleRemoveById=941180,\
ctl:ruleRemoveById=941310,\
ctl:ruleRemoveById=951220"
SecRule REQUEST_URI "@beginsWith /" \
"id:1005,\
phase:2,\
pass,\
nolog,\
ctl:ruleRemoveById=953120,\
ctl:ruleRemoveById=953100"
If you require to update Nginx and thus update the security module, follow the steps below to disable the current version of the module:
- Comment out the content of the file:
/etc/nginx/snippets/waf.conf
2. Remove the existing ngx_http_modsecurity_module.so module from the /usr/share/nginx/modules path:
cd /usr/share/nginx/modules
rm ngx_http_modsecurity_module.so
3. Remove the 50-mod-http-modsecurity.conf symbolic link from the /etc/nginx/modules-enabled path:
cd /etc/nginx/modules-enabled
rm 50-mod-http-modsecurity.conf
4. Only then can you start the upgrade process (follow steps 1–11 from this guide).