Don’t ask me why you find yourself working in ASP.NET. I know there are more effective ways to build a site.
Don’t ask me why you’re maintaining an app written in the style of 2005. I know, but it happens
Don’t ask me why your ASP.NET app is using the MembershipProvider system. I know it’s a poor match for the needs of almost all apps and encourages security holes by design.
Don’t ask me what reason could possibly explain needing to change some passwords. Why isn’t this functionality built in to the app? I know, I know…
But you’re there. Your app is using the MembershipProvider system, which saves the passwords in the database in some kind of encrypted form. And now you have to change some passwords quickly, probably for multiple embarrassing reasons, yet the app doesn’t offer you the functionality to do so, and you don’t have the time to add that functionality and re-build and re-deploy the app.
If only it were possible to go into SSMS and change the passwords using only T-SQL.
Now you can.
How does a one-time password work?
If you read a previous article I wrote
, you’ll remember that I mentioned the use of multi-factor authentication. One common tool for implementing the something you have
factor is the one-time password. When you first hear the phrase one-time password
, you might think of a password that only works once. You can imagine keeping a list of these passwords and marking them off as you use one of them. That is actually one of of implementing the one-time password. Unfortunately, it is cumbersome. There is a better way.
Passwords are everywhere. We have too many of them. We know we shouldn’t re-use them, but we already have too many and we can’t remember another one. So we use one in multiple places and we get in trouble when one website is compromised. They cost us time and money when we have to reset them. Despite the pain, cost and weak security they bring us, we’re only getting more of them.
Their ubiquity is a function of their nature. Passwords are usually input using the same interface used for other functions (e.g., your keyboard.) Authentication by other factors require specific inputs to a system. “Wait,” you say. “What are other ‘factors’?” Excellent question. (more…)
If you’ve read Andrew’s posts on web security (and if you haven’t go read them now – they’re great) you’ll love this Ars Technica article by Dan Goodin, “Why passwords have never been weaker – and crackers have never been stronger” about the state of the art in password cracking, the psychology behind how users select passwords, and the mistakes that services make while storing passwords.
The articles references 1Password which is a great password manager for the Mac, Windows, iOS, and Android. It can generate secure passwords up to 50 characters in length and store them securely as well. It also allows you to easily see where you’re reusing passwords (I’m sure you’re not doing this) and sort your various login passwords by strength so you can see which ones you should update first.
In the wake of Matt Honan getting hacked take the time to make sure you’ve got some strong passwords!
(This is part 2 of a series on web security; see part 1.)
In my last post we saw that what your users don’t know can hurt them. In other words, how securely you handle your users’ private data behind the scenes can have profound implications both for your business and your users’ well being. To put it bluntly, it’s bad for your business to be publicly shamed over your handling of sensitive data, and it’s bad for your users to have their bank accounts pilfered — those being some of the worse case scenarios.
So today I’d like to resume our discussion of secure password storage. Let’s put our black hat back on, and see what we can break.
I’ll start with the easiest case. Sometimes developers assume that as long as their database is safely hidden behind a firewall and an ordinary web server, then it’s OK to store everything in plaintext. But this is not true. There are many ways data can leak from your production database, including:
- performing a SQL injection attack through your website
- digging through a backup or archive of your database — therefore as long as you don’t create backups, you’re safe*
- gaining access to the server file system, e.g. through telnet/SSH/RDP
* That was a joke.
It is a good rule of thumb that you should design your database with the assumption that malicious users may gain unrestricted access to it at some point. But even if that happens, you should be prepared to breathe a sigh of (slightly nervous) relief, knowing that they still won’t be able to use the information maliciously. That doesn’t mean you have to encrypt everything, but you should definitely encrypt anything sensitive, such as credit card numbers, passwords, and so on.
A natural first step is to perform a one-way encryption, or “hash” on passwords so they are no longer readable in the database. Here’s an example:
Do you see any problems with the above? OK, ignore the fact that the hashes are very small numbers. This is just pseudo-data for illustration.
Observant readers will notice that one of the hashes occurs more than once (JSmith and MRandolph). Did you catch that? This is one of the problems with storing password hashes in your database – it’s still very easy to see which users chose the same password. Remember, users won’t protect themselves, and a surprising number of users may have a password of “12345” or “password” (or “Password1”, just to anticipate and refute a well-intentioned, but ultimately insufficient attempt to solve this problem via a more strict password selection process).
Beware the Dictionary
An even deeper problem here is that a hashing scheme like the above is susceptible to a dictionary attack using a large, pre-calculated collection of hashes of common passwords. All it takes is one successful match to positively identify the hashing scheme used, and then start doing damage.
Don’t Follow This Recipe
So we have to make sure the hashes we store are unique. We don’t want an attacker to be able to recognize any of them. To do this, people use what’s called a “salt” to make the output more random.
A well-salted hash.
(photo by Tavallai, CC BY-ND 2.0)
The salt is just a random number, and you can combine it with the hash process to get a more random looking output. Here’s how one person did that, showing the same data from the table above, but with salt included. Pay special attention to the JSmith and MRandolph records, as before:
Whoa, wait a minute. Do you see a new problem here? It is true that each “PasswordHash” attribute is now unique since a random number has been prefixed. And the developers may run a few simple SQL queries and verify that no two PasswordHash attributes are the same, and pat themselves on the back. But that is merely a dangerous illusion, and this is a very wrong implementation.
Since you have your black hat on, it will be obvious to you that a hacker can just bit mask out the part of the hash they are interested in, sort of like performing a Python slice, and exclude the “salt” that way. So this erroneous approach has no meaningful improvement over the “simple hash only” example above.
Note: I actually found this erroneous approach used in an online source code recipe, several years ago. Of course it seems absurd to us under this analysis, but somebody thought it was correct enough to post on a source code recipe sharing website, so I think the point was worth belaboring here a bit.
A Better Seasoned Recipe
Here is a more accurate description of how to use salt to protect your password hashes:
- In context of creating a new user record or updating a password, receive the plaintext password from the user.
- Generate a strongly random number to use as the unique salt value for this user record.
- Compute: a hash of (the salt concatenated with a hash of (the salt concatenated with the password)). Here’s a link explaining why this expression needs to be this complex, instead of simply a hash of the concatenation.
- Store both the result of that final hash calculation, and also the unmodified salt value in your database in the user record. I personally like to concatenate the final hash and salt and store them in the same record attribute, just to be obscure. But that doesn’t really matter. Note that it’s OK to store the salt in plaintext; in fact, that’s required.
- After we are finished with this process, deliberately forget the plaintext password. Depending on the overall architecture, maybe it is was provided by the user, or maybe it was system-generated and must now be emailed to the user. Either way, it must not be stored as plaintext.
- Later on, when the user enters their user name and password to log in, look up the record by user name, then repeat the calculation in step 3 using the salt value retrieved from the record. The resulting hash (using the password being entered) can be checked against the stored hash from the database to determine if the user entered the right password.
If you do it right, your database’s hashes should now look totally scrambled and inscrutable to an unauthorized reader. (Reminder to self: next time must avoid blogging while hungry, especially about recipes for salted hashes and ordering crackable things as scrambled.)
Choosing a Hash Function
This blog post is not a complete treatment of the subject of server side salting and password hashing. Another important decision is what hashing function to use. A hash function in this context is typically chosen to be both secure and slow. But it’s also a moving target, as cryptographic standards must continually respond to rapidly advancing cracking capabilities. Somehow the very weak MD5 ended up as an entrenched hash function in very widespread use in the 90’s and aughts. (Boy, was that a short sighted mistake.) Many people are still using SHA-1, which wasn’t considered horrible just a few years ago, but really needs to be deprecated in favor of stronger options. I recommend you spend some time reading the links in this discussion to get a sense of what’s out there. I’m deliberately not giving a specific recommendation here, in order to reinforce that there is actually more than one possible answer, and also that the “correct answers” periodically change.
Don’t Try This At Home
My final advice may sound like it contradicts everything I’ve said thus far. But that’s OK. 🙂
If at all possible, you should not come up with your own implementation of these approaches. Ideally, you should rely on your framework libraries to provide high level, complete authentication and authorization wrappers. Or if not, at least you should find and integrate a secure implementation from a trusted source. I already showed you how some guy on the internet thought they were salting their passwords, but got it totally wrong; so definitely don’t trust random stuff you google up.
Be very cautious if you’re not a cryptographic expert. Certainly, you can and should learn the basics of information security, and use your knowledge to audit and critique your own systems. But any implementations you deploy to production should be from trusted frameworks, or at least closely follow standard industry best practices. Don’t assemble something off the top of your head, or it will almost certainly be cryptographically weak and defective.
Thanks for reading! You can take the black hat off now. Hopefully this was informative for somebody; if you have any questions or want to share your own advice for readers, I’d love to read your comments below.