The Plain Simple Password Page Not So Simple Anymore

The requirements for the management of passwords have become far more complex over the past few years in response to the increasing sophistication of security breaches. Nowadays, you need to provide a range of features such as hashing, routine change of passwords, preventiion of repeat passwords, email confirmation, auto-generation of random passwords and password quality checks. Dino Esposito explains.

Edited: 26th May 2016

Admittedly the topic of this article may not sound particularly enticing at first. It doesn’t refer to any new cool framework or a technology I’d want to advertise; it doesn’t even refer to any buzzwords in vogue these days. It could have been an extremely timely article if written some ten years ago to welcome the ASP.NET membership provider and user-management built-in ASP.NET server controls. But in the middle of 2016, with a new significant redesign of the ASP.NET platform approaching, what kind of value can an article about changing the login password provide? Hopefully, I’ll give a satisfactory answer to that question in the article

This article is about passwords and how you let users change them and what you should do to guarantee appropriate levels of privacy. It also focuses on a few dos and don’ts of password change pages.

Hash the Password

The privacy of data is a hot topic, and data leaks go immediately into the primetime news. Hence, regardless of the size of your application, if you’re using a login form then passwords must be hashed and ideally salted. Storing passwords as hash strings is doubly beneficial: it still allows you to check credentials effectively and guarantees that, in case the database is compromised, no realistic use can be made of any hashed passwords.

Password hashing can easily become a standard programming technique that is as easy to implement as storing password as plain text. You start by adding the following interface definition to your infrastructure class library:

Next, you create a default hasher class. The code below shows a hashing class that does nothing, but it’s the perfect mock to extend with the hashing algorithm you like most.

As far as a realistic body for the  HashInternal function, you might want to look at the Rfc2898DeriveBytes class in the .NET Framework.
(See http://msdn.microsoft.com/en-us/library/system.security.cryptography.rfc2898derivebytes.aspx).

 To make hashing more effective, you might want to use a random string known as the salt value. A salt value is commonly an alphanumeric string of any length-usually the longer the better. The iteration count parameter indicates the number of times you want the hashing algorithm to iterate to make the final hash harder and harder to crack.

Ideally, you create the salt as a random string for each and every user, and store it in the same database table as the credentials. The salt is recommended because its randomness makes brute-force attacks harder and, more importantly, it significantly invalidates the use of rainbow tables-a fancy name for precomputed tables of hashed passwords that hackers may sometimes use.  (See https://en.wikipedia.org/wiki/Rainbow_table.) To generate a strong salt value, consider using the RNGCryptoServiceProvider class. Note, however, that the Rfc2898DeriveBytes class also offer a constructor that automatically generates a salt string of the desired length.

In addition, or even as an alternative to salt values, you can use pepper values. A pepper value is equally a randomly-generated alphanumeric string that is common to all users and stored outside the database, typically in a configuration file. Unlike the salt value, the pepper is kept hidden and distinct from the salt so that knowing one doesn’t lead to know the other. The way you combine salt and pepper values is up to you: the simplest trick is just concatenating clear password, salt and pepper and then calculate the resulting hash.

Ensure a Minimal Length

As obvious as it may sound, the longer the password, the better it is. In addition, the more varied the set of characters it is based on the better. Using lowercase and uppercase letters, numbers and punctuation symbols simply increases the number of permutations a brute force attack must deal with. It is one thing to calculate all the possible permutations of, say, 8 letters in an alphabet of 26, but quite another to go through all permutations of size 12 in an alphabet of 60. The cost of a brute force attack grows exponentially with the range of characters, increasing your security level.

Both the ASP.NET Identity and classic ASP.NET Membership API provide support for the minimum length of a password and don’t accept any that is not long enough. If you’re using any of those membership and authentication frameworks, you’re encouraged to use the feature. If you’re creating your own simple framework, you should definitely avoid accepting any password shorter than a configured length.

In a web application based on logins, you probably have some register form where users enter their name and choose a password. This is the first place where you can apply the rule with an immediate JavaScript check on the password length. Then you can reinforce the same checks on the server side. Needless to say, in case of multitenant applications, the minimum length of the password must be configurable.

Let Users Know How Good is Their Password

If you opted for enforcing a minimum length, then you should also give immediate feedback to users about that as they’re typing the password in the register form. You should do the same also in any forms that you may have for users to change the password once registered. There are plenty of JavaScript libraries and jQuery plugins that help to meter the goodness of a password as it is being typed. Here’s an example:

The HTML input field is bound to a piece of JavaScript code that fires whenever the user types in.

The change-password button is disabled if the password is too short and re-enabled when the password reaches the minimum length. As it is typed, some JavaScript code calculates a score for the text in the input fields and changes the CSS class of the text that indicates how good it is. (See the figure.)

2421-da7b263f-8ace-48dc-b88c-ac2d678cb1c

The algorithm that you use to calculate the score of the password is completely up to you. Common tasks that you might want it to perform include counting distinct letters in the password, assigning a score that proportionally decreased for each repetition of the letter in the password. In addition, add a bonus if lowercase and uppercase are used and if numbers and punctuation symbols are used. The final score is then evaluated against known constants to determine a vote such as Poor, Good, Strong and so on. It’s purely a client-side feature with no impact on server code, but provides timely feedback and possibly encourages users to use more sophisticated passwords.

Showing Password Characters

The characters typed in a password input field are usually never shown because browsers blur characters in input fields with the type attribute set to password. That has been the standard behavior for over a decade and nobody ever complained much. A few years ago, though, some web sites started offering the option to type the password as clear text.

I wouldn’t definitely say it is a security hazard even though someone reading over your shoulder can easily catch a glimpse of your password. Switching between hidden and clear text characters is a user-friendly feature you might wish to consider.

In terms of code, all you need to do is to programmatically change the value of the type attribute of the input field. You can have a checkbox in the page and react to the user’s clicking on it by switching between the password and text value for the type attribute. Here’s some code.

When this JavaScript code is attached as an onclick event handler on a checkbox within the page, it verifies the checked status of the control and changes the value of the type attribute accordingly. The effect on the user interface is immediate: as soon as the type attribute is changed, the text is blurred or rendered as clear text. In general, you don’t want to save the checked status locally (cookie or local storage) as a user preference. The password field should default to type=password unless users turn clear text on for a few moments.

Suggesting New Random Passwords

In the view where users are entering a password to register with the site, or are just changing their current password, you might also want to offer a button that suggests appropriate passwords. A suggested password is typically unintelligible and randomly generated. Here’s a sample algorithm you can use.

The function picks a random character from the list of digits and lowercase and uppercase letters until it has constructed a string of the requested length. Needless to say, the algorithm can be made less predictive by providing an initial alphabet where digits, lowercase and uppercase letters are mixed up instead of being laid out one block after the next.

The resulting password is analogous to those that are automatically generated by most systems when you (or the admin) force a reset. In other words, it’s a password that will probably be changed soon for something that is easier to remember. So why having such a feature in a view? Some users will probably use one of the auto-generated passwords in order to get a password that is clearly a strong one.

I wouldn’t recommend suggesting passwords that are not automatically generated. Suggesting passwords from an existing list of strings and phrases might not be a good idea as several users might end up picking the same password. Anyway, this is a point on which only the direct knowledge of users and personal feelings really count.

Emailing Users After a Password Change

A password change is never a secondary event in a multi-user software system that requires authentication. For this reason, every time that users change their passwords you should email back the details of the operation. That represents an official communication from the system that a new password has been registered. At the same time, it represents a reminder for the user. Needless to say, communicating the new password via email is never a good idea.

Maintaining the History of Used Passwords

All of the features considered so far are common in most memberships systems whether created from the grounds up for a specific application, or adapted from one of the frameworks provided by Microsoft. Another feature that’s good to have is that of storing the list of passwords that a given user adopted in a given amount of time. Typically, users don’t much like having to change the password frequently (by the way, every six weeks is a good balance between security and bother) so they tend to re-enter the same password over and over or they just change it a bit, for example adding a progressive number to the end.

You should consider adding a string matching algorithm to your application so that whenever a new password is submitted it is checked against the stored list of previously used passwords. The check can be done only for equality or for closeness. For example, the password “foobar” is different from both “foobar1” and “fobbar”, yet the closeness between strings can’t be denied. Some web sites also force users to change the current password with one that is significantly different from any other password that was recently used.

The Levenshtein distance (see http://www.levenshtein.net/) is an algorithm you can use purposely that counts the number of edits required to turn one word into another one. If the calculated Levenshtein distance is below a small number (say 3) you can deny the password because it too similar to an old one.

Note that maintaining a history of previously used password is in contrast with hashing passwords. An effective hash, in fact, is not reversible so all that you can do is checking whether the exact password was used in the past. You have not much chances to check for password closeness. If that feature is required, then you should look for storing passwords through a reversible form of encryption.

Summary

Gone are the days when it was a simple matter to change a password by storing a new alphanumeric string in a database table column. These days, arranging an effective password-change view is much more complicated matter with more functionality to implement, including hashing, list of past passwords, email confirmation, auto-generation of random passwords and assessing the quality of password being typed. Hopefully, this article serves as a reference for the most important things to do to arrange the user experience. The real level of security is specific of the application and this-and only this-should drive the adoption of specific technologies and solutions.

  • 10409 views

  • Rate
    [Total: 19    Average: 3.8/5]
  • Anonymous

    Best practices
    Why MD5? ASP.NET Identity uses this
    /* =======================
    * HASHED PASSWORD FORMATS
    * =======================
    *
    * Version 2:
    * PBKDF2 with HMAC-SHA1, 128-bit salt, 256-bit subkey, 1000 iterations.
    * (See also: SDL crypto guidelines v5.1, Part III)
    * Format: { 0x00, salt, subkey }
    *
    * Version 3:
    * PBKDF2 with HMAC-SHA256, 128-bit salt, 256-bit subkey, 10000 iterations.
    * Format: { 0x01, prf (UInt32), iter count (UInt32), salt length (UInt32), salt, subkey }
    * (All UInt32s are stored big-endian.)
    */

  • Richard L

    Mixed Advice
    Some nice points made about the client side – giving users a strength indication is good, and the problem of people looking over your shoulder is a lot less significant these days, the main threat is remote hackers.

    The parts of your article focussing on the backend of the service however offer some dangerous advice. Lots of security problems occur because people start to roll their own security system, without being fully aware of all of its pitfalls.

    Some comments:

    1. You call out MD5 as a hashing algorithm. This has been considered dangerously weak for some time – GPU cracking and rainbow tables render even salted MD5 passwords easily crackable. Some people might see this listed and take it as a recommendation, even if it were not intended as such.

    2. Password history – this is simply not possible with hashed passwords, as the intention is to store them with no way to access the original password. At the time of password change you have access to the old and the new, so you can verify that they are indeed different, but the only way to check password history involves storing them with reversible encryption.

    3. Emailing passwords – you mention you should email details of the password when it is changed. It’s unclear whether you intend the password to be emailed, but if so then this should never be the case. I fully agree you should email a user to confirm that their password has been changed, but a password should never be revealed.

    Systems like ASP.NET Identity help to prevent people from making basic security mistakes by giving you a good implementation that has been heavily tested and scrutinised by many people. They’ve implemented things which many people would not consider, such as:
    * Allowing for upgrading of password hash algorithm when the current one gets considered weak
    * Generating secure tokens for password reset etc

  • Anonymous

    MD5 in a example?
    Its 2016 and MD5 is in the example code who ever wrote this has no idea about security!

    Also "if you’re using a login form then passwords must be hashed and ideally salted", salt is not optional its required just look how easy the passwords where cracked from linkedin….

    And cudos to the post above using PBKDF2 is the right way to go!

    Only improvement would be if it had some memory intensive hash function instead.

  • Edmond D. Townsend

    informative
    Thank you for sharing this information. Your posts are informative as usual. I did not even find the solution in <a href="https://en.wikipedia.org">wikipedia</a&gt;.

  • Edmond D. Townsend

    informative
    Thank you for sharing this information. Your posts are informative as usual. I did not even find the solution in [url="https://en.wikipedia.org"]wikipedia[/url%5D.

  • Edmond D. Townsend
  • Ian Yates

    Problems
    Sorry, but some of this advice is a bit dated / wrong.

    I like the part about emailing the user that the password was changed – it’s a nice "out-of-band" way to let the user know something happened. Just don’t include the password itself in the email!! 🙂

    But MD5… even with salts it’s not a good idea. And as another commenter mentioned, the out-of-the-box ASP.Net code for quite some time has used stronger methods.

    Password strength can be frustrating if enforced as my 20 char all letters password is arguably better than "123AB!!" in terms of search space, etc.

    Finally, the recent passwords check advice might apply in the enterprise (where I’d rather use IIS and Kerberos or a separate token service), but if your passwords are stored in a truly one-way fashion, there’s not really any ability to do the comparison. All you could reasonably do is compare for an exact password reuse. Granted you could exercise your server CPUs to look for numbers in the new password and try other numbers in their place when comparing to previous salted password hashes but that’s applying a bandaid to a problem that’s not worthy of treatment.

  • Andrew Clarke

    Dino’s Article
    Ed: Dino has updated the article to reflect the advice of Ian Yates,Troy Hunt and Richard. Many thanks for their valuable contributions.

    Editor
    Simple-Talk

  • despos

    Intended purpose
    Thanks everybody for the great feedback! All true, nothing to say on my end if not updating the article wearing sackcloth and ashes 🙂
    Basically, I changed a code snippet using MD5 with Rfc2898DeriveBytes and added a couple of sentences to better explain the intended point of password history and emailing password changes.
    In spite of the "password" theme being discussed, the article was intended to emphasize the UX aspect of changing a password rather than being a guide how to make passwords more secure. Yet, admittedly, this is not an excuse for presenting bad practices. Thanks again for the great feedback.

  • avonwyss

    Don’t replace salt by pepper
    If you only apply pepper and no salt as suggested ("or even as an alternative to salt") in the article, you’ll end up with same hashes for identical passwords, which is a big issue especially for larger user databases because you’ll be able to identify frequently used passwords and focus on them to crack them; these are likely password which are commonly used by users (there are lists of these around…).