Wednesday, April 13, 2011

Rewriting Server Variables in .NET using an HTTPModule

A good friend of mine here at work came to me the other day with an interesting problem.  They have a third party application which relies on the client IP to be populated in the REMOTE_ADDR server variable to properly function.  All of our web products sit behind F5 proxies which means this variable is always populated by the F5 IP and not the client IP.  However, the F5 sends the true client IP in the HTTP_X_FORWARDED_FOR variable.  The problem was, getting HTTP_X_FORWARDED_FOR populated in REMOTE_ADDR.

The application in question is .NET and obviously compiled without access to the source.  So, code modification on our end was not an option.

First solution that came to mind was an HTTPModule.  My first try was a failure after quickly learning the server variable space is read-only.  However, you could write to these variables after implementing a little reflection.  Is this a hack, sort of, but it does appear to work.  Here is the code:

 private void Application_BeginRequest(Object source, EventArgs e)  
     {   
       HttpApplication application = (HttpApplication)source;   
       HttpContext context = application.Context;   
       //pull out the server vars collection   
       NameValueCollection oServerVars = context.Request.ServerVariables;   
       if (!string.IsNullOrEmpty(oServerVars["HTTP_X_FORWARDED_FOR"]))   
       {   
         string x_forward_for = oServerVars["HTTP_X_FORWARDED_FOR"];   
         //locate the server variables field in the collection   
         oServerVars = (NameValueCollection)context.Request.GetType().GetField("_serverVariables", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(context.Request);   
         //locate the readonly fields   
         PropertyInfo oReadable = oServerVars.GetType().GetProperty("IsReadOnly", BindingFlags.NonPublic | BindingFlags.Instance);   
         //set the new value   
         oReadable.SetValue(oServerVars, false, null);   
         oServerVars["REMOTE_ADDR"] = x_forward_for;   
         oReadable.SetValue(oServerVars, true, null);   
       }   
     }  

No comments:

Post a Comment