Hello, I have code in a asp.net application that runs along side other 3rd party code in the same application. I am inserting a custom object that has some information I want to keep private into the HttpContext object so that later in the pipeline some
of my other code can retrieve it. Sessions, application, cookies are not an option here. There is the possibility that 3rd party code can run after I set this object and before my code runs again to read the data. What are some ways to prevent reading/tampering
of this information? The solution I have so far is this:
Custom object has get and set methods like so
public object GetValue(string Password, string Key);
public void SetValue(string Password, string Key, object Value);
-The password is predetermined and is checked before allowing the method to continue.
-If my code tries to get this object from HttpContext.Items and is either NULL or getting a value returns Null, then I know that the object has been overriden or tampered with, which I can live with I just can't reveal its values.
Although I don't know how, I can imagine that 3rd party code can retrieve this object from HttpContext, somehow stream the bytes to disk somewhere and then reverse engineer it to see whats inside?
You can use encryption to store private data to the context.
using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Security.Cryptography;
using System.Runtime.Serialization.Formatters.Binary;
internal static class Util
{
/// <summary>
/// Serializes the specified object using a binary serializer
/// </summary>
/// <param name="sourceInstance">Instance to be serialized</param>
/// <returns>Byte array</returns>
public static byte[] BinarySerialize (this object sourceInstance)
{
if (sourceInstance == null)
{
return null;
}
BinaryFormatter binFmtr = new BinaryFormatter ();
using (MemoryStream memStream = new MemoryStream ())
{
binFmtr.Serialize (memStream, sourceInstance);
return memStream.ToArray ();
}
}
/// <summary>
/// Deserialize a byte buffer (serialized by BinarySerialize) to its corresponding instance
/// </summary>
/// <param name="sourceInstanceData"></param>
/// <returns></returns>
public static object BinaryDeserialize (this byte[] sourceInstanceData)
{
if ((sourceInstanceData == null) ||
(sourceInstanceData.Length == 0))
{
return null;
}
BinaryFormatter binFmtr = new BinaryFormatter ();
using (MemoryStream memStream = new MemoryStream (sourceInstanceData))
{
return binFmtr.Deserialize (memStream);
}
}
/// <summary>
/// Encrypt Data
/// </summary>
/// <param name="dataBlob">Data</param>
/// <returns>Encrypted Data</returns>
[SuppressMessage ("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
public byte[] EncryptData (byte[] dataBlob)
{
if (dataBlob == null)
{
return null;
}
if (dataBlob.Length == 0)
{
return new byte[0];
}
TripleDESCryptoServiceProvider cryptoProvider = new TripleDESCryptoServiceProvider ();
cryptoProvider.Key = HexStringToByteArray ("1EBF07742BF99D56DA8C4048F3832E5B93251A73A3C9215B");
cryptoProvider.IV = HexStringToByteArray ("AB4F972CA38C2437");
using (MemoryStream destStream = new MemoryStream ())
{
using (CryptoStream cryptoStream = new CryptoStream (destStream, cryptoProvider.CreateEncryptor (), CryptoStreamMode.Write))
{
cryptoStream.Write (dataBlob, 0, dataBlob.Length);
cryptoStream.FlushFinalBlock ();
return destStream.ToArray ();
}
}
}
/// <summary>
/// Decrypts data
/// </summary>
/// <param name="dataBlob">Data</param>
/// <returns>Decrypted data</returns>
[SuppressMessage ("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
public byte[] DecryptData (byte[] dataBlob)
{
if (dataBlob == null)
{
return null;
}
if (dataBlob.Length == 0)
{
return new byte[0];
}
TripleDESCryptoServiceProvider cryptoProvider = new TripleDESCryptoServiceProvider ();
cryptoProvider.Key = HexStringToByteArray ("1EBF07742BF99D56DA8C4048F3832E5B93251A73A3C9215B");
cryptoProvider.IV = HexStringToByteArray ("AB4F972CA38C2437");
using (MemoryStream destStream = new MemoryStream ())
{
using (CryptoStream cryptoStream = new CryptoStream (destStream, cryptoProvider.CreateDecryptor (), CryptoStreamMode.Write))
{
cryptoStream.Write (dataBlob, 0, dataBlob.Length);
cryptoStream.FlushFinalBlock ();
return destStream.ToArray ();
}
}
}
/// <summary>
/// Converts a hex representation of data to byte array
/// </summary>
/// <param name="hexText">Hex representation of data</param>
/// <returns>Byte array</returns>
public static byte[] HexStringToByteArray (string hexText)
{
if (hexText == null)
{
return null;
}
byte[] returnBytes = new byte[hexText.Length / 2];
for (int i = 0; i < returnBytes.Length; i++)
{
returnBytes[i] = Convert.ToByte (hexText.Substring (i * 2, 2), 16);
}
return returnBytes;
}
}
Store the byte array returned by EncryptData (BinarySerialize (<yourobject>)) into the context
and use BinaryDeserialize (DecryptData (<stored byte array from the context>)) to retrieve back the object
Change the Key and Initialization vector given in the above code to some other random sequence of hex digits before using the code.
If the data is tamprered with, then an exception will be thrown when you try to decrypt the data retrieved from the context. So wrap it up in a try-catch. The content will not be readable unless the tampering party knows your Key & IV which will be within
your code.
Your Key & IV can be read if the other party gets access to your code binaries by using Reflector. To avoid it, you will have to obfuscate your code during your build phase. Even then it is not completely safe. But it makes atleast very hard to un-obfuscate
your code and then take your key & iv and then decrypt the data your stored on the context.
Note that, the above methods are cut from my code base and hence I could not check the compilability. If you get any compilation errors, please check the MSDN to reference appropriate namespaces at the beginning of the file
Thanks for the sugguestion, so is the encryption even needed if the keys will be stored into the object anyways? I think if someone could un obfuscate the code, at that point they could easily decrypt the string. But I like the idea of obfuscating the code,
thanks.
You need a key to encrypt data. You need the same key to decrypt the data. So if the keys are stored in the object, and the object is encrypted, how can you decrypt it without first having the keys?
Putting the keys in the code soes not necessarily expose them to the threats. The code usually lies in a dll file hosted on the server and will be accessible to the server administrators.
You can store the keys anywhere, if not in the code - for eg. in the Registry etc.,
What exactly is the scenario you're going for? Is your component fully trusted and you want to prevent partial trust code from accessing it? If so, just wrap the object to be stored into Items in a type that's internal to your application, and protect
the class with a demand:
You can put an instance of MyWrapper into HttpContext.Items. Partial trust code will be able to get the opaque instance of MyWrapper by enumerating Items, but they can't look at WrappedObject since they don't fulfill the required demand. When your fully
trusted code reads the MyWrapper instance back out, you're free to look at WrappedObject since your own code implicitly meets the required demand.
Edit: This won't prevent replays, but you can code defensively around that, e.g. by keeping a reference to the correct HttpContext inside of the wrapper. This sample is meant to prevent partial trust code from
creating or inspecting instances of MyWrapper.
kahlua001us
Member
16 Points
43 Posts
Securing HttpContext.Items
Aug 12, 2010 06:40 PM|LINK
Hello, I have code in a asp.net application that runs along side other 3rd party code in the same application. I am inserting a custom object that has some information I want to keep private into the HttpContext object so that later in the pipeline some of my other code can retrieve it. Sessions, application, cookies are not an option here. There is the possibility that 3rd party code can run after I set this object and before my code runs again to read the data. What are some ways to prevent reading/tampering of this information? The solution I have so far is this:
Custom object has get and set methods like so
public object GetValue(string Password, string Key);
public void SetValue(string Password, string Key, object Value);
-The password is predetermined and is checked before allowing the method to continue.
-If my code tries to get this object from HttpContext.Items and is either NULL or getting a value returns Null, then I know that the object has been overriden or tampered with, which I can live with I just can't reveal its values.
Although I don't know how, I can imagine that 3rd party code can retrieve this object from HttpContext, somehow stream the bytes to disk somewhere and then reverse engineer it to see whats inside?
Has anyone faced this task before?
ravikatha
Contributor
2136 Points
348 Posts
Re: Securing HttpContext.Items
Aug 12, 2010 07:30 PM|LINK
You can use encryption to store private data to the context.
using System; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Security.Cryptography; using System.Runtime.Serialization.Formatters.Binary; internal static class Util { /// <summary> /// Serializes the specified object using a binary serializer /// </summary> /// <param name="sourceInstance">Instance to be serialized</param> /// <returns>Byte array</returns> public static byte[] BinarySerialize (this object sourceInstance) { if (sourceInstance == null) { return null; } BinaryFormatter binFmtr = new BinaryFormatter (); using (MemoryStream memStream = new MemoryStream ()) { binFmtr.Serialize (memStream, sourceInstance); return memStream.ToArray (); } } /// <summary> /// Deserialize a byte buffer (serialized by BinarySerialize) to its corresponding instance /// </summary> /// <param name="sourceInstanceData"></param> /// <returns></returns> public static object BinaryDeserialize (this byte[] sourceInstanceData) { if ((sourceInstanceData == null) || (sourceInstanceData.Length == 0)) { return null; } BinaryFormatter binFmtr = new BinaryFormatter (); using (MemoryStream memStream = new MemoryStream (sourceInstanceData)) { return binFmtr.Deserialize (memStream); } } /// <summary> /// Encrypt Data /// </summary> /// <param name="dataBlob">Data</param> /// <returns>Encrypted Data</returns> [SuppressMessage ("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")] public byte[] EncryptData (byte[] dataBlob) { if (dataBlob == null) { return null; } if (dataBlob.Length == 0) { return new byte[0]; } TripleDESCryptoServiceProvider cryptoProvider = new TripleDESCryptoServiceProvider (); cryptoProvider.Key = HexStringToByteArray ("1EBF07742BF99D56DA8C4048F3832E5B93251A73A3C9215B"); cryptoProvider.IV = HexStringToByteArray ("AB4F972CA38C2437"); using (MemoryStream destStream = new MemoryStream ()) { using (CryptoStream cryptoStream = new CryptoStream (destStream, cryptoProvider.CreateEncryptor (), CryptoStreamMode.Write)) { cryptoStream.Write (dataBlob, 0, dataBlob.Length); cryptoStream.FlushFinalBlock (); return destStream.ToArray (); } } } /// <summary> /// Decrypts data /// </summary> /// <param name="dataBlob">Data</param> /// <returns>Decrypted data</returns> [SuppressMessage ("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")] public byte[] DecryptData (byte[] dataBlob) { if (dataBlob == null) { return null; } if (dataBlob.Length == 0) { return new byte[0]; } TripleDESCryptoServiceProvider cryptoProvider = new TripleDESCryptoServiceProvider (); cryptoProvider.Key = HexStringToByteArray ("1EBF07742BF99D56DA8C4048F3832E5B93251A73A3C9215B"); cryptoProvider.IV = HexStringToByteArray ("AB4F972CA38C2437"); using (MemoryStream destStream = new MemoryStream ()) { using (CryptoStream cryptoStream = new CryptoStream (destStream, cryptoProvider.CreateDecryptor (), CryptoStreamMode.Write)) { cryptoStream.Write (dataBlob, 0, dataBlob.Length); cryptoStream.FlushFinalBlock (); return destStream.ToArray (); } } } /// <summary> /// Converts a hex representation of data to byte array /// </summary> /// <param name="hexText">Hex representation of data</param> /// <returns>Byte array</returns> public static byte[] HexStringToByteArray (string hexText) { if (hexText == null) { return null; } byte[] returnBytes = new byte[hexText.Length / 2]; for (int i = 0; i < returnBytes.Length; i++) { returnBytes[i] = Convert.ToByte (hexText.Substring (i * 2, 2), 16); } return returnBytes; } }Store the byte array returned by EncryptData (BinarySerialize (<yourobject>)) into the context
and use BinaryDeserialize (DecryptData (<stored byte array from the context>)) to retrieve back the object
Change the Key and Initialization vector given in the above code to some other random sequence of hex digits before using the code.
If the data is tamprered with, then an exception will be thrown when you try to decrypt the data retrieved from the context. So wrap it up in a try-catch. The content will not be readable unless the tampering party knows your Key & IV which will be within your code.
Your Key & IV can be read if the other party gets access to your code binaries by using Reflector. To avoid it, you will have to obfuscate your code during your build phase. Even then it is not completely safe. But it makes atleast very hard to un-obfuscate your code and then take your key & iv and then decrypt the data your stored on the context.
Note that, the above methods are cut from my code base and hence I could not check the compilability. If you get any compilation errors, please check the MSDN to reference appropriate namespaces at the beginning of the file
kahlua001us
Member
16 Points
43 Posts
Re: Securing HttpContext.Items
Aug 12, 2010 08:14 PM|LINK
Thanks for the sugguestion, so is the encryption even needed if the keys will be stored into the object anyways? I think if someone could un obfuscate the code, at that point they could easily decrypt the string. But I like the idea of obfuscating the code, thanks.
ravikatha
Contributor
2136 Points
348 Posts
Re: Securing HttpContext.Items
Aug 14, 2010 07:07 PM|LINK
You need a key to encrypt data. You need the same key to decrypt the data. So if the keys are stored in the object, and the object is encrypted, how can you decrypt it without first having the keys?
Putting the keys in the code soes not necessarily expose them to the threats. The code usually lies in a dll file hosted on the server and will be accessible to the server administrators.
You can store the keys anywhere, if not in the code - for eg. in the Registry etc.,
levib
Star
7702 Points
1099 Posts
Microsoft
Re: Securing HttpContext.Items
Aug 16, 2010 09:49 AM|LINK
What exactly is the scenario you're going for? Is your component fully trusted and you want to prevent partial trust code from accessing it? If so, just wrap the object to be stored into Items in a type that's internal to your application, and protect the class with a demand:
[PermissionSet(SecurityAction.LinkDemand, Name="FullTrust")] internal sealed class MyWrapper { internal object WrappedObject; }You can put an instance of MyWrapper into HttpContext.Items. Partial trust code will be able to get the opaque instance of MyWrapper by enumerating Items, but they can't look at WrappedObject since they don't fulfill the required demand. When your fully trusted code reads the MyWrapper instance back out, you're free to look at WrappedObject since your own code implicitly meets the required demand.
Edit: This won't prevent replays, but you can code defensively around that, e.g. by keeping a reference to the correct HttpContext inside of the wrapper. This sample is meant to prevent partial trust code from creating or inspecting instances of MyWrapper.