Thursday, January 22, 2009

Obfuscating QueryString Parameters

I need to provide a link to a URL which contains some parameters I'd like to obfuscate. Specifically, within an automatically generated Email, instead of embedding a link /sendMessage.aspx?address=foo@bar.com&expiry=2009-01-22Z13:30 , I'd prefer /sendMessage.aspx?token=s0MEth1ngUnfath0mable!

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 file
            File.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 generated
        private const string KEY = "MXvUAmUobjA=";
 
        public static string Obfuscate(object targetObject)
        {
            // Binary serialize
            MemoryStream 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 string
            string quotable = Convert.ToBase64String(encrypted);
 
            return quotable;
        }
 
        public static object Deobfuscate(string quotable)
        {
            // Retrieve the bytes from the quotable string
            byte[] 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);
 
            // Deserialize
            MemoryStream 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 expired
                Response.End();
            }
            else
            {
                string toAddress = token.EmailAddress;
                // etc
            }

Wednesday, January 14, 2009

Self-Hosting WCF

I'd like to have two separate processes (both under my control) communicate over WCF. What's the easiest way to achieve this? As an example, I'd like Process 1 (a client) to be able to check the health or presence of Process 2 (the server) by periodically requesting the server's local time.

To permit communication, we need to define a contract between the two processes. All I'd like this contract (let's call it HealthCheck) to define is an operation GetTimestamp. Given that my two separate processes will be two separate projects in Visual Studio, and that they both need to access this contract, we'll create a third class library called SharedTypes that will contain nothing but the contract.


SharedTypes (contains the contract)

Assembly references: System.ServiceModel

We'll define the contract as an interface, decorated by System.ServiceModel.ServiceContract. The interface's one method signature (GetTimestamp) should be decorated by System.ServiceModel.OperationContract.

using System;
using System.ServiceModel;
 
namespace SharedTypes
{
    [ServiceContract]
    public interface IHealthCheck
    {
        [OperationContract]
        DateTime GetTimestamp();
    }
}


Server

Assembly references: SharedTypes, System.ServiceModel

The server process, perhaps unsurprisingly, will need to implement this contract interface as follows:

using System;
using SharedTypes;
 
namespace Server
{
    class HealthCheck : IHealthCheck
    {
        public DateTime GetTimestamp()
        {
            return DateTime.Now;
        }
    }
}

The program's main method will simply instantiate and open a ServiceHost to expose the service, and hang around in the background:

using System;
using System.ServiceModel;
 
namespace Server
{
    class Program
    {
        static void Main(string[] args)
        {
            ServiceHost serviceHost = new ServiceHost(typeof(HealthCheck));
            serviceHost.Open();
 
            // Keep the process running (hence the service open) for an hour
            System.Threading.Thread.Sleep(3600000);
        }
    }
}

Finally, we'll need to specify the address and protocol by which the service can be called. Part of the joy of WCF is allowing this to be configurable by an end-user or sysadmin, so we'll specify a minimal app.config to contain the core settings we require:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
   <system.serviceModel>
      <services>
         <service name="Server.HealthCheck">
            <endpoint address="basic" binding="basicHttpBinding"
                      contract="SharedTypes.IHealthCheck" />
            <host>
               <baseAddresses>
                  <add baseAddress="http://localhost:8080/HealthCheck" />
               </baseAddresses>
            </host>
         </service>
      </services>
   </system.serviceModel>
</configuration>


Client

Assembly references: SharedTypes, System.ServiceModel

The client will also need to have a class that implements the service contract, but we'll make it such that calls to its methods actually result in a remote call over WCF:

using System;
using System.ServiceModel;
using SharedTypes;
 
namespace Client
{
    public class HealthCheck : ClientBase<IHealthCheck>, IHealthCheck
    {
        public DateTime GetTimestamp()
        {
            return base.Channel.GetTimestamp();
        }
    }
}

The program's main method will just sit in a loop calling and echoing the result from GetTimestamp:

using System;
 
namespace Client
{
    class Program
    {
        static void Main(string[] args)
        {
            HealthCheck healthCheck = new HealthCheck();
            while (true)
            {
                Console.WriteLine(healthCheck.GetTimestamp());
 
                // Wait for a second
                System.Threading.Thread.Sleep(1000);
            }
        }
    }
}

Again, we'll need to specify in app.config the location of the server, and the protocol we want to use:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
   <system.serviceModel>
      <client>
         <endpoint address="http://localhost:8080/HealthCheck/basic"
                   binding="basicHttpBinding"
                   contract="SharedTypes.IHealthCheck" />
      </client>
   </system.serviceModel>
</configuration>

Introduction

History, or at least working within my company, has shown that the simplest, most basic implementations of code stand the most chance of being correct. As soon as code is littered with endless if-then-else scenarios or numerous configuration options, it becomes increasingly difficult to spot the core logic, and inevitably, the bugs or inconsistencies.

Working in the Microsoft space, I have become increasingly frustrated with the typical low signal-to-noise ratio of documentation, samples and articles about Microsoft technologies. Exacerbated by the fact that Microsoft developers (or more specifically Visual Studio developers) have become ever-more dependent on code generators, hidden-away partial classes, and bloated configuration files, there is a tendency for code examples to be little more than screenshots showing which buttons should be pushed within Visual Studio, and which of the configuration options should be tweaked in the sea of automatically generated XML.

The code samples I plan to show in this blog will attempt to represent the simplest implementations of particular technologies. Paring back the unnecessary bloat from Visual Studio's code generators and from the multitude of code samples on the web is often a fairly time-consuming task, and the primary purpose of these posts is to record any outcomes as notes to myself. Nonetheless, I hope they might also prove useful to others.