Monday 22 April 2013

Configuring an Apache2 instance to only allow access from a specific set of countries

Ok. This is pretty simple, but I'm documenting it here for myself.
The issue arose for me when one of our test servers started getting hammered by script kiddies from China and so on.
They didn't get in, but that wasn't the point.
The point was that the web site was for Australian users only.
Now to short circuit any comments I can say:
1) The solution had to work for several frameworks (Elgg, Joomla, etc)
2) I wasn't redirecting traffic to a special page
3) I wanted to black all access except Australian IPv4 ranges
I could have gone to MaxMind or its ilk, but that would make '1' problematic.

The first step was to locate a *correct* and *regularly updated* list of CIDR and range formatted IPv4 list.
I tried several including http://www.ipdeny.com/ipblocks/ with no luck.
Most have gaps in their lists because they use 'official' sources.
And ISP ranges are not always covered in those lists.

Eventually I found http://software77.net/geo-ip/
I downloaded the zone and CIDR lists for the countries I was interested in.
Then I modified the /etc/apache2/sites-available/my-site.something.com file to look like this:
<caveat>
Abbreviated for this post. :-)
</caveat>

<VirtualHost *:80>
  ServerAdmin     my.email@my.email.service.com
  ServerName      my-site.something.com
  ServerSignature Off
  DocumentRoot    /home/my-user/my-site/site
  LogLevel        warn
  ErrorLog        /home/my-user/my-site/logs/error.log
  CustomLog       /home/my-user/my-site/logs/access.log combined
  ScriptAlias     /cgi-bin/ /usr/lib/cgi-bin/
  <Directory /home/my-user/my-site/site/>
    Options       Indexes FollowSymLinks MultiViews
    AllowOverride All
    Order         Deny,Allow
    # See .htaccess for country limiting
  </Directory>
</VirtualHost>

Then in the /home/my-user/my-site/site/.htaccess file I added the following to the bottom:

<Limit GET HEAD POST>
  Order Deny,Allow
  Deny from all
  # Report generated on Mon Apr 22 01:02:36 2013
  # by http://software77.net/geo-ip/
  # Report Type  : CIDR format
  # Country      : Australia
  # ISO 3166 CC  : ALPHA-2 AU; ALPHA-3 AUS
  # Registry     : APNIC
  # Records found: 6,160 BEFORE flattening (As they appear in the database)
  # Records      : 3,999 AFTER flattening (Adjoining CIDR blocks concatenated into single blocks where possible)
  Allow from 1.0.0.0/24
  Allow from 1.0.4.0/22
  ...elided for brevity...  
  Allow from 223.255.248.0/22
  Allow from 223.255.255.0/24
</Limit>

The block from under the 'Deny from all' to the end is the CIDR formatted file for a country.
You have to add the 'Allow from ' in front of the address, but if you use vi that's trivial.
If you want to allow another country access, then simply add the CIDR formatted file below the first.

Then I ran '/etc/init.d/apache2 reload' and all is well.

IMPORTANT NOTE: Things change. You have to check for additions and deletions on the CIDR files on a regular basis - say, once a month to ensure that you .htaccess file is up to date.

Some readers may have noticed that I suggest downloading the zone files as well.
This is to allow you to read your apache logs and see which country that access came from.
I will be posting another entry soon that shows how to do that in Ruby.

No comments:

Post a Comment