IT:AD:Patterns:Don't Drop your pants Strategy

Summary

Security is hard with a capital H.

Mainly because there's only a handful of you developing the walls, while there's a whole horde of people banging away at your ports.

So you want to ensure that you don't give them the keys to the place, right?

Even if you use an AntiForgeryToken/, don't round trip your database keys/ids as ClearText/.

In other words, although you need to round trip to the end user an Id of some kind in the View Model being rendered, or the ViewModel/ being sent up to the User Agent/, don't send out a database key.

Obfuscation won't help either.

It's pretty common to see users send out compressed Guids -- guids collapsed to the shortest amount of string text as possible. But that's not enough to thwart a determined [[IT/#Threat/]].

The very least you can do is combine it with a secret they don't have.

XOR

A simple first step solution is using something like:

void Main()
{
			//Server
			var secretId = new Guid("2b6f0cc9-04d1-37be-2e17-30235f566409");
			secretId.Dump();
			byte[] secretBytes;// = secretId.ToByteArray();
			secretBytes = GetBytes( "Special" + secretId.ToString("D"), 100);


			
			var sessionId = Guid.NewGuid();
			sessionId.Dump();
			var sessionBytes = sessionId.ToByteArray();



			byte[] xor = new byte[sessionBytes.Length];
			for (int i=0;i<sessionBytes.Length;i++)
			{
				xor[i] = (byte) (secretBytes[i]^ sessionBytes[i] );
			}
			var result =  ByteArrayToString(xor); 
			
//Send it out...
//...
//Get it back...
			xor = StringToByteArray(result);
			var xor2 = new byte[sessionBytes.Length];
			for (int i=0;i<sessionBytes.Length;i++)
			{
				xor2[i] = (byte) (xor[i] ^ secretBytes[i]);
			}

            
			Guid g = new Guid(xor2);
			g.Dump();
		}

		public static byte[] StringToByteArray(String hex)
		{
			int NumberChars = hex.Length;
			byte[] bytes = new byte[NumberChars / 2];
			for (int i = 0; i < NumberChars; i += 2)
				bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
			return bytes;
		}
		
		public static string ByteArrayToString(byte[] ba)
		{
			StringBuilder hex = new StringBuilder(ba.Length * 2);
			foreach (byte b in ba)
				hex.AppendFormat("{0:x2}", b);
			return hex.ToString();
		}

static byte[] GetBytes(string str, int length=0)
{
    if (length == 0){length = str.Length * sizeof(char);}
	byte[] bytes = new byte[length];
	var src = str.ToCharArray();
	System.Buffer.BlockCopy(src, 0, bytes, 0, Math.Min(length,src.Length));
	return bytes;
}
static string GetString(byte[] bytes)
{
	char[] chars = new char[bytes.Length / sizeof(char)];
	System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
	return new string(chars);
}
// Define other methods and classes here
 

You can then compress/obfuscate that to your hearts content afterwards.

Addendum

Note that using Guid's as an Id is always problematic…They're fast as heck when indexed – the problem is that they are random and when a new record is created, the guid has to be inserted into the index table…somewhere…if it is near the top, it has to move down everything below it…you can see how that quickly gets slow. Much slower than an auto-incrementing integer that always sticks it at the end.

Hence why I recommend looking at the DistributedIdentifierService in XActLib the next time you need a Guid that's ordered and unique across platforms (yup ;-).