Scott Wiersdorf (scott@perlcode.org)
Wed Nov 19 01:01:14 MST 2003
$Id: attacks.html,v 1.7 2005/09/02 21:41:14 scott Exp $

DOS got you down?

Sometimes disgruntled individuals wish to "take down" your web site by flooding it with bogus traffic from Windows PCs they've compromised, causing your server to deny service to legitimate traffic because of the increased load on your web server (this is "DOS"--denial of service).

This document describes a couple of simple, lightweight, and efficient ways (using mod_rewrite) you as an Apache admin can redirect this illegitimate traffic elsewhere and keep your site available to regular requests.

mod_rewrite is an efficient and flexible Apache module which allows you to perform URL rewriting dynamically.

Blocking requests based on request characteristics

You can block requests based on certain characteristics by adding this to your httpd.conf in the appropriate virtualhost section:

  LoadModule rewrite_module modules/mod_rewrite.so

  ...

  <IfModule mod_rewrite.c>
    RewriteEngine   on
    RewriteCond     %{HTTP_REFERER}    ^$
    RewriteCond     %{HTTP_USER_AGENT} ^$
    RewriteCond     %{REQUEST_URI}     ^/$
    RewriteRule     ^/.*     http://%{REMOTE_ADDR}/      [L,E=nolog:1]
  </IfModule>

  LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
  CustomLog   logs/access_log-www.mydomain.com combined env=!nolog
The mod_rewrite directives above will block requests that meet the following three criteria:

You should change these to match the characteristics of your attack. For example, if your attackers have a specific user agent set (e.g., Mozilla or IE, etc.), you should supply that instead. The net effect is this:

Blocking based on IP

You can also block (or admit) users based on their incoming IP address:
  <IfModule mod_rewrite.c>
    RewriteEngine   on
    RewriteMap      block dbm:/www/conf/my.block
    RewriteCond     ${block:%{REMOTE_ADDR}|OK}           !^OK$
    RewriteRule     ^/.*     http://%{REMOTE_ADDR}/      [L]
  </IfModule>

You create my.block.db from a file (named blocklist) that looks like this:

    123.123.123.123    block
    123.123.123.134    block
    321.321.321.222    block
    ...

and piping it to this file:

You can add additional entries on the fly:

Allow-lists

Changing this to an "allow" list works like this:
  <IfModule mod_rewrite.c>
    RewriteEngine   on
    RewriteMap      allow dbm:/www/conf/my.allow
    RewriteCond     ${allow:%{REMOTE_ADDR}|block}           !^ok$
    RewriteRule     ^/.*     http://%{REMOTE_ADDR}/      [L]
  </IfModule>

and your my.allow.db is generated from a file like this:

    123.123.123.123    ok
    123.123.123.134    ok
    321.321.321.222    ok
    ...

Observations

This has worked for sites being hit at roughly 10 attacking hits per second without breaking a sweat. I haven't scaled up to test it, but I imagine it would work for much higher values.

If attacking characteristics are randomized or otherwise not of a set that can be easily normalized, then this method will be less useful. Likewise, if the incoming requests are coming in at a rate higher than your socket or Apache buffers can hold, nothing you can do at the application layer will help (i.e., you'll need to configure your network card to drop the attacking packets, or better, have your upstream ISP stop it at their incoming routers). YMMV.

I load mod_setenvif in my Apache; it might be required to use mod_rewrite's E=var (e.g., E=nolog:1) capabilities. I haven't confirmed this. If someone figures this out (e.g., has one Apache built with and one built without mod_setenvif), let me know.

This article was mentioned in Sys-Con magazine.

Apache tutorials

Send comments to the author