Skip to main content

URL Encryption/URL Rewriting

One of the main security checks that the most of the sites implement is URL encryption.
URL encryption in simple terms converts the human readable address into encrypted format. Most of the times only a part of the URL is encrypted that makes it secure by hiding I the inner implementation details used on the page.
Consider an example:
Imagine a page which provides user details and let’s assume that the URL for that is http://[site]/users?user_id=[userid]. The same page is called over and again, just y differing the user_id parameter.
The simplest approach is to encrypt this value so that it becomes hard to guess the user_id and prevent unauthorized access. (Assuming that Role-based security is not used, as provided in ASP.Net).
This looks simple; however one of the side-effects arising out of this could be JavaScript or any code that reads the value from Querysting. To avoid this issue we need to encrypt the page when it is rendered and decrypt the values when there is a need.
Easier said than done; the challenge is to identify when to encrypt and decrypt and what logic to use for encryption and decryption.
Some of the approaches for implementing it, can be found at this location
After reading the above approaches (if you cared to go through the above link), I found the Http Module option the Best that suits the requirement.

However the approach seemed a bit confusing, so let’s tweek it a bit and write an HttpModule that will do the trick for us.
Code :
using System;
using System.IO;
using System.Web;
using System.Text;
using System.Security.Cryptography;

public class URLRewriter : IHttpModule
{

public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(context_BeginRequest);
}

private const string param = "enc=";
private const string enc_key = "key";
static string OriginalUrl;
void context_BeginRequest(object sender, EventArgs e)
{
HttpContext context = HttpContext.Current;
if (context.Request.Url.OriginalString.Contains("aspx") && context.Request.RawUrl.Contains("?"))
{
string queryval = GetQuery(context.Request.RawUrl);
string querypath = GetQueryVirtualPath();

if (queryval.StartsWith(param, StringComparison.OrdinalIgnoreCase))
{
// Decrypts the query string and rewrites the path.
string OriginalQuery = queryval.Replace(param, string.Empty);
string decryptedQuery = DecryptURL(OriginalQuery);
context.RewritePath(querypath, string.Empty, decryptedQuery);
}
else if (context.Request.HttpMethod == "GET")
{
// Encrypt the query string and redirects to the encrypted URL.
string encryptedQuery = string.Empty;
encryptedQuery = Encrypt(queryval);
context.Response.Redirect(querypath + encryptedQuery);
}
}
string qrystrng = context.Request.RawUrl;
if (qrystrng.Contains("?"))
{
string[] prntexcp = qrystrng.Split('?');
string query = GetQuery(context.Request.RawUrl);
string path = GetQueryVirtualPath();

if (query.StartsWith(param, StringComparison.OrdinalIgnoreCase))
{
// Decrypts the query string and rewrites the path.
string rawQuery = query.Replace(param, string.Empty);
string decryptedQuery = DecryptURL(rawQuery);
context.RewritePath(path, string.Empty, decryptedQuery);
}
else if (context.Request.HttpMethod == "GET")
{
// Encrypt the query string and redirects to the encrypted URL.
OriginalUrl = path;
string encryptedQuery = string.Empty;
encryptedQuery = Encrypt(query);
context.Response.Redirect(path + encryptedQuery);
}

}

}

private static string GetQueryVirtualPath()
{
string path = HttpContext.Current.Request.RawUrl;
path = path.Substring(0, path.IndexOf("?"));
return path;
}

private static string GetQuery(string url)
{
int index = url.IndexOf("?") + 1;
return url.Substring(index);
}

private string Encrypt(string strEncrypted)
{
try
{
byte[] b = System.Text.ASCIIEncoding.ASCII.GetBytes(strEncrypted);
string encryptedConnectionString = Convert.ToBase64String(b);
return "?" + param + encryptedConnectionString;
}
catch
{
throw;
}
}

private string DecryptURL(string encrString)
{
try
{
byte[] b = Convert.FromBase64String(encrString);
string decryptedConnectionString = System.Text.ASCIIEncoding.ASCII.GetString(b);
return decryptedConnectionString;
}
catch
{
throw;
}
}

#endregion

}

Code Analysis:
URLRewriter class derives from IHttpModule i.e. it is an HTTP Module(for details on HttpModule please visit the link

IT traps the httpRequest and httpResponse and performs the logic( self explanatory) written in code. The Code encrypts the incoming Querysting values in Base64String, that is non readable.
(Another option can be to implement various algorithms (Rjandel etc) that will provide more security.)

The code encrypts the plaintext and decrypts the encrypted string as appropriate.

Shortcomings: This Code will need modifications if URL value is appended to on Client Side (via JavaScript(s))

Scope of Improvement: The above written code can be enhanced to enable/disable conditional logic for the pages as per the requirement

Last step required to make this class usable is to register the Module in Web.config as demonstrated below

<httpModules>
      <add name="URLRewriterMod" type="URLRewriter"/>
 </httpModules>

Advantage:
The main advantage of this class is the fact that if the module is not registered as described above, the code will function as normal(useful in debugging)
I appreciate the efforts put in By Sumit Khandelwal in simplifying the encryption and Decryption methods and making them generic enough to be deployed and used in most common scenarios.
Till Next we connect
Happy Coding!!

Comments

Popular posts from this blog

Asp.Net 4.0: An Overview-Part-III

This is the last post in the series which will explore the following new features of ASP.Net 4.0  Performance Monitoring for Individual Applications in a Single Worker Process Web.config File Refactoring Permanently Redirecting a Page Expanding the Range of Allowable URLs Performance Monitoring for Individual Applications in a Single Worker Process It is a common practice to host multiple ASP.NET applications in a single worker process, In order to increase the number of Web sites that can be hosted on a single server. This practice results in difficulties for server administrators to identify an individual application that is experiencing problems. ASP.NET 4 introduces new resource-monitoring functionality introduced by the CLR. To enable this functionality, following XML configuration snippet is added to the aspnet.config configuration file.(This file is located in the directory where the .NET Framework is installed ) <?xml version="1.0" encoding="UTF-8...

WCF-REST Services-Part-II

HOW REST is implemented in WCF Part-I of the series explored the REST conceptually and this post will explore how REST is implemented in WCF. For REST implementation in WCF, 2 new attributes namely WebGetAttribute and WebInvokeAttribute are introduced in WCF along with a URI template mechanism that enables you to declare the URI and verb to which each method is going to respond. The infrastructure comes in the form of a binding ( WebHttpBinding ) and a behavior ( WebHttpBehavior ) that provide the correct networking stack for using REST. Also, there is some hosting infrastructure help from a custom Service¬Host ( WebServiceHost ) and a ServiceHostFactory ( WebServiceHostFactory ). How WCF Routes messages WCF routes network messages to methods on instances of the classes defined as implementations of the service. Default behavior ( Dispatching ) for WCF is to do this routing based on the concept of action. For this dispatching to work, an action needs to be present in ev...

WPF Routing

WPF (3.5) introduced the concept of Routing that made the event routing easies in the scenarios where it was tedious to handle events. Consider a scenario where there are a number of Hyperlinks in a Panel that direct to separate locations on Click. Now if this is done in normal programming, each hyperlink will have to have code for execution. It would be easier and cleaner if we could handle the hyperlinks in the container (the Panel) that handles the click and redirects to appropriate location. WPF handles the events with the following 3 strategies. Direct events are like ordinary .NET events. They originate in one element and don’t pass to any other. For example, MouseEnter is a direct event. Bubbling events are events that travel up the containment hierarchy. For example, MouseDown is a bubbling event. It is raised first by the element that is clicked. Next, it is raised by that element’s parent, and then by that element’s parent, and so on, until WPF reaches the top of the e...