ModSecurity
ModSecurity is a web application firewall with a long history, originally designed for Apache (the project was started before nginx was even around).
What's an application firewall? ModSecurity looks at every request that comes through nginx. If it meets certain parameters, (defined by the OWASP core rule set), the request is immediately denied with a 403 error.
ModSecurity 3, released a few years ago, has been adapting itself from an apache module to a server-independent library - libmodsecurity. I'm setting this up for an Ubuntu 18.04 server, but the steps will be similar for any Unix system. Ubuntu 20.04 provides a libmodsecurity3 package. So, I can take advantage of that when I'm on Ubuntu 20, but even then I'll still have to compile my own nginx module to connect this to nginx.
Here are the pieces you need to get ModSecurity working with nginx:
libmodsecurity
libmodsecurity itself. Compiled from https://github.com/SpiderLabs/ModSecurity/, synonymous with "ModSecurity".
ModSecurity-nginx
The nginx module. Compiled from https://github.com/SpiderLabs/ModSecurity-nginx/.
In order to compile this, you need to download
the nginx
source code at the right version (in our case,
1.14.0). The configure flags passed during the
configure step must also match those that our
version of nginx was compiled with, by Ubuntu (You
get these with nginx -V
), or use
the --with-compat
flag.
From the nginx source directory:
./auto/configure --add-module=/path/to/ModSecurity-nginx --with-compat
OWASP coreruleset
Some of these rules require libmodsecurity to be compiled with certain library support. For example, the geolocation rules require a libmodsecurity with either GeoIP or MaxMind enabled. These are IP location databases. We're currently using GeoIP. I had an issue with MaxMind - the version that Ubuntu 18 provides is too old for ModSecurity.
Connecting everything together
All these pieces are connected with these configuration files:
- /etc/nginx/nginx.conf: This file needs to load the modsecurity nginx module, and turn
modsecurity on
, and setmodsecurity_rules_file /etc/nginx/modsecurity/main.conf
- /etc/nginx/modsecurity/main.conf: This file loads
/etc/nginx/modsecurity/modsecurity.conf
along with the core ruleset files. It's pretty simple, and here's an example:
# From https://github.com/SpiderLabs/ModSecurity/blob/master/ # modsecurity.conf-recommended # # Edit to set SecRuleEngine On Include "/etc/nginx/modsecurity/modsecurity.conf" Include "/etc/nginx/modsecurity/coreruleset/crs-setup.conf" Include "/etc/nginx/modsecurity/coreruleset/rules/*.conf" # Basic test rule SecRule ARGS:testparam "@contains test" "id:1234,deny,status:403"
After restarting nginx, if everything's working as
expected, you should see the following line
in /var/log/nginx/error.log
after
nginx starts up:
2020/05/21 12:08:51 [notice] 6362#6362: ModSecurity-nginx v1.0.1 \ (rules loaded inline/local/remote: 0/907/0)
Note that 907 local rules were loaded here, that's
from the OWASP ruleset. Because of the test rule
in
main.conf
, you can also test this by
making a request to your server with the GET param
?testparam=test
. That request should
be denied with a 403 error.
Now, take a look
in /var/log/modsec_audit.log
and /var/log/nginx/error.log
. There
will be lots of interesting info in these files as
requests are blocked by ModSecurity. You might
need to tune your new firewall if you're seeing
false positives — I'm still learning about
that process, and I'll have another post
documenting that.