Many users of nginx do not realize how easy it is to add a WAF (Web Application Firewall) to nginx and how powerful this simple tool is.

What is a WAF? A WAF is a layer of protection that lies between the user of your website and the service that is executing your website. That extra layer inspections http traffic looking for malicious code designed to make your application respond in ways it was not designed to do.

I’ll assume you already have nginx up and running, if you have not there are other resources to help with that. Let’s take a look at an open source product called “naxsi.” Straight from their github account: “NAXSI means Nginx Anti XSS & SQL Injection.”
In other words it stops 2 of the most common web attacks present today. Let’s get it installed and take a look at how to install and configure it.

sudo apt-get install nginx-naxsi

sudo yum install ulyaoth-nginx-naxsi

Other distros may require compiling it by hand.

Next enable loading of your rules in /etc/nginx/nginx.conf, on Ubuntu the line just needs to be uncommented:
include /etc/nginx/naxsi_core.rules;
So now we have the core ruleset loaded each of your virtualhosts can have a different ruleset. Edit your /etc/nginx/sites-enabled/<domain> and you can add your custom rules like this:

location / {
 # First attempt to serve request as file, then as directory, then fall back to displaying a 404.
 try_files $uri $uri/ =404;
 include /etc/nginx/naxsi.rules.mydomain;

Another technique which I prefer is using one per application. For example:
include /etc/nginx/naxsi.rules.wordpress;
include /etc/nginx/naxsi.rules.joomla;

Now let’s create these rulesets and learn some basics about Naxsi. Let’s copy the default ruleset into whichever method you chose above:
sudo cp /etc/nginx/naxsi.rules /etc/nginx/naxsi.rules.wordpress

Now let’s edit this file and go over it’s contents:

# Sample rules file for default vhost.

LearningMode; #Enables learning mode
SecRulesEnabled; #enables the checks
#SecRulesDisabled; #disables all checks
DeniedUrl "/RequestDenied"; #where to send bad traffic

## check rules
CheckRule "$SQL >= 8" BLOCK; #rules to check against and score logic
CheckRule "$RFI >= 8" BLOCK;
CheckRule "$TRAVERSAL >= 4" BLOCK;
CheckRule "$EVADE >= 4" BLOCK;
CheckRule "$XSS >= 8" BLOCK;

Now the important parts of this is the very top option “LearningMode;” and the CheckRule and scores.

As long as LearningMode is on, you’re not really securing anything what this is designed to do it log all the requests it was going to block instead of actually blocking them.

With wordpress you’ll see it doesn’t like some of the cookie data it uses to track the user’s activity and if you’re running the default ruleset you’ll start to see things like this in the error log:

/var/log/nginx/ 16:10:59 [error] 14597#0: *122 NAXSI_FMT: ip=, client:, server: *, request: "GET /wp-content/themes/iribbon/cyberchimps/lib/js/ HTTP/1.1", host: "", referrer: ""

Let’s break this down into it’s components:

/var/log/nginx/ 16:10:59 [error] 14597#0: *122 NAXSI_FMT: 
ip= //client or upstream (if behind load balancer/proxy) ip
& //your domain
&uri=/wp-content/themes/iribbon/cyberchimps/lib/js/ //path requested
&learning=1 //learning mode on or off
&total_processed=48 //number of rules that would have been blocked
&total_blocked=0 //this number increases when learning is off
&zone0=HEADERS //What part of the rule is causing the issue
&id0=1315 //Rule number
&var_name0=cookie, //What attribute specifically
client:, //More client information (if it can get it)
server: *, 
request: "GET /wp-content/themes/iribbon/cyberchimps/lib/js/ HTTP/1.1", host: "", referrer: ""

So here we see Rule number 1315, in the HEADERS zone, and variable cookie. Let’s take a look at /etc/nginx/naxsi_core.rules and see what that rule is:

> grep 1315 /etc/nginx/naxsi_core.rules
MainRule "rx:%[2|3]." "msg:double encoding !" "mz:ARGS|URL|BODY|$HEADERS_VAR:Cookie" "s:$XSS:8" id:1315;

As you can see there’s something getting double encoded. We can disable this single check since our application requires it to work for legitimate traffic. Ideally you would want to try to “fix” the issue without disabling any rules.

To disable this rule we can whitelist the whole rule or part of the rule, then we add it back above the CheckRule lines in our domain/app specific naxsi ruleset:

BasicRule wl:1315 "mz:$HEADERS_VAR:cookie";

Here “wl” stands for “whitelist” and “mz” is the zone we saw above in the error. If we had multiple issues with a specific rule and wanted to whitelist the entire rule the syntax would be simply:

BasicRule wl:1315;

The other option would be raising the score to >8 so it wouldn’t match the score immediately.

Goodluck! Feel free to leave a comment below with feedback and corrections.