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

Authentication using Social Networking portals(Facebook, Gmail, and Yahoo)

There are tons of sites, which offer sign on using the social networking site credentials (Facebook, gtalk, twitter and the list continues).It can be termed a “SINGLE SIGNON” and offers a lot of benefits compared to traditional database authentication approach. However, not storing user credentials in the DB imposes an additional risk. How to track who all logged into the system. Now the question is, which approach to follow. The best approach is to use inbuilt asp.net users for storing the logging info about user activities and using single signon technique for authentication. This article will explore the approach and provide the details of implementation using some third party libraries and customizing it to the requirements. The Authentication will be done using the following networking portals Yahoo  Gmail Facebook    Special thanks to my friend Sumit Khandelwal, for implementation of Facebook part (in fact he did it all!!) Except Facebook, all other ca...

WPF Overview-Part-II

This post is in continuation to the last post. In this Post I’ll be exploring the Dependency Properties Dependency properties are similar to CLR properties with more advanced and complex features. The main difference between the CLR properties and dependency properties is, that the value of a normal .NET property is read directly from a private member in your class, whereas the value of a DependencyProperty is resolved dynamically when calling the GetValue() method that is inherited from DependencyObject . In case this description did not make sense, no need to worry, It will become clear by the time you reach end of this article. How the Value is Resolved in Dependency properties Every time a dependency property is accessed, it internally resolves the value by following the precedence from high to low. It checks if a local value is available, if not, check if a custom style trigger is active and I the similar manner continues until it finds a value. At last the default value is alwa...

HTML-5 Let's get started

Want to see html 5 in action, before actually diving into it, here's your chance. Go to this LINK and see the wonderful features that HTML-5 has to offer. Feeling overwhelmed, feel like getting hands dirty with this new kid on the block? Here's how to get started Hope this was useful.... Till next we connect.... Happy reading.....