Monday, November 17, 2008

How to Block Country and IP Addresses in ASP.NET using HTTPModule?

Problem

Recently, we noticed in our web traffic report some very suspicious activities so we decide to block certain ip addresses. Now there are many ways block ip addresses like at Windows server level, using IIS and at ASP.NET level.

First two choices works only if the person had access to the server and it becomes problem if one does not have access to the server and blocking IP address in ASP.NET becomes only choice.

References used to research and learn

Custom configuration sections
Creating ASP.NET HTTPModule
Restful API for finding out IP address's country

Assumption

1) The reader is familiar with ASP.NET
2) Wants to learn about HTTPModule, and Custom Configuration Sections

About the project

Download: IPBlocker.zip source

Here are the features of IPBlocker:

0) Rule is if the IP address is in denied list or ip address is not in granted list it will be blocked. Also, IP address will be checked against all the defined blocking scheme in the configuration until ip is blocked. If the IP is granted access and not in blocked list IP address will be granted.

1) IP Address can contain * as wild character.
i.e. <ip value="127.0.0.1" access="granted" valueType="IpAddress" />

2) Range of IP address can be specified.
i.e. <ip value="127.0.0.1;127.0.0.200" access="denied" valueType="IpRange" />

3) Can block country.
i.e. <ip value="IN;US" access="denied" valueType="CountryCode" />

4) Multiple IP address blocking scheme can be defined.
i.e. grant all ip from 127.0.0.1 through 127.0.0.255 EXCEPT 127.0.0.20 through 127.0.0.25.
<ip value="127.0.0.*" access="granted" valueType="IpAddress" />
<ip value="127.0.0.20;127.0.0.25" access="denied" valueType="IpRange" />

Here is sample configuration



<IpBlockerGroup>


  <IpBlockerConfiguration>


 


    <pages defaultScheme="blockIp">


      <page name="contactus.aspx" />


      <page name="home.aspx" scheme="blockIpRange" />


      <page name="aboutus.aspx" scheme="blockCountry" />


    </pages>


 


    <schemes>


      <!-- Used for Load Test -->


      <scheme name="blockIp">


        <ips>


          <!-- Use * as wild card -->


          <ip value="*.*.*.*" access="granted" valueType="IpAddress" />


          <!-- min value and max value seperated by ; (i.e. 127.1.2.3;233.3.3.2) -->


          <ip value="127.0.0.1;127.0.0.2" access="denied" valueType="IpRange" />


          <!-- ; seperated country code (i.e. IN;US) -->


          <ip value="IN;US" access="denied" valueType="CountryCode" />


        </ips>


      </scheme>


    </schemes>


 


  </IpBlockerConfiguration>


</IpBlockerGroup>




Requirements

1) VS2008
2) .Net 3.5

Step by step instruction

In web.config, add to configSections:



<sectionGroup name="IpBlockerGroup">


  <section


    name="IpBlockerConfiguration"


    type="IpBlocker.Configuration.IpBlockerConfigurationSection, IpBlocker"


    allowLocation="true"


    allowDefinition="Everywhere" />


</sectionGroup>




Add to configuration



<IpBlockerGroup>


  <IpBlockerConfiguration>


    <pages defaultScheme="blockCountry">


      <page name="contactus.aspx" />


    </pages>


    <schemes>


      <!-- Used for Load Test -->


      <scheme name="blockCountry">


        <ips>


          <!-- Use * as wild card -->


          <!--<ip value="*.*.*.*" access="granted" valueType="IpAddress" />-->


          <!-- min value and max value seperated by ; (i.e. 127.1.2.3;233.3.3.2) -->


          <!--<ip value="127.0.0.1;127.0.0.2" access="denied" valueType="IpRange" />-->


          <!-- ; seperated country code (i.e. XX;IN;US) -->


          <ip value="IR;RU;SA;IN" access="denied" valueType="CountryCode" />


        </ips>


      </scheme>


    </schemes>


  </IpBlockerConfiguration>


</IpBlockerGroup>




That it for running the module. Let's look at what is happening at more detailed level.



public class IpBlockerModule : IHttpModule


{


  public IpBlockerModule()


  {


  }


 


  public void Init(HttpApplication context)


  {


    context.BeginRequest += new EventHandler(Context_BeginRequest);


  }


 


  public void Dispose()


  {


  }


 


  private void Context_BeginRequest(object sender, EventArgs e)


  {


    IpBlockerConfigurationSection config = ConfigurationManager.GetSection("IpBlockerGroup/IpBlockerConfiguration") as IpBlockerConfigurationSection;


    HttpApplication application = sender as HttpApplication;


    string aspxPageName = System.IO.Path.GetFileName(application.Request.Url.AbsolutePath).ToUpper();


 


    PageElement page = config.Pages[aspxPageName];


    if (page != null && config.Schemes[config.Pages[aspxPageName].Scheme].CanBlockIp(application.Request.UserHostAddress))


    {


      // Blocking process


      application.Response.StatusCode = 404;


      application.Response.SuppressContent = true;


      application.Response.End();


    }


  }


 


}




IpBlockerModule listens to BeginRequest and checks to see if IP is granted to proceed for the specific page. Notice that in configuration Every page can have different IP blocking scheme. The reason why IP is blocked on specific page is because page like contact page that has email submission can be protected while other pages are not.

Conclusion

This module was developed out of need because even with captcha we had our contact page visited by some very starge ips performing very strange things. Also, it was good practice in creating HTTPModule and creating custom configuration.

10 comments:

Bdub said...

This is a great solution. I am experiencing one shortcoming it seems though. In a schema, I would like to include multiple ranges. It seems that once the code hits an IP range that does not contain the IP address, it bails out and blocks the current IP address. The IP was actually contained in the range following the one that it bailed out on. So, even though it should have been allowed, the CanBlockIp function sends a true result too soon. Do you know how I can get around this? Thanks!

NewAgeSolution said...

Sorry for getting so late on this.

I am on the road right now takes while to respond. Anyway, here is the solution that will resolve your problem. I improved IPRange in a way that you can provide comma separated ranges.

Below is new IPRange scheme that is added to address your problem.

Now you can add IpRanges that are separated by comma.

Please take a look at IpRangesCheckerTest unit test.

Your new scheme should look like below in web.config

ip value="127.0.0.1;127.0.0.5,127.0.0.25;127.0.0.30" access="granted" valueType="IpRange"

Let me know if this works out for you.

I updated download to contain the improvment to meet your need.

sanych said...

Nice module. I modified your code a little bit allowing sequential rules combination.

I need this for allowing access to admin control panel from 4 specific URLs only

Basically I needed a schema that works like that

ip value="*.*.*.*" access="denied" valueType="IpAddress"
ip value="127.0.0.1" access="granted" valueType="IpAddress"
p value="192.168.*.*" access="granted" valueType="IpAddress"


If you need these mods - drop me an email at sanych at dwall dot org

Anonymous said...

Hi, I am testing your code and I am missing a step. I have added the tags to the Web.Config and have added your project to my solution. The code never gets run (I am testing using Localhost if that matters). Is there an additional step I need to take to get this code to run? Thank you!

NewAgeSolution said...

Are you still having problem? Let me know I was on the road so I couldnt get to this quickly as I would liked.

网络无边 said...

cann't download source code ipblocker.zip

网络无边 said...

cann't download source code ipblocker.zip, would you please send me one? nqzzbnzz@gmail.com

Flex Compiler said...

The zip file is missing. Can you please put the file back up? I'd really like to use it.
Thanks!

Flex Compiler said...

The zip file is missing. Can you please put the file back up? I'd really like to use it.
Thanks!

NewAgeSolution said...

please try www.toetapz.com/downloads/IPBlocker.zip