I need to Encrypt the URLs in my ASP.NET MVC application.
Do I need to write the code in Global page in Route Collection to Encrypt all the URLs?
Based on the answers here, which did not work for me BTW, I found another solution based on my particular MVC implementation, and the fact that it also works depending on whether you're using II7 or II6. Slight changes are needed in both cases.
II6
Firstly, you need to add the following into your web.config (root, not the one in View folder).
II7
add this instead into your web.config (root, not the one in View folder).
Or you could add both. It doesn't matter really.
Next use this class. I called it, as you've probably noticed - URIHandler.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.IO;
using System.Text;
using System.Security.Cryptography;
using System.Diagnostics.CodeAnalysis;
public class URIHandler : IHttpModule
{
#region IHttpModule members
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(context_BeginRequest);
}
#endregion
private const string PARAMETER_NAME = "enc=";
private const string ENCRYPTION_KEY = "key";
private void context_BeginRequest(object sender, EventArgs e)
{
HttpContext context = HttpContext.Current;
//if (context.Request.Url.OriginalString.Contains("aspx") && context.Request.RawUrl.Contains("?"))
if (context.Request.RawUrl.Contains("?"))
{
string query = ExtractQuery(context.Request.RawUrl);
string path = GetVirtualPath();
if (query.StartsWith(PARAMETER_NAME, StringComparison.OrdinalIgnoreCase))
{
// Decrypts the query string and rewrites the path.
string rawQuery = query.Replace(PARAMETER_NAME, string.Empty);
string decryptedQuery = Decrypt(rawQuery);
context.RewritePath(path, string.Empty, decryptedQuery);
}
else if (context.Request.HttpMethod == "GET")
{
// Encrypt the query string and redirects to the encrypted URL.
// Remove if you don't want all query strings to be encrypted automatically.
string encryptedQuery = Encrypt(query);
context.Response.Redirect(path + encryptedQuery);
}
}
}
///
/// Parses the current URL and extracts the virtual path without query string.
///
/// The virtual path of the current URL.
private static string GetVirtualPath()
{
string path = HttpContext.Current.Request.RawUrl;
path = path.Substring(0, path.IndexOf("?"));
path = path.Substring(path.LastIndexOf("/") + 1);
return path;
}
///
/// Parses a URL and returns the query string.
///
/// The URL to parse.
/// The query string without the question mark.
private static string ExtractQuery(string url)
{
int index = url.IndexOf("?") + 1;
return url.Substring(index);
}
#region Encryption/decryption
///
/// The salt value used to strengthen the encryption.
///
private readonly static byte[] SALT = Encoding.ASCII.GetBytes(ENCRYPTION_KEY.Length.ToString());
///
/// Encrypts any string using the Rijndael algorithm.
///
/// The string to encrypt.
/// A Base64 encrypted string.
[SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
public static string Encrypt(string inputText)
{
RijndaelManaged rijndaelCipher = new RijndaelManaged();
byte[] plainText = Encoding.Unicode.GetBytes(inputText);
PasswordDeriveBytes SecretKey = new PasswordDeriveBytes(ENCRYPTION_KEY, SALT);
using (ICryptoTransform encryptor = rijndaelCipher.CreateEncryptor(SecretKey.GetBytes(32), SecretKey.GetBytes(16)))
{
using (MemoryStream memoryStream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(plainText, 0, plainText.Length);
cryptoStream.FlushFinalBlock();
return "?" + PARAMETER_NAME + Convert.ToBase64String(memoryStream.ToArray());
}
}
}
}
///
/// Decrypts a previously encrypted string.
///
/// The encrypted string to decrypt.
/// A decrypted string.
[SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
public static string Decrypt(string inputText)
{
RijndaelManaged rijndaelCipher = new RijndaelManaged();
byte[] encryptedData = Convert.FromBase64String(inputText);
PasswordDeriveBytes secretKey = new PasswordDeriveBytes(ENCRYPTION_KEY, SALT);
using (ICryptoTransform decryptor = rijndaelCipher.CreateDecryptor(secretKey.GetBytes(32), secretKey.GetBytes(16)))
{
using (MemoryStream memoryStream = new MemoryStream(encryptedData))
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
byte[] plainText = new byte[encryptedData.Length];
int decryptedCount = cryptoStream.Read(plainText, 0, plainText.Length);
return Encoding.Unicode.GetString(plainText, 0, decryptedCount);
}
}
}
}
#endregion
}
You don't need a NameSpace
.
The above class does everything you need to Encrypt and Decrypt any URL parameters starting with '?'
character. It even does a nice job of renaming your parameter variables to 'enc', which is a bonus.
Lastly, place the class in your App_Start
folder, and NOT the App_Code
folder, as that will conflict with 'unambiguous errors'.
Done.
Credits:
https://www.codeproject.com/questions/1036066/how-to-hide-url-parameter-asp-net-mvc
https://msdn.microsoft.com/en-us/library/aa719858(v=vs.71).aspx
HttpModule Init method were not called
C# Please specify the assembly explicitly in the type name
https://stackoverflow.com/questions/1391060/httpmodule-with-asp-net-mvc-not- being-called