您的位置:首页 > 运维架构 > Nginx

How to setup naxsi for nginx

2013-06-13 03:11 330 查看
This document describes the full process of configuring NAXSI.

Installing nginx + naxsi : From package

Packages of naxsi exist in official repositories for :

Debian
FreeBSD
NetBSD
OpenBSD

However, beware, naxsi is a young & fast evolving project, building from latest source code release is recommended.
If you plan to do so, refer to source compilation.

Installing nginx + naxsi : From sources

Nginx doesn't support (by design) loadable modules. Extra modules must be added during compilation. Here we will install it from the source, but (if you're lucky) you might as well find nginx+naxsi already packaged in your favorite distribution.
If you're not, here is the way to go :
wget http://nginx.org/download/nginx-x.x.xx.tar.gz wget http://naxsi.googlecode.com/files/naxsi-x.xx.tar.gz tar xvzf nginx-x.x.xx.tar.gz
tar xvzf naxsi-x.xx.tar.gz
cd nginx-x.x.xx/

[install libpcre (and libssl if you want https, along with zlib for gzip support) libs with your favorite package
manager, naxsi relies on it for regex]
./configure --add-module=../naxsi-x.xx/naxsi_src/ [add/remove your favorite/usual options]
make
make install

my personal "building" options being, here :
./configure --conf-path=/etc/nginx/nginx.conf  --add-module=../naxsi-x.xx/naxsi_src/   --error-log-path=/var/log/nginx/error.log     --http-client-body-temp-path=/var/lib/nginx/body     --http-fastcgi-temp-path=/var/lib/nginx/fastcgi     --http-log-path=/var/log/nginx/access.log     --http-proxy-temp-path=/var/lib/nginx/proxy     --lock-path=/var/lock/nginx.lock     --pid-path=/var/run/nginx.pid     --with-http_ssl_module     --without-mail_pop3_module     --without-mail_smtp_module     --without-mail_imap_module     --without-http_uwsgi_module     --without-http_scgi_module     --with-ipv6  --prefix=/usr

Important note for source compilation
You need to remember this if you are new to nginx : NGINX will decide the order of modules according the order of the module's directive in nginx's ./configure, take care not to have another similar module before.

Initial setup

I want to configure NAXSI for my company's website :
www.nbs-system.com
So, let's have a look at the initial setup :
/etc/nginx/nginx.conf :
user www-data;
worker_processes  1;
worker_rlimit_core  500M;
working_directory   /tmp/;

error_log  /var/log/nginx/error.log;
pid        /var/run/nginx.pid;

events {
worker_connections  1024;
use epoll;
# multi_accept on;
}

http {
include        /etc/nginx/naxsi_core.rules;
include       /etc/nginx/mime.types;
server_names_hash_bucket_size 128;
access_log  /var/log/nginx/access.log;

sendfile        on;
keepalive_timeout  65;
tcp_nodelay        on;

gzip  on;
gzip_disable "MSIE [1-6]\.(?!.*SV1)";
include /etc/nginx/sites-enabled/*;
}

Notice the /etc/nginx/naxsi_core.rules include. This file is provided in the project (naxsi_config/), and it contains the rules. As you might have noticed, these are not signatures, in the classic WAF sense, but simple "score rules".
Now, let's have a look at my sites-enabled/default :
server {
proxy_set_header Proxy-Connection "";
listen       *:80;
access_log  /tmp/nginx_access.log;
error_log  /tmp/nginx_error.log debug;

location / {
include    /etc/nginx/nbs.rules;
proxy_pass http://194.213.124.111/; proxy_set_header Host www.nbs-system.com;
}

#This location is where, in learning mode, to-be-forbidden requests will be "copied"
#In non-learning mode, it's where denied request will land, so feel free to do whatever you want,
#return 418 I'm a teapot, forward to a custom webpage with
#a captcha to help track false-positives (see contrib for that),
#whatever you want to do !
location /RequestDenied {
return 500;
}
}

/etc/nginx/nbs.rules :
LearningMode; #Enables learning mode
SecRulesEnabled;
#SecRulesDisabled;
DeniedUrl "/RequestDenied";

## check rules
CheckRule "$SQL >= 8" BLOCK;
CheckRule "$RFI >= 8" BLOCK;
CheckRule "$TRAVERSAL >= 4" BLOCK;
CheckRule "$EVADE >= 4" BLOCK;
CheckRule "$XSS >= 8" BLOCK;

Starting the LearningMode phase

While browsing your site, events will be generated by naxsi. But, as you are in learning mode, the requests wont be blocked. Those events are outputed in nginx's error_log.
Learning Daemons will be able to parse those events to extract whitelists and reports. (see nx_util)

Whitelist generation : Main goal of the daemon. From naxsi catched exceptions, generate appropriate whitelists. Rules are presented in raw form, as well as in optimized form. For example, after some browsing I got the following
rules :

########### Optimized Rules Suggestion ##################
# total_count:59 (23.69%), peer_count:1 (100.0%) | parenthesis, probable sql/xss
BasicRule wl:1011 "mz:$HEADERS_VAR:cookie";
# total_count:59 (23.69%), peer_count:1 (100.0%) | parenthesis, probable sql/xss
BasicRule wl:1010 "mz:$HEADERS_VAR:cookie";
# total_count:59 (23.69%), peer_count:1 (100.0%) | mysql keyword (|)
BasicRule wl:1005 "mz:$HEADERS_VAR:cookie";
# total_count:53 (21.29%), peer_count:1 (100.0%) | double encoding !
BasicRule wl:1315 "mz:$HEADERS_VAR:cookie";


Statistics generation : You can get reports on source / types of attacks, as well as counts for each kind of exceptions :





The global idea, indeed, is to use the whitelists generated by naxsi, include them into your naxsi's configuration, and then reload nginx.
For advanced whitelists, such as user forms, please see AdvancedWhitelists section. Following section deals as well with user
forms in a more classic way.

user forms

Now comes the "tricky" part of whitelists triggers : USER FORMS !
Yes, fields with 'free' user input, such as registration forms, search boxes and so on are typically parts that you should take a great care of.
For example, my company's website contains a "contact" form with lastname, firstname, email adress, and a free text zone. I decided that I will allow simple/double quotes as well as coma and semi-coma in the last/first names fields, and included
as well parenthesis for the free text zone. So, I will simply fill the form and learnign daemons will generate the associated whitelists.
Once I've filled the forms, if I look at the generated whitelists, I will see that new exceptions have been generated :
rule 1007(--) authorized on url for argument 'cf2_field_1' of zone BODY
rule 1010(() authorized on url for argument 'cf2_field_1' of zone BODY
rule 1011()) authorized on url for argument 'cf2_field_1' of zone BODY
rule 1013(') authorized on url for argument 'cf2_field_1' of zone BODY
rule 1015(,) authorized on url for argument 'cf2_field_1' of zone BODY
rule 1306(') authorized on url for argument 'cf2_field_1' of zone BODY
rule 1308(() authorized on url for argument 'cf2_field_1' of zone BODY
rule 1309()) authorized on url for argument 'cf2_field_1' of zone BODY
rule 1007(--) authorized on url for argument 'cf2_field_2' of zone BODY
rule 1013(') authorized on url for argument 'cf2_field_2' of zone BODY
rule 1015(,) authorized on url for argument 'cf2_field_2' of zone BODY
rule 1306(') authorized on url for argument 'cf2_field_2' of zone BODY
rule 1007(--) authorized on url for argument 'cf2_field_3' of zone BODY
rule 1013(') authorized on url for argument 'cf2_field_3' of zone BODY
rule 1015(,) authorized on url for argument 'cf2_field_3' of zone BODY
rule 1306(') authorized on url for argument 'cf2_field_3' of zone BODY
rule 1007(--) authorized on url for argument 'cf2_field_4' of zone BODY
rule 1007(--) authorized on url for argument 'cf2_field_5' of zone BODY
rule 1007(--) authorized on url for argument 'cf2_field_7' of zone BODY
rule 1010(() authorized on url for argument 'cf2_field_7' of zone BODY
rule 1011()) authorized on url for argument 'cf2_field_7' of zone BODY
rule 1013(') authorized on url for argument 'cf2_field_7' of zone BODY
rule 1015(,) authorized on url for argument 'cf2_field_7' of zone BODY
rule 1306(') authorized on url for argument 'cf2_field_7' of zone BODY
rule 1308(() authorized on url for argument 'cf2_field_7' of zone BODY
rule 1309()) authorized on url for argument 'cf2_field_7' of zone BODY
rule 1007(--) authorized on url for argument 'cf_codeerr2' of zone BODY
rule 1315() authorized on url for argument 'cf_codeerr2' of zone BODY
rule 1315() authorized on url for argument 'cf_failure2' of zone BODY
rule 1200(..) authorized on url for argument 'cf_working2' of zone BODY
rule 1315() authorized on url for argument 'cf_working2' of zone BODY

Let's reload it, and have a look at the generated whitelists ! New rules have been generated, in the style :
BasicRule wl:1007 "mz:$BODY_VAR:cf2_field_1" ;
BasicRule wl:1010 "mz:$BODY_VAR:cf2_field_1" ;
BasicRule wl:1011 "mz:$BODY_VAR:cf2_field_1" ;
BasicRule wl:1013 "mz:$BODY_VAR:cf2_field_1" ;
BasicRule wl:1015 "mz:$BODY_VAR:cf2_field_1" ;
BasicRule wl:1306 "mz:$BODY_VAR:cf2_field_1" ;
BasicRule wl:1308 "mz:$BODY_VAR:cf2_field_1" ;
BasicRule wl:1309 "mz:$BODY_VAR:cf2_field_1" ;
BasicRule wl:1007 "mz:$BODY_VAR:cf2_field_2" ;
BasicRule wl:1013 "mz:$BODY_VAR:cf2_field_2" ;
BasicRule wl:1015 "mz:$BODY_VAR:cf2_field_2" ;
BasicRule wl:1306 "mz:$BODY_VAR:cf2_field_2" ;
BasicRule wl:1007 "mz:$BODY_VAR:cf2_field_3" ;
BasicRule wl:1013 "mz:$BODY_VAR:cf2_field_3" ;
BasicRule wl:1015 "mz:$BODY_VAR:cf2_field_3" ;
BasicRule wl:1306 "mz:$BODY_VAR:cf2_field_3" ;
BasicRule wl:1007 "mz:$BODY_VAR:cf2_field_4" ;
BasicRule wl:1007 "mz:$BODY_VAR:cf2_field_5" ;
BasicRule wl:1007 "mz:$BODY_VAR:cf2_field_7" ;
BasicRule wl:1010 "mz:$BODY_VAR:cf2_field_7" ;
BasicRule wl:1011 "mz:$BODY_VAR:cf2_field_7" ;
BasicRule wl:1013 "mz:$BODY_VAR:cf2_field_7" ;
BasicRule wl:1015 "mz:$BODY_VAR:cf2_field_7" ;
BasicRule wl:1306 "mz:$BODY_VAR:cf2_field_7" ;
BasicRule wl:1308 "mz:$BODY_VAR:cf2_field_7" ;
BasicRule wl:1309 "mz:$BODY_VAR:cf2_field_7" ;
BasicRule wl:1007 "mz:$BODY_VAR:cf_codeerr2" ;
BasicRule wl:1315 "mz:$BODY_VAR:cf_codeerr2" ;
BasicRule wl:1315 "mz:$BODY_VAR:cf_failure2" ;
BasicRule wl:1200 "mz:$BODY_VAR:cf_working2" ;
BasicRule wl:1315 "mz:$BODY_VAR:cf_working2" ;

Once I've did the same for the searchbox, my configuration is now over, and we can browse the site, and fill the forms without generating any new exception !

Some side notes

Sometimes, you will want to partially disable naxsi for a part of the website. In the case of my company's website, I don't want to configure / enable naxsi for the wordpress back-office, as it's already protected by a .htaccess.
Then, you can "simply" define another location, where you don't enable NAXSI :
location / {
include    /etc/nginx/nbs.rules;
proxy_pass http://194.213.124.111/; proxy_set_header Host www.nbs-system.com;
}

location /wp-admin {
proxy_pass https://194.213.124.111/; proxy_set_header Host www.nbs-system.com;
}

And the trick is done ;)
Actually, you can do something way smarter. As wordpress is affected by numerous vulnerabilities in the back-office, I still want to protect it, but without spending too much time on the configuration, so here is what I'm doing :
location /wp-admin {
include /etc/nginx/nbs.rules;
BasicRule wl:0 mz:BODY;
proxy_pass https://194.213.124.111; proxy_set_header Host www.nbs-system.com;
}

I'm enabling NAXSI, but I'm disabling all checks on BODY, as it's the painfull part (posting HTML and so on). In this way, I will still protect WP back-office from vulnerabilities that are exploited through GET requests.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: