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

How-to safely keep a password field during postbacks and why it shouldn't be done

By , 31 May 2007
 

Screenshot - keeppassword_screenshot.png

Disclaimer

The author does not accept responsibility for any effects, adverse or otherwise, that this code may have on you, your computer, your sanity, your dog, and anything else that you can think of. Use it at your own risk. (Deja Vu? I also love the Allegro disclaimer.)

Quick and dirty tour

So, you don't like to read all articles you see on the web, or you don't have time for it? Then, just download the source files, and open the solution as a web project on your Visual Studio 2005 IDE, and click Play.

Background

You only need to have a basic knowledge of ASP.NET and C# to use and benefit from the article.

Introduction

Stop where you are! Don't think about reading this article thinking about a magic solution for the world's problems. It is a very simple way of caring about more things than just the problem at hand. And also, minding about collateral effects of apparent feasible solutions.

Understanding the problem at hand

You have a page with a textbox on password mode that you need to persist the state during postbacks. .NET keeps erasing its content when you postback the page, and you want it no more! You just have to keep its data. Simple, right? Not really. I'll explain why it is so simple to explain and it is so tricky to solve.

The illusion of solving a problem

During my early years as a .NET developer, a few years ago, I stuck on this very problem, and by using my favorite friend consulting (Google), I ended up with a widely used solution (for newbies, of course).

It was something like this: you write the password field value back to itself on every page_load event. Wow! Let's see how it would look like:

protected void Page_Load(object sender, EventArgs e)
{
    //does not work, .net will erase the content this way
    //txtPassword.Text = txtPassword.Text;
    //so adding an attribute on the client side would solve it. (do NOT use this!)

    txtPassword.Attributes.Add("value", txtPassword.Text);
}

That will solve the problem of losing the password at a very high cost. Run the DoesNotSolveTheProblem.aspx page on the source solution. Type a user and password, click on the button, and see that the password is indeed persisted. Now, click on View Source on your browser. Look for the txtPassword HTML tag:

<input name="txtPassword" type="password" 
       maxlength="128" id="txtPassword" value="123" />  

See anything that shouldn't be there? You are exposing the password, in plain text!

Solving the problem

There is a way for solving this problem very easily, it is a little tricky though. First, you need to keep the password on the server side, so a way to do so is using a server-side variable...not! It would be erased at every page load, so we go for ViewState.

It would look like this:

protected string TypedPassword
{
    get 
    {
        if (ViewState["TypedPassword"] != null)
        {
            return Convert.ToString(ViewState["TypedPassword"]);
        }
        return null;
    }
    set 
    {
        ViewState["TypedPassword"] = value;
    }
}

We also need to keep a fake data on the field (like a bunch of '*'s) to inform the user that there is data present in that field. We also need a way of detecting that the user typed a password, and that it is not the fake password we kept in the password field. Remember that '*' is a valid character for passwords!

Here comes the trick.

Passwords on modern Windows systems (post Windows 98 versions) can have up to 128 characters, so we limit the HTML password field to 128 characters by using its MaxLength property. We set the fake password mask to 129 '*' characters.

On every page load, we test if the password field is not blank and if it is different from the fake mask to detect if any change occurred.

//detect if password was changed. if filled and not equal to mask, it is new 

if (txtPassword.Text.Trim().Length > 0 && txtPassword.Text != PasswordMask)
{
    TypedPassword = txtPassword.Text;
    txtPassword.Attributes.Add("value", PasswordMask);
}

Since the user can not type more than 128 characters, he can enter a password full of '*' characters and have a valid password. And, how can we set 129 characters on a MaxLength=128 field? Well, this validation occurs on the client side, so we are able to do whatever we want on server-side.

Now, the last part of the cryptic show. When the user clicks on the password field, we have to erase its content (it is 129 '*' chars, not the password itself, remember?) and let the user type the new password. To do so, we add a simple JavaScript code.

This way, we do not compromise the security since the password is not in plain text on the page source. However, it is encoded (base64) in the ViewState hidden field, which can be used without encoding. My little piece of advice: don't.

See KeepPassword.aspx for the complete source.

Solving the right problem

This monster of keeping the password was born because we created it by using a bad design for our systems. If you put a little more effort on the design of an application, you could avoid these kind of tricky problems and come up with clean and robust approaches.

BetterDesign.aspx page has a complete example of a different way of looking at the same problem.

Screenshot - betterapproach_screenshot.png

As you can see, there is no need to keep the password. When the user wants to change it, he just types it and that's all! Plus, asking for the current password and for the new password confirmation would improve security and avoid costly typos when setting new passwords.

You will see that this last solution does not use the typed password for storage purposes, but its hashcode (unique number generated from a string) instead. It is a common way of dealing with sensible data (like a password), and it is very simple too.

Catches

Besides the ViewState encoding situation I've mentioned before, there is another piece of information I must give you. Two strings can generate the same hashcode. Yes, I lied. But, it is such a remote possibility that we usually forget about it for most applications. Caring about it and storing plain text passwords instead would be a blatant mistake.

A few comments on hashcode algorithms are also necessary. The GetHashCode() method used in this solution is good for learning purposes, but should not be used in real systems. Instead, you should use the .NET provided (keyed or nonkeyed) hash algorithms like RIPEMD160Managed, SHA1CryptoServiceProvider, or SHA1512Managed (example below, on jimmy_b comments). You can find lots of articles about the subject on CodeProject, like this.

Also, I'm not using validators or any other .NET feature here for the sake of simplicity. But, it doesn't mean you shouldn't be using it. :)

Conclusion

That's all I have to offer you for now. Please feel free to ask for new functionality, report bugs, or to tell me how boring is this stuff.

References

Some great resources on the web:

History

  • 05-31-2007:
    • Added a few comments on hash algorithms, thanks to jimmy_b.
  • 05-25-2007:
    • Changed "encryption" to "encoding", which is the correct term for ViewState. Thanks to William who pointed it out!
  • 05-24-2007:
    • Original article.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Roberto Colnaghi
Software Developer
Brazil Brazil
Member
I'm a passionate developer and videogame player.
Been in touch with Objective-C, Javascript, C#, C, Guild Wars 2, Tera and many more.
 
Javascript is one of my favorite languages.

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   
QuestionDoesn't work for password box, but will for othersmemberMember 350908027 Nov '11 - 2:30 
Any idea why I can't do a write to the password box, even though I could do a write to other form boxes with the password value on the very same postback?
 
    protected string TypedPassword
    {
        get
        {
            if (ViewState["TypedPassword"] != null)
            {
                return Convert.ToString(ViewState["TypedPassword"]);
            }
            return null;
        }
        set
        {
            ViewState["TypedPassword"] = value;
        }
    }
    protected void Page_Load(object sender, EventArgs e)
    {
        if (txtPassword.Text.Trim().Length > 0 )
        {
          TypedPassword = txtPassword.Text;
          Response.Write("password: " + TypedPassword);
        }
        string pword = TypedPassword;
 
        Response.Write(" pword: " + pword);
        if (!String.IsNullOrEmpty(txtPassword.Text) && !String.IsNullOrEmpty(pword) )
        {
            txtPassword.Text = TypedPassword;
            txtLastName.Text = TypedPassword;
            Response.Write(" Attempted to write " + TypedPassword);
        }
 
    }
This code will write the password to my "Last Name" box but not to the password box. Ideas?
 
-Tom
 
P.S. I got it working using
txtPassword.Attributes.Add("value", TypedPassword);
in that last "if", but would be interesting to know why I can't set the Text property directly, server-side.
QuestionJava - maintain value in a fieldmemberjackclaude19 Jan '09 - 15:40 
Hello,
 
I'm working on a project (in Java) where I need to maintain a value entered into a field by the user. There is a do/while loop that asks the user if they want to go again. If they choose yes, I need for one of the values input by the user to remain in the field so they do not have to retype the information in that field. Any and all help is greatly appreciated.Confused | :confused: Confused | :confused: Confused | :confused:
AnswerRe: Java - maintain value in a fieldmemberRoberto 'Obi-Wan' Colnaghi Junior21 Jan '09 - 7:20 
Hi!
 
I'm a beginner in java and I'm not sure if I got your problem right.
 
If you were using HTML and javascript to persist the values of a field, you could use hidden fields or set the value attribute of that HTML tag on the server-side.
 
That's sort of what the .Net state bag (view state) is intend for.
 
I've found a similar mechanism for java:
http://java.sun.com/blueprints/qanda/client_tier/session_state.html
 
Hope that helps you. Smile | :)
QuestionSSL an alternative?memberMartin Capodici7 Jan '09 - 23:36 
Surely if using SSL the basic option i.e.:
 
txtPassword.Attributes.Add("value", txtPassword.Text);
 
would suffice as the password would be encrypted along with everything else due to the SSL?
 
Is that correct? Can anyone confirm?
AnswerRe: SSL an alternative?memberRoberto 'Obi-Wan' Colnaghi Junior8 Jan '09 - 1:56 
SSL would encrypt the data sending/receiving, and would not cache the page on the client computer.
If you try to save the page source, it wouldn't allow you to do so.
 
Though, for the security paranoia sake, I wouldn't rely on this since the user may move away from the computer and his password would be easily available on the page source.
 
These are facts I've experienced back in 2006 when testing this behavior on few browsers.
Let me know if you're experiencing something different.
GeneralRe: SSL an alternative?memberMartin Capodici8 Jan '09 - 4:27 
Thanks Roberto
 
The truth is I don't feel 100% happy myself relying on the SSL. There is something niggling me about it but I can't say what - it just feels as thought there might be a security loophole there somewhere.
 
So I decided to go for the solution you have propsed and it works a treat. Thanks for posting it.
 
My situation requires a password and confirm password, but it wasn't too hard to adapt.
 
I also made the password mask more resiliant to length changes by creating a property:
 
protected string PasswordMask
{
get
{
return new string('p', tbPassword.MaxLength + 1);
}
}
 
I use 'p' instead of '*' as I was having trouble with a regular expression validator when trying to include an exception for *********************.
 
Thanks for replying so many months after the original article! Wink | ;)
GeneralRe: SSL an alternative?memberRoberto 'Obi-Wan' Colnaghi Junior8 Jan '09 - 4:51 
No problem! Smile | :)
 
It seems that this is a recurring problem that we're bound to forever.
 
Thanks for sharing your comments and thoughts!
Generalsmall addonmembertdp_Codeproject23 Nov '07 - 3:50 
If you want to keep the length of the password in the textbox do this
 
if (txtPassword.Text.Trim().Length > 0 && txtPassword.Text != PasswordMask)
{
TypedPassword = txtPassword.Text;
txtPassword.Attributes.Add("value", PasswordMask.SubString(0,Password.Text.Length));
}
 

GeneralRe: small addonmemberRoberto 'Obi-Wan' Colnaghi Junior17 Dec '07 - 11:11 
Hi!
 
Actually changing the logic for a length check instead of a mask have some advantages and some drawbacks.
 
It would solve a problem with the newer versions of FireFox and Opera, whose constraint engines check for maxlength compliance even from script injected values.
 
But if the user changes the password to another one with the same length, it would be a problem that would require some handling.
 
Thanks for your comment!
GeneralWarning about ViewStatememberMichaelvdB9 Jun '07 - 22:43 
Be careful when using ViewState, the default setting is that it is not encrypted it is just a base64-encoded string. So if someone wanted to the could pull a password out of it.
 
Michael van der Bokke
GeneralRe: Warning about ViewStatememberRoberto 'Obi-Wan' Colnaghi Junior10 Jun '07 - 11:15 
Yes, indeed. That's why I've came up with this article on solving the right problem. Big Grin | :-D
Maybe I've mentioned it on the article, you could play with it on every conceivable place, but the point is in not keeping it at all.
 
Thanks for your comments and interest in posting though! Smile | :)
GeneralRe: Warning about ViewStatememberAspera21 Jan '10 - 3:37 
Adding ViewStateEncryptionMode="Always" in Page directive will encrypt ViewState for the page
GeneralString.GetHashCode() should not be used for security!memberjimmy_b31 May '07 - 3:08 
There is still a big mistake in your code, you use String.GetHashCode() which is v.bad given the purpose. The String.GetHashCode() is intended to be fast, not difficult to reverse, it is only a 32 bit integer after all.
 
You are correct to use hashing though, you just need to use a cryptographic hash function. Using the following code snip would do the same but in a secure way, I have used the SHA512 hash algorithm (only because it is biggest, 512 bits Cool | :cool: ), there are others you can use.
 

using System.Security.Cryptography;
// Convert the password to a byte array
byte[] inputBytes = Encoding.Unicode.GetBytes(newPassword);
 
// create a hash algorithm object
SHA512 sha512 = new SHA512Managed();

// Call the ComputeHash method
sha512.ComputeHash(inputBytes);
 
// Retrieve the hash
StoredPasswordHashCode = Convert.ToBase64String(sha512.Hash);

 
The resulting SHA512 hash of the string "somepassword" is KlkJH7mmHED+FRq0FAw4jFRW047NRBhvcLn5Xpnh2KiwqnEOLh+4J+0F/Rx94Wcs/cBUrHigLGiVTWSrGtwdMQ==
 
where else String.GetHashCode() is -1076713334
 
The rest of your article is great as I too followed the same path when solving the issue. Smile | :)
GeneralRe: String.GetHashCode() should not be used for security!memberRoberto 'Obi-Wan' Colnaghi Junior31 May '07 - 16:43 
I didn't used any hash algorithm to keep the article as simple as possible *but* I also missed to mention that GetHashCode() should not be used on production environments. My bad! D'Oh! | :doh:
 
I'll be adding a few comments to the article soon to fix that.
 
Thanks for your very relevant comments! I'm glad you like the article! Wink | ;)
GeneralNice article - my bank makes this mistake!membertoticow25 May '07 - 4:12 
www.fnb.co.za - got to love them posting back your password in plain text if you get your username wrong! Ok, they are using SSL - but still, I cant see why they need to return the password.
GeneralRe: Nice article - my bank makes this mistake!memberRoberto 'Obi-Wan' Colnaghi Junior25 May '07 - 7:04 
Well... they don't need to. And they really shouldn't rely on SSL as the only answer for security.
What if the user inadvertently saves the page on the disk? What about cache? There's so many things that can compromise a system.
 
Bad design is bad design, with or without SSL. Poke tongue | ;-P
Thanks for your post!
GeneralRe: Nice article - my bank makes this mistake!memberafterburn25 May '07 - 9:23 
default response for every browser in SSL is to never write the files to disk. So unless you have a keylogger/spyware its not likely that its a risk of any great nature. other than prying eyes.
 
In fact why even care to test the password in this article. If it doesn't match the database, leave it blank like the default response for the textBox in TextMode = "Password".
 

GeneralRe: Nice article - my bank makes this mistake!memberRoberto 'Obi-Wan' Colnaghi Junior25 May '07 - 9:40 
Good point! Browsers won't save encrypted files to disk (though users sometimes do). But any discussion over security issues is far beyond this article purpose.
 
Yes, left it (password field) blank would be the technical preferred solution, like the BetterDesign.aspx page proposes.
 
Though there are systems that have the password persisting as a "requirement". I've seen it before dozen times and I don't think it will stop appearing around unless the design is changed.

General[Message Deleted]memberDarkjo24 May '07 - 21:08 

GeneralRe: Nice articlememberRoberto 'Obi-Wan' Colnaghi Junior25 May '07 - 6:56 
I'm glad you like it! Thanks! Wink | ;)
GeneralRe: Nice articlememberBen Daniel25 May '07 - 15:51 
I agree, short + simple. Keep up the good work.
 
Thanks,
Ben Smile | :)

GeneralNewbie - ahh, now I get itmemberBen Daniel24 May '07 - 16:11 
Cool. I had come across this behavior building a wizard page to register a user and ended up storing the password value in a session variable between postbacks. It's good to now understand why it doesn't persist it automatically and also see a way to make it appear like it's still filled in after postbacks without compromising security. Too bad they couldn't build a behavior similar to this straight into the textbox, eh.
 
I do have a question though, being new to asp.net I'm not quite sure when I should be storing things in viewstate vs session vs cache(?). But I was wondering if session would be a better store for the password given viewstate could be decoded? Being a noob I'd be interested in hearing any pro/con for either store.
 
Thanks,
Ben Smile | :)

GeneralRe: Newbie - ahh, now I get it [modified]memberRoberto 'Obi-Wan' Colnaghi Junior24 May '07 - 16:24 
Hi Ben,
 
An article wouldn't be enough to explain all this options, so I'll try my best. Big Grin | :-D
I think that a very fast answer would be something like this:
 
ViewState: all that needs to be persisted at the page context and is not needed the navigating to another page.
 
Session: all that is important for a single user and should be shared among all pages. Keep only a small number of small memmory usage objects. Don't go crazy putting datasets into the session because it will degrade performance and the server may lack of resources quickly when multiple users navigate through the system.
 
Application: all data that is shared among all users on an application. keep in mind the same restrictions as the session ones.
 
Cache: like a application, but with the fair advantage of expiration. You could set a piece of data and make it available for 2 min. After that you could automatiacly refresh it or just let it go away, freeing server resources.
 
Cookies: non-mission critical data that should persist across user sessions would be a good example for cookies.
 

 

-- modified at 9:55 Wednesday 30th May, 2007
GeneralRe: Newbie - ahh, now I get itmemberBen Daniel25 May '07 - 15:53 
Thanks, that was helpful.
 
Thanks,
Ben Smile | :)

GeneralRe: Newbie - ahh, now I get itmembermorphix29 May '07 - 12:27 
Actually Cache is like more like Application because the data is available to all users.
Anyway: Nice compact explanation of the different collections...
oooh by the way dont forget Page.Items:
only available for the current user, and only during the lifespan of the request...
This is really neat when you have multiple controls (user/server controls/webparts) that needs to access the same resource. ex: you only need to get a user object from a database once and you can use that object throughout your components.
GeneralRe: Newbie - ahh, now I get itmemberRoberto 'Obi-Wan' Colnaghi Junior30 May '07 - 3:54 
Oops! Sorry about that! D'Oh! | :doh: You catch it right. Cache is not tied to user sessions, it is like Application indeed.
 
Thanks!
GeneralRe: Newbie - ahh, now I get itmemberRoberto 'Obi-Wan' Colnaghi Junior30 May '07 - 4:00 
Forget to mention, thanks to bring Page.Items to the discussion! It is new to .net 2.0 as myself. Poke tongue | ;-P

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

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 31 May 2007
Article Copyright 2007 by Roberto Colnaghi
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid