Showing posts with label Encrypt Querystring. Show all posts
Showing posts with label Encrypt Querystring. Show all posts

Tuesday, April 28, 2009

How to Encrypt Query String Parameters in ASP.NET

There are some circumstances when you need to encrypt query string parameters in your URLs in order to secure your web applications. There are many reasons and many cases but as one of my recent experiences in Waegis a user activation requires such a system. The reason is to prevent anyone to use other’s plain email address to activate his or her account without receiving the activation mail!

Of course, there are some solutions and I’m not using this solution on Waegis (I replaced the solution with a simpler and secure mathematical algorithm that I inspired myself) but the incoming solution is the most common way to encrypt your query string parameters.

The basic idea of this method is using DES cryptography system to encrypt query string parameters on one side and then decrypting it on the other side. But the key point about this method is that DES algorithm is a symmetric algorithm that requires two keys. How do you want to work around this?

You may want to pass your sector vector or initialization vector as a secondary parameter in query string and keep the other key private but this is an insecure solution because having those two parameters, your key is predictable so your algorithm is breakable!

But what’s the solution? The solution is to define both keys on your side and use them to encrypt your text and only pass the encrypted text to query string then retrieve the text and decrypt it with these keys.

Having this background, the implementation is easy and straightforward and contains nothing but some .NET cryptography code.

The main part of this workflow is building a simple cryptographic class that manages the encryption and decryption of string values with your keys. Below code represents the class that you can port for your application. There are two fields that define and hold sector vector and initialization vector. You need to define them once and add them to your application. The rest of the code should be familiar to you because it’s just a set of regular .NET cryptography operations.

using System;

using System.Data;

using System.Configuration;

using System.Linq;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.HtmlControls;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Xml.Linq;

using System.Text;

using System.Security.Cryptography;

using System.IO;

namespace QueryStringEncryption

{

public class Cryptography

{

#region Fields

private static byte[] key = { };

private static byte[] IV = { 38, 55, 206, 48, 28, 64, 20, 16 };

private static string stringKey = "!5663a#KN";

#endregion

#region Public Methods

public static string Encrypt(string text)

{

try

{

key = Encoding.UTF8.GetBytes(stringKey.Substring(0, 8));

DESCryptoServiceProvider des = new DESCryptoServiceProvider();

Byte[] byteArray = Encoding.UTF8.GetBytes(text);

MemoryStream memoryStream = new MemoryStream();

CryptoStream cryptoStream = new CryptoStream(memoryStream,

des.CreateEncryptor(key, IV), CryptoStreamMode.Write);

cryptoStream.Write(byteArray, 0, byteArray.Length);

cryptoStream.FlushFinalBlock();

return Convert.ToBase64String(memoryStream.ToArray());

}

catch (Exception ex)

{

// Handle Exception Here

}

return string.Empty;

}

public static string Decrypt(string text)

{

try

{

key = Encoding.UTF8.GetBytes(stringKey.Substring(0, 8));

DESCryptoServiceProvider des = new DESCryptoServiceProvider();

Byte[] byteArray = Convert.FromBase64String(text);

MemoryStream memoryStream = new MemoryStream();

CryptoStream cryptoStream = new CryptoStream(memoryStream,

des.CreateDecryptor(key, IV), CryptoStreamMode.Write);

cryptoStream.Write(byteArray, 0, byteArray.Length);

cryptoStream.FlushFinalBlock();

return Encoding.UTF8.GetString(memoryStream.ToArray());

}

catch (Exception ex)

{

// Handle Exception Here

}

return string.Empty;

}

#endregion

}

}

Now the rest of this post exemplify how to use this Cryptography class. I implement a UserActivation class that manages the activation process. It generates activation links by getting a username and also activates a user by getting the encrypted username key. The final class is shows below.

using System;

using System.Data;

using System.Configuration;

using System.Linq;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.HtmlControls;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Xml.Linq;

using System.IO;

namespace QueryStringEncryption

{

public static class UserActivation

{

#region Public Methods

public static void ActivateUser(string key)

{

string username = Cryptography.Decrypt(key);

// TODO: Activation Login

}

public static string GetActivationLink(string username)

{

string key = Cryptography.Encrypt(username);

StringWriter writer = new StringWriter();

HttpContext.Current.Server.UrlEncode(key, writer);

return string.Format("/default.aspx?key={0}", writer.ToString());

}

#endregion

}

}

Here the important point is to not forget to UrlEncrypt the encrypted key because usually it contains some characters that will be ignored by ASP.NET and can cause exceptions on decryption.

I finally wrap up this example by applying it in a simple page. This page generates an activation link when there is no query string parameter and it also decrypts the key parameter when it is provided. In real world scenarios you can use this decrypted username to activate the user’s account.

using System;

using System.Collections;

using System.Configuration;

using System.Data;

using System.Linq;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.HtmlControls;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Xml.Linq;

namespace QueryStringEncryption

{

public partial class _Default : System.Web.UI.Page

{

protected void Page_Load(object sender, EventArgs e)

{

if (string.IsNullOrEmpty(Request["key"]))

Response.Write(UserActivation.GetActivationLink("keyvannayyeri"));

else

Response.Write(Cryptography.Decrypt(Request["key"]));

}

}

}

Encrypting QueryStrings with .NET

Encrypting QueryStrings with .NET

Once upon a time in the tech world, obscurity was security - this being most true in the early years of the industry, when there were gaping holes in privacy policies and confidential client information was bandied about from site to site without a care as to who actually could read the information.

With the new Cryptography classes in .NET, there's absolutely no excuse for not hiding even the most innocuous user data. If you ever need to 'piggy-back' information from one web page to another, whether it is within a POST or a GET parameter, you're passing clear information that anyone can sniff - and that's a bad thing.

If you're not going to use a session variable for storing end user information, you're most likely going to keep some sort of State by passing the information to a cookie or push it around with GET/POST parameters. If you're passing around any sort of ID or user information like their name, it's better to err on the side of caution and encrypt the information.

GET Vs. POST

A POST parameter keeps the information out of the URL, but it can still be sniffed quite easily as it passes in clear text across your network or the Internet. Using POST will keep the mere curious at bay, as the information is not contained in the URL - but this will not stop someone determined to snag out your data.

A QueryString parameter passes information within the site's URL. Why would you even use a QueryString? Well, maybe you need to let your user bookmark a particular page, or maybe you have to refer directly to a page in a URL via a link - you can't do either if you're using POST. A QueryString puts data in the URL for the entire world to see, so if you don't know if the end user is malicious, I'd think hard about using a QueryString for anything but site-related information.

Be smart and encrypt any and all data you're moving around from page to page, especially if that information could be used maliciously. You may trust your users, but you still need that extra level of security that clear text GET/POST data doesn't provide.Imagine this scenario - you've been passing the customer's ID in the database around in a QueryString, in a URL that looks like this:

http://yoursite.com?cust_id=29

You know what a user is going to do? Switch that 29 to a 30 or 12 or some other number, and if you're not checking for invalid requests, you'll be dishing up some other customer's data.

Enter Encryption

What I was looking for was a quick way to encrypt and decrypt parts of a QueryString - it had to be on the fly, quick and dirty.

I chose Base64 because it wouldn't throw bizarre characters in my QueryString that I couldn't pass around… Little did I know that I'd hit a snag while passing around my encrypted QueryString - Apparently, the Request.QueryString object interprets the '+' sign as a space! So, with a quick Replace function slapped on my decrypt string, no harm, no foul.

Symmetric Key

The whole trick to this working is that the QueryString is encrypted and decrypted with the same private key. This is the secret key - if anyone gets a hold of your key, they can decrypt the data themselves, so keep it a secret!

We're going to use a hard-to-crack 8 byte key, !#$a54?3, to keep parts of our QueryString secret.

Let's Walk through the C# portion of the code:

Notice our two functions that abstract the dirty work that our Encryption64 class. The first, encryptQueryString, is used to encrypt the value of a QueryString. The second, decryptQueryString, is used to decrypt the value of an encrypted QueryString.

public string encryptQueryString(string strQueryString) {
ExtractAndSerialize.Encryption64 oES =

new ExtractAndSerialize.Encryption64();
return oES.Encrypt(strQueryString,"!#$a54?3");

}

public string decryptQueryString(string strQueryString) {
ExtractAndSerialize.Encryption64 oES =

new ExtractAndSerialize.Encryption64();
return oES.Decrypt(strQueryString,"!#$a54?3");

}

If we wanted to encrypt our QueryString on our first page, we could do something like this:

string strValues = "search term";

string strURL = "http://yoursite.com?search="
+ encryptQueryString(strValues);
Response.Redirect(strURL);

Inside our code-behind in our second page, we pass the contents our QueryString to a variable named strScramble. After that, we replace the '+' signs that our wonderful Request.QueryString has replaced with a space. We pass that string into our function, decryptQueryString, and retrieve the decrypted string.

string strScramble =  Request.QueryString["search"];

string strdeCrypt = decryptQueryString(
strScramble.Replace(" ", "+"));

Now we've decrypted the value of the QueryString, 'search', and we can do whatever we want with it. The end user is going to see a URL that looks like:

http://yoursite.com?search=da00992Lo39+343dw

They'll never be able guess what's going on in your QueryString, and if they try to fool around with it, there's no way to crack the code without knowing the Symmetric key.

VB.NET

Imports System
Imports System.IO
Imports System.Xml
Imports System.Text
Imports System.Security.Cryptography

Public Class Encryption64

Private key() As Byte = {}
Private IV() As Byte = {&H12, &H34, &H56, &H78, &H90, &HAB, &HCD, &HEF}

Public Function Decrypt(ByVal stringToDecrypt As String, _
ByVal sEncryptionKey As String) As String

Dim inputByteArray(stringToDecrypt.Length) As Byte
Try
key = System.Text.Encoding.UTF8.GetBytes(Left(sEncryptionKey, 8))

Dim des As New DESCryptoServiceProvider()
inputByteArray = Convert.FromBase64String(stringToDecrypt)
Dim ms As New MemoryStream()

Dim cs As New CryptoStream(ms, des.CreateDecryptor(key, IV), _

CryptoStreamMode.Write)
cs.Write(inputByteArray, 0, inputByteArray.Length)

cs.FlushFinalBlock()
Dim encoding As System.Text.Encoding = System.Text.Encoding.UTF8

Return encoding.GetString(ms.ToArray())
Catch e As Exception
Return e.Message

End Try
End Function

Public Function Encrypt(ByVal stringToEncrypt As String, _

ByVal SEncryptionKey As String) As String
Try
key = System.Text.Encoding.UTF8.GetBytes(Left(SEncryptionKey, 8))

Dim des As New DESCryptoServiceProvider()
Dim inputByteArray() As Byte = Encoding.UTF8.GetBytes( _

stringToEncrypt)
Dim ms As New MemoryStream()
Dim cs As New CryptoStream(ms, des.CreateEncryptor(key, IV), _

CryptoStreamMode.Write)
cs.Write(inputByteArray, 0, inputByteArray.Length)

cs.FlushFinalBlock()
Return Convert.ToBase64String(ms.ToArray())
Catch e As Exception

Return e.Message
End Try
End Function

End Class