Broken down, my requirements for obfuscation are:
- Serialize an object which contains my parameters (address and expiry), so that it can be transmitted to a different server (i.e. the web server)
- Encrypt the serialized bytes to prevent tampering
- Make Quotable the encrypted bytes so that they can be included within a URL querystring (albeit after a suitable UrlEncode)
Key Generation
My security requirements are pretty basic, as I'm not trying to protect anything desperately important here - rather prevent basic tampering by spotting patterns in the quotable string. Therefore, I'll keep things as simple as possible and take some shortcuts, for example using a basic security algorithm (DES), and embedding the encryption key within my source code.
Firstly, we'll need to generate a key upon which the encryption and decryption can occur:
using System;using System.IO;using System.Security.Cryptography;namespace ObfuscationTesting{class Program
{static void Main(string[] args)
{ // Generate a suitable key DESCryptoServiceProvider desCryptoServiceProvider =new DESCryptoServiceProvider();
desCryptoServiceProvider.GenerateKey();
// Represent key as a quotable string string base64EncodedKey = Convert.ToBase64String(desCryptoServiceProvider.Key); // Save to fileFile.WriteAllText(@"C:\key.txt", base64EncodedKey);
}
}
}
Obfuscator Class
Now, we'll create a static class that takes any serializable object and returns us a string which represents that object (and, naturally, allows us to re-create the original object from such a string):
using System;using System.IO;using System.Runtime.Serialization.Formatters.Binary;using System.Security.Cryptography;namespace ObfuscationTesting{public static class Obfsucator
{ // The key previously generatedprivate const string KEY = "MXvUAmUobjA=";
public static string Obfuscate(object targetObject)
{ // Binary serializeMemoryStream memoryStream = new MemoryStream();
BinaryFormatter binaryFormatter = new BinaryFormatter();
binaryFormatter.Serialize(memoryStream, targetObject);
byte[] serialized = memoryStream.GetBuffer(); // Encrypt DESCryptoServiceProvider desCryptoServiceProvider =new DESCryptoServiceProvider();
desCryptoServiceProvider.Key = Convert.FromBase64String(KEY); desCryptoServiceProvider.IV = Convert.FromBase64String(KEY); byte[] encrypted = desCryptoServiceProvider.CreateEncryptor()
.TransformFinalBlock(serialized, 0, serialized.Length);
// Render as stringstring quotable = Convert.ToBase64String(encrypted);
return quotable;}
public static object Deobfuscate(string quotable)
{ // Retrieve the bytes from the quotable stringbyte[] encrypted = Convert.FromBase64String(quotable);
// Decrypt DESCryptoServiceProvider desCryptoServiceProvider =new DESCryptoServiceProvider();
desCryptoServiceProvider.Key = Convert.FromBase64String(KEY); desCryptoServiceProvider.IV = Convert.FromBase64String(KEY); byte[] serialized = desCryptoServiceProvider.CreateDecryptor()
.TransformFinalBlock(encrypted, 0, encrypted.Length);
// DeserializeMemoryStream memoryStream = new MemoryStream(serialized);
BinaryFormatter binaryFormatter = new BinaryFormatter();
object deserialized = binaryFormatter.Deserialize(memoryStream); return deserialized;}
}
}
Usage
We'll create a class which contains the parameters I'd like to represent, remembering to mark it as serializable:
using System;namespace ObfuscationTesting{ [Serializable]public class Token
{public string EmailAddress { get; set; }
public DateTime Expiry { get; set; }
}
}
To construct the URL with the obfuscated parameters, all we need to have is:
(Assembly reference: System.Web)
using System;using System.Web;...
Token token = new Token()
{ EmailAddress = "foo@bar.com", Expiry = DateTime.Now.AddHours(1)};
string url = String.Format(@"/sendMessage.aspx?token={0}",
HttpUtility.UrlEncode(Obfsucator.Obfuscate(token)));
And, on our web page that receives the URL, we just need to de-obfuscate again:
string tokenString = Request.QueryString["token"];
Token token = (Token)Obfsucator.Deobfuscate(tokenString);
if (token.Expiry < DateTime.Now)
{ // Token has expiredResponse.End();
}
else { string toAddress = token.EmailAddress; // etc}

No comments:
Post a Comment