Nginx, ModSecurity, IP Tables blocking WordPress dos/ddos attack

firewallmod-securitynginxSecurity

For the past 14 days I have had my website being hit by millions of WordPress installs over the world which .htaccess is kind of coping with but I am trying to get something to kick them before meeting htaccess. (RewriteCond %{HTTP_USER_AGENT} ^WordPress [NC,OR])

I tried to put some code in my nginx configuration to block wordpress user agents which made apache no be able to boot so I reverted the code.

This is the configuration:

user nobody;
#noneedformoreworkersintheproxymode
worker_processes  2;
error_log  /var/log/nginx/error.loginfo;
worker_rlimit_nofile 20480;

events {
   worker_connections 5120;#increaseforbusierservers
   useepoll;#youshoulduseepollhereforLinuxkernels 2.6.x
}

http {
    server_name_in_redirectoff;
    server_names_hash_max_size 10240;
    server_names_hash_bucket_size 1024;
    include   mime.types;
    default_type application/octet-stream;
    server_tokensoff;
    #remove/commentoutdisable_symlinksif_not_owner;ifyougetPermissiondeniederror
    #disable_symlinksif_not_owner;
    sendfileon;
    tcp_nopushon;
    tcp_nodelayon;
    keepalive_timeout  5;

    gzipon;
    gzip_varyon;
    gzip_disable "MSIE [1-6]\.";
    gzip_proxiedany;
    gzip_http_version 1.0;
    gzip_min_length  1000;
    gzip_comp_level  6;
    gzip_buffers  16 8k;

    fastcgi_buffers 8 16k;
    fastcgi_buffer_size 32k;
    fastcgi_connect_timeout 300;
    fastcgi_send_timeout 300;
    fastcgi_read_timeout 300;

    #Youcanremoveimage/pngimage/x-iconimage/gifimage/jpegifyouhaveslowCPU
    gzip_types   text/plaintext/xmltext/cssapplication/x-javascriptapplication/xmlapplication/javascriptapplication/xml+rsstext/javascriptapplication/atom+xml;
    ignore_invalid_headerson;

    client_header_timeout  3m;
    client_body_timeout 3m;
    send_timeout     3m;
    reset_timedout_connectionon;
    connection_pool_size  256;
    client_header_buffer_size 256k;
    large_client_header_buffers 4 256k;
    client_max_body_size 200M; 
    client_body_buffer_size 128k;
    request_pool_size  32k;
    output_buffers   4 32k;
    postpone_output  1460;
    proxy_temp_path  /tmp/nginx_proxy/;
    proxy_cache_path /var/cache/nginxlevels=1:2keys_zone=microcache:5mmax_size=1000m;
    client_body_in_file_onlyon;
    log_formatbytes_log "$msec $bytes_sent .";
    log_formatcustom_microcache '$remote_addr - $remote_user [$time_local] '
            '"$request" $status $body_bytes_sent '
            '"$http_referer" "$http_user_agent"nocache:$no_cache';
    include "/etc/nginx/vhosts/*";
}

We have Mod Security and this is the config.

http://pastebin.com/raw.php?i=Z5Lx3WkH (too long to insert)

Please can you tell me if you think you know how to block the WordPress user agent? It will help me out a ton. ModSecurity is currently blocking a few but not enough, 251+ IP's every second and they keep changing.

CentOS 6.5 converted to CloudLinux 6.5 x86_64

Best Answer

You can have iptables match a string contained in a packet.. that string could be the user-agent header.

The problem with that is that the HTTP request could span multiple packets. If that happens, it will do two things.. it will still hit your server, and it will establish the TCP connection, potentially thwarting your efforts to block the next request.

There are a few ways around this. One way is to require a User-agent in order to initially open the connection..

Consider something along the lines of the following:

# allow already established connections
iptables -A INPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT

# send brand new connections to the WORDPRESS chain
iptables -A INPUT -p tcp --dport 80 -m conntrack --ctstate NEW -j WORDPRESS

# drop everything else (ie INVALID or RELATED)
iptables -A INPUT -p tcp --dport 80 -j DROP


#### WORDPRESS chain. Only handles brand new connections to TCP 80

# drop anything with the offending user-agent
# optionally duplicate this line to bludgeon additional UAs
iptables -A WORDPRESS -m string --string "User-Agent: WordPress" --algo bm --to 65535 -j DROP

# allow that which has a user-agent. (that wasn't the offending ua)
iptables -A WORDPRESS -m string --string "User-Agent:" --algo bm --to 65535 -j ACCEPT

# drop that which has no user-agent, such as a 2nd packet within an HTTP request
# not a problem for legit traffic, since the first packet would have had a UA and
# thereby established the connection and avoided the whole WORDPRESS chain..
iptables -A WORDPRESS -j DROP

Of course, there are other approaches..

For instance: You could match the UA string, log and then drop. You could then feed the log into fail2ban. Etc..

Related Topic