2015年11月5日木曜日

Mitigating DDoS Attacks nginx with module

nginx module of ngx_http_limit_conn_module and ngx_http_limit_req_module has resistant to DDoS attack.
This nginx modules will provides regulating the incoming HTTP/S traffic and controlling the traffic as it is proxied to backend servers.
This is native nginx module. so settings is easy and performance is nice. If you want to anti DDoS system easily, maybe this solution is good for you.

Let's Try.

HTTP Connection limit
http://nginx.org/en/docs/http/ngx_http_limit_conn_module.html

Set zone name of shared memory and maximum size of this zone.
http {
    # memory limit for number of connections
    limit_conn_zone $remote_addr zone=connection_limit_per_ip:10m;
Allow 10 connection per an IP address at a time.
server {
    # connection limit
    limit_conn connection_limit_per_ip 30;

Let's Check.

Connection number is 10.
It's no Failed.
# ab -c 10 -n 100000 http://127.0.0.1/
Complete requests:      100000
Failed requests:        0
Connection number is 100.
It has Failed.
# ab -c 100 -n 100000 http://127.0.0.1/
Complete requests:      100000
Failed requests:        11866

HTTP request limit
http://nginx.org/en/docs/http/ngx_http_limit_req_module.html

Allow 100 request per an IP address at a one secound.
http {
    # memory limit for number of requests
    limit_req_zone $remote_addr zone=request_limit_per_ip:10m rate=100r/s;
Sets the maximum burst size of requests.
For example, when request is over the 100r/s, max number of connection will be 10.
If you want to no
server {
    # request limit
    limit_req zone=request_limit_per_ip burst=10;

Let's Check.

Connection number is 10. burst=10.
It has no failed. but it has delay.
Time taken for tests is long.
# ab -c 10 -n 1000 http://127.0.0.1/
Time taken for tests:   10.365 seconds
Complete requests:      1000
Failed requests:        0
# grep delay /var/log/nginx/error.log
2015/11/05 15:06:18 [warn] 8595#0: *999 delaying request, excess: 9.700, by zone "request_limit_per_ip", client: 127.0.0.1, server: localhost, request: "GET / HTTP/1.0", host: "127.0.0.1"
2015/11/05 15:06:18 [warn] 8595#0: *1000 delaying request, excess: 9.700, by zone "request_limit_per_ip", client: 127.0.0.1, server: localhost, request: "GET / HTTP/1.0", host: "127.0.0.1"

Connection number is 10. burst=9.
It has failed and delay.
Time taken for tests is short. because many requests has faild.
# ab -c 10 -n 1000 http://127.0.0.1/
Time taken for tests:   0.231 seconds
Complete requests:      1000
Failed requests:        954
# grep delay /var/log/nginx/error.log
2015/11/05 15:07:06 [warn] 8652#0: *912 delaying request, excess: 9.000, by zone "request_limit_per_ip", client: 127.0.0.1, server: localhost, request: "GET / HTTP/1.0", host: "127.0.0.1"
2015/11/05 15:07:06 [warn] 8652#0: *961 delaying request, excess: 9.000, by zone "request_limit_per_ip", client: 127.0.0.1, server: localhost, request: "GET / HTTP/1.0", host: "127.0.0.1"

Connection number is 10. burst=10 nodelay.
If you want to no delay, you can add nodelay opetion.
# ab -c 10 -n 1000 http://127.0.0.1/
Time taken for tests:   0.204 seconds
Complete requests:      1000
Failed requests:        969
# grep delay /var/log/nginx/error.log
Nothing delay.

Exsample Settings of nginx conf
http {
    # Amazon ELB (VPC) 
    set_real_ip_from 172.16.0.0;
    real_ip_header     X-Forwarded-For;

    # memory limit for number of connections
    limit_conn_zone $remote_addr zone=connection_limit_per_ip:10m;

    # memory limit for number of requests
    limit_req_zone $remote_addr zone=request_limit_per_ip:10m rate=1000r/s;

server {
    # connection limit
    limit_conn connection_limit_per_ip 100;

    # request limit
    limit_req zone=request_limit_per_ip burst=10;


nginx logo from NGINX Newsroom - NGINX