Click here to Skip to main content
Click here to Skip to main content

HttpSecureCookie, A Way to Encrypt Cookies with ASP.NET 2.0

By , 3 Apr 2006
 

Introduction

I really have some good laughs when I tamper with cookies on my machine and watch the results when it is submitted back to the site. On the other hand, I don’t want any one to do the same to the cookies that I make!

Cookies, most of the times, shouldn’t be in plain text, at least, they should be tamper-proof! Revealing the content of your cookies might give curious and malicious people an idea about your application’s architecture, and that might help hacking it.

ASP.NET encodes and hashes its authorization ticket, making it secure and tamper-proof. However, the methods used to secure authorization cookies are inaccessible from outside the .NET framework libraries, so you can’t protect your own cookie using these methods; you need to protect it yourself using your own encryption key, encoding and hashing algorithms. HttpSecureCookie works around this by accessing the same methods ASP.NET uses for cookie authorization.

Of course, you shouldn’t save valuable information in your cookies, but if you have to, then this library is at your disposal.

Background

Before you start using this code, if you do not know what MachineKey is, I highly recommend checking this MSDN article: How To: Configure MachineKey in ASP.NET 2.0.

ASP.NET uses the System.Web.Security.CookieProtectionHelper internal class to decode and encode the content of a cookie before submitting it to the client. This class is based on the MachineKey. I wonder why Microsoft kept this class internal!?

To be able to access this internal class, I had to use reflection to be able to access the Decode and Encode methods of CookieProtectionHelper.

Eric Newton has a similar and good article on CP: Encrypting cookies to prevent tampering. However, that code is made for .NET 1.1 and it doesn't work with .NET 2.0 (but it does with some modifications); moreover, its resulting cipher text is in binary format versus being in encrypted format, and I don't know if this is a security risk. Also, I am accessing a higher level class System.Web.Security.CookieProtectionHelper than the one used by that article, System.Web.Configuration.MachineKey, to obtain the cryptography service, and that saved me time by not writing some low level code.

There is also another available method for encoding cookies, by using the FormsAuthenticationTicket and FormsAuthentication.Encrypt; for more information, check the section "Creating the Forms Authentication Cookie" on Explained: Forms Authentication in ASP.NET 2.0. However, I believe, the method mentioned in this article is more flexible.

Obtaining Reference to the CookieProtectionHelper Class via Reflection

To be able to access System.Web.Security.CookieProtectionHelper, I had to create a wrapper class CookieProtectionHelperWrapper which uses reflection to obtain a reference to the underlying methods and exposes the same methods as of the original class:

public static class CookieProtectionHelperWrapper {

    private static MethodInfo _encode;
    private static MethodInfo _decode;

    static CookieProtectionHelperWrapper() {
        // obtaining a reference to System.Web assembly
        Assembly systemWeb = typeof(HttpContext).Assembly;
        if (systemWeb == null) {
            throw new InvalidOperationException(
                "Unable to load System.Web.");
        }
        // obtaining a reference to the internal class CookieProtectionHelper
        Type cookieProtectionHelper = systemWeb.GetType(
                "System.Web.Security.CookieProtectionHelper");
        if (cookieProtectionHelper == null) {
            throw new InvalidOperationException(
                "Unable to get the internal class CookieProtectionHelper.");
        }
        // obtaining references to the methods of CookieProtectionHelper class
        _encode = cookieProtectionHelper.GetMethod(
                "Encode", BindingFlags.NonPublic | BindingFlags.Static);
        _decode = cookieProtectionHelper.GetMethod(
                "Decode", BindingFlags.NonPublic | BindingFlags.Static);

        if (_encode == null || _decode == null) {
            throw new InvalidOperationException(
                "Unable to get the methods to invoke.");
        }
    }

    public static string Encode(CookieProtection cookieProtection, 
                                byte[] buf, int count) {
        return (string)_encode.Invoke(null, 
                new object[] { cookieProtection, buf, count });
    }

    public static byte[] Decode(CookieProtection cookieProtection, 
                                string data) {
        return (byte[])_decode.Invoke(null, 
                new object[] { cookieProtection, data });
    }

}

MachineKeyCryptography: A Cryptography Class Based on MachineKey

MachineKeyCryptography is a static class that provides text ciphering and tamper-proofing services, it provides higher level access to CookieProtectionHelperWrapper. So, if you want to cipher any text based on the machine key, this class is the right one to use.

public static string Encode(string text, CookieProtection cookieProtection) {
    if (string.IsNullOrEmpty(text) || cookieProtection == CookieProtection.None) {
        return text;
    }
    byte[] buf = Encoding.UTF8.GetBytes(text);
    return CookieProtectionHelperWrapper.Encode(cookieProtection, buf, buf.Length); 
}

public static string Decode(string text, CookieProtection cookieProtection) {
    if (string.IsNullOrEmpty(text)) {
        return text;
    }
    byte[] buf;
    try {
        buf = CookieProtectionHelperWrapper.Decode(cookieProtection, text);
    }
    catch(Exception ex) {
        throw new InvalidCypherTextException(
            "Unable to decode the text", ex.InnerException);
    }
    if (buf == null || buf.Length == 0) {
        throw new InvalidCypherTextException(
            "Unable to decode the text");
    }
    return Encoding.UTF8.GetString(buf, 0, buf.Length);
}

HttpSecureCookie Class

This static class will handle the service of securing the content of a cookie. Also, it provides a service to clone a cookie. This class uses MachineKeyCryptography internally to provide crypting services:

public static class HttpSecureCookie {

    public static HttpCookie Encode(HttpCookie cookie) {
        return Encode(cookie, CookieProtection.All);
    }

    public static HttpCookie Encode(HttpCookie cookie, 
                  CookieProtection cookieProtection) {
        HttpCookie encodedCookie = CloneCookie(cookie);
        encodedCookie.Value = 
          MachineKeyCryptography.Encode(cookie.Value, cookieProtection);
        return encodedCookie;
    }

    public static HttpCookie Decode(HttpCookie cookie) {
        return Decode(cookie, CookieProtection.All);
    }

    public static HttpCookie Decode(HttpCookie cookie, 
                  CookieProtection cookieProtection) {
        HttpCookie decodedCookie = CloneCookie(cookie);
        decodedCookie.Value = 
          MachineKeyCryptography.Decode(cookie.Value, cookieProtection);
        return decodedCookie;
    }

    public static HttpCookie CloneCookie(HttpCookie cookie) {
        HttpCookie clonedCookie = new HttpCookie(cookie.Name, cookie.Value);
        clonedCookie.Domain = cookie.Domain;
        clonedCookie.Expires = cookie.Expires;
        clonedCookie.HttpOnly = cookie.HttpOnly;
        clonedCookie.Path = cookie.Path;
        clonedCookie.Secure = cookie.Secure;

        return clonedCookie;
    }
}

Using the Code

Using HttpSecureCookie is easy; for a complete demo, please check the sample application. To encode a cookie:

HttpCookie cookie = new HttpCookie("UserName", "Terminator");
cookie.Expires = DateTime.Now.AddDays(1);
HttpCookie encodedCookie = HttpSecureCookie.Encode(cookie);
Response.Cookies.Add(encodedCookie);

To decode an encoded cookie:

HttpCookie cookie = Request.Cookies["UserName"];
lblDisplayBefore.Text = cookie.Value;
HttpCookie decodedCookie = HttpSecureCookie.Decode(cookie);

To use HttpSecureCookie on a web farm, you need to set the correct MachineKey configuration in Web.Config. For more information, check the "Web Farm Deployment Considerations" section on How To: Configure MachineKey in ASP.NET 2.0. To generate a machine key, please check How to create keys by using Visual C# .NET for use in Forms authentication.

Limitations

This library uses reflection, so it might break with the next version of .NET. Also, it doesn't work with .NET 1.1.

Reflection might have some performance implication; however, I used an assembly that is already loaded, "System.Web.dll", and I am only using reflection once across the life time of the application, to gain extra performance.

Conclusion

If you don't want a sophisticated cookie encryption service, if you don't want to mind the encryption key, and if you don't want to create your own encryption algorithm, then this library is for you!

Comments and suggestions are welcome. Please vote if you like this article (or if you didn't).

History

  • 1 April 2006 - First version.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)

About the Author

Adam Tibi
Team Leader
United Kingdom United Kingdom
Member
Software Consultant, Lives in Guildford/Surrey, UK.
 
www.AdamTibi.net

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralRe: Was working great - now throwing errorsmemberdiego mesa tabares29 Sep '11 - 11:58 
Hello I was able to solve the problem setting a machine key in my application web.config, in the system.web section, I generated the key using this tool:
 

http://aspnetresources.com/tools/machineKey

 
Hope this helps Smile | :)
GeneralI'm pretty sure I'm missing something, but...memberreinux1 Nov '10 - 21:26 
What's the difference between using this and using System.Web.Security.MachineKey.Encrypt() ?
GeneralRe: I'm pretty sure I'm missing something, but...memberfrankosaurus5 Dec '10 - 14:06 
It seems that class is only available in .NET Framework version 4. This article was targeting .NET Framework 2.0.
GeneralRe: I'm pretty sure I'm missing something, but...memberreinux5 Dec '10 - 14:46 
Ah right... stupid me x_x
GeneralThanks for the propsmemberericnewton769 Jul '10 - 7:12 
Thanks for the props in your article.
 
Big Grin | :-D
GeneralMedium TrustmemberSpiff Dog1 Mar '10 - 10:40 
Since this uses Reflection, I gather that this will not run in a default Medium Trust environment at a hosting provider. Any idea how to do this so it will work?
 
Perhaps you could implement one of the Crypto providers in the System.Security.Cryptography namespace?
-------------------------
Spiffdog Design
It's ok... he doesn't bite...

GeneralRe: Medium TrustmemberAdam Tibi2 Mar '10 - 0:12 
Hi
 
I never tried this in a medium trus enviroment.
 
You could always refer to your own encryption strategy
Make it simple, as simple as possible, but not simpler.

GeneralThanks for the insight Adam...I've actually implemented your code in my projectmemberZiad J.khan26 Nov '09 - 10:45 
Session, Cookie, Query String & Cache Variables Unified
 
Regards
Ziad
GeneralRe: Thanks for the insight Adam...I've actually implemented your code in my projectmemberAdam Tibi30 Nov '09 - 2:20 
Thank you Ziad Smile | :)
 
Make it simple, as simple as possible, but not simpler.

Generalerror : padding is invalid...memberjamel197416 Sep '08 - 4:39 
hi adam,
i've a login page with a checkbox if i want to remember password. If this checkbox is checked, i encode the password in the cookies .
I've a problem when i compile in debug with visual it's OK but if i launch direct my site (http://localhost/mysite) i've the following error message:Padding is invalid and cannot be removed
if i delete my cookies and i try again it's ok but if i launch again with visual (without delete the cookies) in debug i've the same error
 
source:mscorlib
 
Line 58:                  catch(Exception ex) {
Line 59:                        throw new InvalidCypherTextException("Unable to decode the text", ex.InnerException);
Line 60:                  }
Line 61:                  if (buf == null || buf.Length == 0) {
 
Source File: C:\MJL\MySite\Sources\MySite_ClassLibrary\Security\MachineKeyCryptography.cs      Line: 59
Stack trace
[CryptographicException: Padding is invalid and cannot be removed.]
   System.Security.Cryptography.RijndaelManagedTransform.DecryptData(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount, Byte[]& outputBuffer, Int32 outputOffset, PaddingMode paddingMode, Boolean fLast) +1490188
   System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount) +306
   System.Security.Cryptography.CryptoStream.FlushFinalBlock() +30
   System.Web.Configuration.MachineKeySection.EncryptOrDecryptData(Boolean fEncrypt, Byte[] buf, Byte[] modifier, Int32 start, Int32 length, Boolean useValidationSymAlgo) +154
   System.Web.Security.CookieProtectionHelper.Decode(CookieProtection cookieProtection, String data) +79
 
[InvalidCypherTextException: Unable to decode the text]
 
have you an idea?
thanks
GeneralRe: error : padding is invalid...memberAdam Tibi16 Sep '08 - 11:54 
Hi,
 
Recheck if you have set a machine key in your web.config which also should be the same across your web servers. Also, do you have any security software being active? Did you try different browserw?
 
Another question for you, why don't you use the membership provider which is introduced with ASP.NET 2. It is flexible and the save password feature is a "built-in".
 
Regards
 
Make it simple, as simple as possible, but not simpler.
Looking to hire .NET Software Consultant in UK?

GeneralRe: error : padding is invalid...memberjamel197416 Sep '08 - 21:03 
i use the membership provider but i must have add 2 textbox because i use the username to load informations in the session (in the code c#) otherwise (without my textbox but with textbox of asp:login), i don't have recover the login: asp: <asp:Login ID="UserLoginCtrl"...
c#: UserLoginCtrl.UserName is always empty.(I surely do something wrong). I'd like to use the component more simply but i can not...
Regarding my first problem i ve tried with firefox and i ve no problem...
GeneralRe: error : padding is invalid...memberjamel197416 Sep '08 - 22:21 
the 2 textboxes are in component it's just a breaking down into <template> but without this breaking down, i don't recover my data. in this case the gestion is not hidden and i must do manually (gestion of cookies). I hope that it's clear enough
thanks
GeneralInvalidCypherText.... no good.memberKurtPW29 Aug '08 - 13:31 
Adam:
 
I get a CS0246: The type or namespace name 'InvalidCypherTextException' could not be found (are you missing a using directive or an assembly reference?)
 
... error at: throw new InvalidCypherTextException("Unable to decode the text", ex.InnerException);
 
I cannot find this exception in any of the .Net docs. The closest I come up with is a InvalidCipherTextException() in BouncyCastle. Where in .Net is this exception defined? I'm not sure what namespace in use.
 
Thanks
 
Kurt
GeneralRe: InvalidCypherText.... no good.memberAdam Tibi31 Aug '08 - 11:47 
Hi Kurt,
 
I have no idea about this error, be sure that I am not missing any namespace as the code is compiling!
 
Note that this code uses reflection, so it might not work with ASP.NET 3.5 (please if anyone has tested it then please let me know).
 
Are you using the compiled dll?
 
Regards
Adam
 
Make it simple, as simple as possible, but not simpler.
Looking to hire .NET Software Consultant in UK?

GeneralThanks Adammemberlehuuduc6 Aug '08 - 17:37 
it's great Article. Thanks you
GeneralRe: Thanks AdammemberAdam Tibi6 Aug '08 - 23:22 
You are welcome Smile | :)
 
Make it simple, as simple as possible, but not simpler.
Looking to hire .NET Software Consultant in UK?

GeneralDownload link error [modified]memberMarie-Christine Bechara6 May '08 - 2:52 
I'm trying to download the source code but it's giving me that it's an invalid url.
Did the source project link change?
 
modified on Tuesday, May 6, 2008 9:03 AM

GeneralRe: Download link errormemberAdam Tibi8 May '08 - 23:05 
It is working for me, please try again
 
Cheers
Adam
 
Make it simple, as simple as possible, but not simpler.
AdamTibi.NET

GeneralPadding is invalid and cannot be removed.memberSurjit Singh23 Apr '08 - 0:00 
I am getting this message when i published the site locally and running it through IIS. Please tell how to remove this error ASAP.
 

Thanks a lot in advance
Surjit
GeneralRe: Padding is invalid and cannot be removed.memberAdam Tibi24 Apr '08 - 22:32 
Hi,
 
You haven't given enough information.
What line of code is giving the error? What is the stack trace? when? etc...
 
Regards
 
Make it simple, as simple as possible, but not simpler.
AdamTibi.NET

QuestionClarificationmemberstixoffire1 Apr '08 - 22:57 
You state in the Article:
"There is also another available method for encoding cookies, by using the FormsAuthenticationTicket and FormsAuthentication.Encrypt; for more information, check the section "Creating the Forms Authentication Cookie" on Explained: Forms Authentication in ASP.NET 2.0. However, I believe, the method mentioned in this article is more flexible."
 

In what ways do you think that your method is more flexible ?
Generalthank youmemberRob van der Veer25 Feb '08 - 4:38 
Thank you very much. This was what I was looking for..
GeneralRe: thank youmemberAdam Tibi25 Feb '08 - 22:04 
I am glad this helped!
 
Make it simple, as simple as possible, but not simpler.

QuestionHow do you delete the cookie?memberSimon Deshaies10 Dec '07 - 6:11 
I figure the subject speaks for it's self...
 
Any one can help?
QuestionInvalidCypherTextException can't find?memberdianlongliu27 Nov '07 - 14:18 
the name can't find
error 4 can't find the name “MachineKeyCryptography” C:\Documents and Settings\Administrator\My Documents\Visual Studio 2005\WebSites\cookie\encrypt.aspx.cs 133 35 C:\...\cookie\
using System should be?
 
gggame
AnswerRe: InvalidCypherTextException can't find?memberAdam Tibi27 Nov '07 - 23:45 
Hi
 
Sorry, could you please rephrase your question with additional explanation?
 
Cheers,
Adam Tibi
 
Make it simple, as simple as possible, but not simpler.

GeneralRe: InvalidCypherTextException can't find?memberdianlongliu28 Nov '07 - 3:30 
error:
 
行 100: catch (Exception ex)
行 101: {
行 102: throw new InvalidCypherTextException("Unable to decode the text", ex.InnerException);//there is the error
行 103: }
行 104: if (buf == null || buf.Length == 0)
 

错误 2 找不到类型或命名空间名称“InvalidCypherTextException”(是否缺少 using 指令或程序集引用?) C:\Documents and Settings\Administrator\My Documents\Visual Studio 2005\WebSites\cookie\encrypt.aspx.cs 106 23 C:\...\cookie\
the name space can't be found
and 错误 MachineKeyCryptography” can 't find

 
gg
GeneralRe: InvalidCypherTextException can't find?memberAdam Tibi28 Nov '07 - 23:03 
Hi,
 
Did you check the ex.InnerException to get the detailed error?
 
Regards,
Adam
 
Make it simple, as simple as possible, but not simpler.

GeneralRe: InvalidCypherTextException can't find?memberdianlongliu29 Nov '07 - 14:55 
when i enter the F5,
the problem is carry out.
 
there is lack of the "using system"
 

GeneralRe: InvalidCypherTextException can't find?memberdianlongliu29 Nov '07 - 15:00 
ASP.NET uses the System.Web.Security.CookieProtectionHelper internal class to decode and encode the content of a cookie before submitting it to the client. This class is based on the MachineKey.
 

what is mean?
GeneralRe: InvalidCypherTextException can't find?memberAdam Tibi29 Nov '07 - 23:39 
Hi,
 
This will tell you more about the machine key:
 
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/paght000007.asp[^]
 
To make things easier for you, try to use the compiled assembly (the .dll file) rather than referencing the source code.
 
Regards,
Adam
 

 
Make it simple, as simple as possible, but not simpler.

GeneralRe: InvalidCypherTextException can't find?memberdianlongliu30 Nov '07 - 3:10 
thinks much
i am chinese
luck to meet you
 
gggame
QuestionPadding exceptionmemberDaberElay9 Sep '07 - 22:07 
Hi Adam,
 
I'm getting this "unable to decode the text" error which internally reveals an "Padding is invalid and cannot be removed." exception.
 
from a quick lookout i made on this error, it appears that one should specify the padding mode when encoding/decoding text and recommanded modes are PaddingMode.ISO10126, PaddingMode.PKCS7, or PaddingMode.ANSIX923 ( and all assumes we use rijndael encryption)
 
the major disadvantage of using that internal class using reflection turns out to be the lack of documentation, intellisense etc'
 
could you help out on how to add this padding mode to your code?
 
thanks,
DaberElay

AnswerRe: Padding exceptionmemberAdam Tibi9 Sep '07 - 22:30 
Hi Daber,
 
Thank you for your comment. Currently I am very busy and I don't have any time (deadlines are hitting me) to investigate.
 
Regards,
Adam Tibi
 
Make it simple, as simple as possible, but not simpler.

AnswerRe: Padding exceptionmemberBoxcarwilli15 Sep '07 - 19:37 
We were getting this also, but the user agent was google bot. Google bot trying to login to our forms authed site.
AnswerRe: Padding exceptionmemberrsmith6661 Oct '07 - 15:33 
I had this error as well.   It happened when I tried to access the cookie from another application on the same webserver.   The fix I found was to explicitly set the <machineKey> setting in machine.Config as follows:
<machineKey
         validationKey="AutoGenerate"
         decryptionKey="AutoGenerate"
         validation="SHA1"
         decryption="Auto"
      />
The default setting is "AutoGenerate,IsolateApps", which causes the encryption mechanism to add a unique identifier for each application to the MachineKey before encrypting the data.   So essentially you are not using the same key in each application.
Of course this will have an impact on Forms Authentication as well. Better check out this article http://msdn2.microsoft.com/en-us/library/ms998288.aspx#paght000007_viewstate
 
RON
http://www.realtechnology.com
Generalthank umemberMember #396127727 Mar '07 - 1:03 
hiiiiiiii adam
this is vikash from india, i have been through ur code really impresseive, i just came iut of college and working as a S/W engineer, so can u tel me wic book should i read to enhance my knowldeg
my id is forever_vikash@yahoo.com
 
uu

GeneralRe: thank umemberAdam Tibi28 Mar '07 - 9:19 
Hi Vikash,
 
Thank you.
A good book for starting ASP.NET 2.0 is "Beginning ASP.NET 2.0 (Programmer to Programmer)" and if you have experience I would recommand "Professional ASP.NET 2.0 (Programmer to Programmer)" from Wrox.
 
best regards,
Adam Tibi
 
Make it simple, as simple as possible, but not simpler.

GeneralGreat articlememberazam's22 Feb '07 - 18:07 
Hi
this is one of the very very good article i have gone through...
 
Thanks for sharing your supperb knowledge
 

Thanks again....
 
azam's
GeneralRe: Great articlememberAdam Tibi22 Feb '07 - 22:39 
Thank you,
 
I am glad you liked it Smile | :)
 
Cheers,
Adam Tibi
 
Make it simple, as simple as possible, but not simpler.

GeneralWell done Adam!membernighthawk132 Jul '06 - 10:53 
It works like a charm Smile | :)
 
Nila
GeneralGREAT!memberKevin I13 Apr '06 - 18:04 
This is EXACTLY what I was just needing, how timely and extremely easy to use. Thanks a lot!

GeneralCool articlememberMoustafa Banbouk11 Apr '06 - 17:58 
Very cool article but we would be thankfull if you could just post the source code corresponding to .Net 1.1.
 
Moustafa Banbouk
GeneralRe: Cool articlememberAdam Tibi12 Apr '06 - 0:11 
Thank you Moustafa,
 
The good news is that there is an article on Code Project that deals with a similar situation with .NET 1.1 and it can be found here:
 
http://www.codeproject.com/aspnet/HttpCookieEncryption.asp[^]
 
Best regards,
Adam Tibi
 
Make it simple, as simple as possible, but not simpler.
GeneralGood onememberVasudevan Deepak Kumar4 Apr '06 - 4:40 
Good one
 
Vasudevan Deepak Kumar
Personal Web: http://www.lavanyadeepak.tk/
I Blog At:
http://www.dotnetjunkies.com/weblog/deepak/
http://deepakvasudevan.blogspot.com/
http://deepak.blogdrive.com/

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130516.1 | Last Updated 3 Apr 2006
Article Copyright 2006 by Adam Tibi
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid