Application security

Vulnerable Encoded URL

Ajay Yadav
March 24, 2014 by
Ajay Yadav

This paper especially pinpoints the poor practice of cryptography in URL, which is typically implemented to encrypt sensitive data residing in the website URL in the form of a query string that is transmitted across a variety of networks. Websites can be compromised and such subtle information (query string) can be disclosed by exploiting this vulnerability. This article demonstrates a real-time scenario in which developers commit mistakes by practicing weak cryptographic methods inadvertently. Finally, this article addresses the various disadvantages of applying weak cryptography algorithm and suggests a variety of alternative methods to secure URL data properly.

Introduction

Securing URL is the process of concealing or encrypting a parameterized query string-based URL such as www.xyz.com/login.aspx?uid=ajay&pawd=09876 by applying complex C#.NET cryptography. The moment a URL is requested from the server, internally we determine the required parameters, then encrypt the query string values where sensitive information is typically located, redirect them to another source for further processing, and then decrypt the encrypted query string values there, if necessary. In this whole process, the URL always shows some bizarre values in the query string that are safe from the malicious hacker's eyes because it is very hard for him to figure out what exactly is travelling across the network via the query string. The idea of query string encryption protects a web page from MITM or session hijacking attacks to some extent. This mechanism is somewhat similar to URL rewriting, where a verbose URL is flashing in the address in spite of the actual web page address where the query string parameters are located. The hacker never ever anticipates that the requested URL would have contained any query string values.

Susceptible URL

The following Asp.Net page, which simply authenticates users by checking for a correct user id and password, is created to demonstrate the real concept behind disclosing "sensitive data via URL" incident. This page stipulates both facilities for logging in; plain text or secure sign-in.

When the user enters his credentials and goes ahead with a simple plain text mechanism (without checking Secure Sign-in), his user name and password travel through a query string to the redirected page and is literally displayed in the URL address bar, as shown below:

Though it is optional, we are showing user credential information on the redirected Welcome.aspx page, but there is a catch in the address bar, also. There is a possibility that a malicious hacker could intercept the traffic and he can easily take advantage of user information, as such data are travelling or located in the query string in clear text. Hence, this is the crucial vulnerability that we are going to pinpoint in this paper.

Securing Sensitive Data

This section describes the process of encrypting the data residing in a query string. The login form interface is designed in such a way that, if the user enables the Secure Sign-in check box, the encryption algorithm will be activated behind the scene and it is hard to anticipate what ciphered data will travel across the web pages in the query string.

As the user moves ahead by enabling the "Secure Sign-in" option, the following piece of code is activated and encrypted as the sensitive portion of URL. Here, the Encrypt() method takes the user name and password from the login form and implements ciphering. Later, the user will be redirected to the welcome page via query string mechanism:

[c]

string usr = HttpUtility.UrlEncode(Encrypt(txtUser.Text.Trim()));

string pwd = HttpUtility.UrlEncode(Encrypt(txtPwd.Text.Trim()));

Response.Redirect(string.Format("~/welcome.aspx?usrname={0}&password={1}",

usr, pwd));

[/c]

Developers usually protect the query string by invoking the UrlEncode method, which typically converts the plain text into base64 format. But such encoding does not suffice and is still vulnerable. Hence, we applied double protection here in the form of invoking a custom algorithm and the UrlEncode method.

Query String Encryption

In this code segment, the real encryption of query string parameters will be happen in the Encrypt() method implementation, which is called when the user clicks on the "Sign-In" button. The query string values will first be encrypted using the AES Symmetric key algorithm and will then be sent to the welcome page, where the query string values will be first deciphered and then decrypted using the AES Algorithm again using the symmetric key that was used for encryption earlier on the login page.

As we know, the hashing algorithm can be implemented by either a symmetric key or an asymmetric key. In asymmetric key cryptography, two keys are employed for encryption and decryption, but in this tutorial we are relying on a symmetric key, in which a single key is used for both ciphering and deciphering the sensitive data.

Generating Secure Key (Symmetric)

The symmetric key could be anything, depending on the developer's discretion. Symmetric key algorithms are very effective for processing extensive amounts of data and are less intensivecomputationally than asymmetric encryption algorithms. Hence, we hardcoded the symmetric key as "ajaykumar007," which perform both functions as following;

[c]

string password = "ajaykumar007";

[/c]

It is recommended that the symmetric key be strong, with many alphanumeric keys, so it is hard to guess. A simple combination of words is always considered to be a weak key and susceptible to dictionary attacks. There are plenty of methods for generating a secure key, such as the following code for generating a symmetric key:

[c]
static String CreateKey(int numBytes)

{

RNGCryptoServiceProvider rnd = new RNGCryptoServiceProvider();

byte[] b = new byte[numBytes];

rnd.GetBytes(b);

return BytesToHexString(b);

}

static String BytesToHexString(byte[] bytes)

{

StringBuilder hexString = new StringBuilder(64);

for (int counter = 0; counter < bytes.Length; counter++)

{

hexString.Append(String.Format("{0:X2}", bytes[counter]));

}

return hexString.ToString();

}

[/c]

We can also use the aforesaid code for generating an asymmetric key programmatically, but we move ahead with "ajaykumar007."

Generating Salt

Salt is typically random data that is used as supplementary input to a one-way function that hashes a passphrase or sensitive data. The salt and the password are concatenated and processed with a cryptographic hash function and the resulting output (but not the original password) is stored with the salt in a database. The key purpose of salts is to protect against pre-computed rainbow table and dictionary attacks.

It is not mandatory to keep the salt value a secret. An attacker never ever assumes in advance what the salt will be, so they can't use a rainbow table or a pre-computed lookup table, because the salt value is generated randomly and thehash's value would be different each time. Generally, we create salt random values by employing the code shown below:

[c]
private static string CreateSalt(int size)

{

//Generate a cryptic random number.

RNGCryptoServiceProvider rnd = new RNGCryptoServiceProvider();

byte[] b = new byte[size];

rnd.GetBytes(b);

// Return a Base64 string representation of the random number.

return Convert.ToBase64String(b);

}

[/c]

Although the aforesaid code could best fit in while generating a raw salt value, it is a bit complicated. Hence, we can generate random salt values by using an ASCII converter, too. The salt value can be anything, as we explained earlier. So just put any value in the plain-text box, for example, "keyencrypt" and convert it into hexadecimal format. We have generated the salt value that will be merged with secret to encrypt the plain text, as shown below:

As we can observe from the figure above, the salt value is in hex form; now prefix "0X" to each hex byte, place them into a sequence, and assign this value to an array of byte data type, which will referenced in the Rfc2898DeriveBytes later with the secret key. Just remember one thing: The salt value must be same during both encryption and decryption.

[c]

byte[] salt = new byte[]

{ 0x6B, 0x65, 0x79, 0x65, 0x6E, 0x63, 0x72, 0x79, 0x70, 0x74 };

[/c]

Hashing Algorithm

We shall encrypt the query string parameters by employing the AES (advanced encryption standard) algorithm, which is a variant of Rijandael algorithm and which, of course, provide strong security and performance. AES reduces the number of parameters you have to configure and allows you to work at a very high level of abstraction. The AES algorithm is a symmetric-key block cipher that can use keys of 128, 192, and 256 bits; it encrypts and decrypts data in blocks of 128 bits. The following image shows the entire life cycle of encrypting the query string and decrypting at the receiving site:

Okay, we now have all the ingredients for hashing: a query string, secret key, and salt value. In the Encrypt() method, the key derivation method Rfc2898DeriveBytes in AES implementation repeatedly hashes the password along with the salt, padding, and block size configuration.

[c]
string password = "ajaykumar007";

..

using (Aes encryptor = Aes.Create())

{

byte[] salt = new byte[]

{ 0x6B, 0x65, 0x79, 0x65, 0x6E, 0x63, 0x72, 0x79, 0x70, 0x74 };

Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(password, salt);

..

encryptor.Key = pdb.GetBytes(32);

encryptor.IV = pdb.GetBytes(16);

..

}

[/c]

Testing

Everything has been place in the Encrypt() method so far. Now run the project, enter some login information, and enable the "Secure Sign-in" check box. The user will be redirected to Welcome.aspx page, but notice the query string parameter value. It is encrypted and totally foolproof against hacking. For our convenience, we are also displaying the query string value (login data) over the welcome.aspx as shown below:

Query String Decryption

As you have seen in the previous figure, the query string is also being displayed over the page in encrypted form and that form also provides the facility to decrypt these ciphered values. This section showcases such a mechanism by the Decrypt() method, which would be called when the user clicks the Decrypt button. Here, we need two things: the key that is used to encrypt the query string parameters and the salt. Both of these must not be tampered with or decryption won't be happen.

[c]
private string Decrypt(string cipherText)

{

string password = "ajaykumar007";

byte[] cipherBytes = Convert.FromBase64String(cipherText);

using (Aes encryptor = Aes.Create())

{

byte[] salt = new byte[]

{ 0x6B, 0x65, 0x79, 0x65, 0x6E, 0x63, 0x72, 0x79, 0x70, 0x74 };

Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(password, salt);

encryptor.Key = pdb.GetBytes(32);

encryptor.IV = pdb.GetBytes(16);

using (MemoryStream ms = new MemoryStream())

{

..

}

}

..

}

[/c]

This time, click the Decrypt button and the web page will display the deciphered value that is entered over the login form and passed through the query string, as shown below:

Vulnerability and Redemption

This paper has demonstrated the generation of a persistent asymmetric key using the AES algorithm to encrypt and decrypt sensitive URL data. However, although the data in the query string are successfully encoded, this approach is still vulnerable to the Replay attack, MITM attack, and brute-force attack. Sensitive credentials are still passing in clear text form even if they are encrypted via the AES algorithm. A smart hacker can easily hack the user name and password via session hijacking, since HTTPS is not applied. The real problem here is that the user name and password are still being transmitted in plain text at least once to the server and then the encrypted strings are being passed back to the client. Those strings can be picked up off the wire and used in a replay attack. Here, the following methods should be used to fix the aforesaid problem in this article for redemption:

  • HTTPS—We shall have to install a digital certificate on the server in order to protect the communication traffic between client and server.
  • POST Method—Data that travels across the server via a query string using the GET method is always venerable to sniffing or hijacking. Hence, it is a good idea to use the POST method rather than GET method in such a scenario.
  • Secure Session Management—It is suggested that proper, secure session management should be used in order to foil man-in-the-middle and session hijacking attacks.
  • Encryption of XML Data—Data resided in XML file is always in clear text form, so it is not recommended to store crucial data in XML files.

Final Word

In this article, we have pinpointed the vulnerability in the query string parameter while encoding them by practicing weak cryptography methods where the data travels across the network in clear text and is susceptible to MITM attack. We have showcased the scenario and glitches that are often created by programmers or developers during the encryption and decryption of sensitive URL data using symmetric key encryption through the use of AES algorithm. Finally, we have seen the actual problem of applying weak cryptography methods as well as redemption methods.

Ajay Yadav
Ajay Yadav

Ajay Yadav is an author, Cyber Security Specialist, SME, Software Engineer, and System Programmer with more than eight years of work experience. He earned a Master and Bachelor Degree in Computer Science, along with abundant premier professional certifications. For several years, he has been researching Reverse Engineering, Secure Source Coding, Advance Software Debugging, Vulnerability Assessment, System Programming and Exploit Development.

He is a regular contributor to programming journal and assistance developer community with blogs, research articles, tutorials, training material and books on sophisticated technology. His spare time activity includes tourism, movies and meditation. He can be reached at om.ajay007[at]gmail[dot]com