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!!
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
Post a Comment