Continue Discussion 131 replies
September 2007

Robert

Andrew R,

Absolutely. However, the fact that they emailed passwords in plaintext as a matter of course didn’t inspire confidence that they were otherwise smart about password management.

September 2007

TheDave

Not storing passwords in plaintext is good in theory, but in practice it’s not always possible.

For example, a mail server must be able to access plaintext passwords because the APOP and CRAM-MD5 authentication methods require the server and client to compute hashes based on a salt provided in the session.

TLS solves this, but TLS isn’t always possible.

I’m sure there are more authentication schemes in the world that use the same principles. Until they go away, plaintext passwords won’t either because plaintext is better then the alternative.

September 2007

Michael

Thanks for posting on this topic! Funny coincidence, I was thinking on writing about the same issue and explaining to our customers how we chose to approach the problem. Well I did that anyway and used your blog posting as a good introduction. The technical details of our approach and philosophy are posted here in my blog entry. I would appreciate anyone’s feedback on our choices.

I think websites need to put more thought into this and MORE importantly MORE transparency. Let me know how you do what you do with my password and personal information. We as consumers should demand this.

One challenge we face is allowing password reset. During this operation we email the user a new randomly generated password for use. Of course this new password is open to snoopers until the user changes it. Sure, you could send the user a link to click on to put in a new password (and make it a temp link) as Robert suggested. However, this is open to snoopers as well. Effectively, if I can snoop the password I can snoop the link and choose your new password. Both solutions have the same problem. Any good suggestions on how to deal with password reset in a more secure fashion would be appreciated. Of course, we could resort to the user contacting us – but we want to stick with a self-service based solution. Any good suggestions to this problem would be much appreciated?

September 2007

Michael

Ooops. Didn’t realize I didn’t post my blog entry on this. http://blog.tribalpizza.com/2007/09/how-do-we-secur.html

September 2007

codinghorror

Also of interest is OAuth, which addresses the problem of websites (eg, Facebook) asking for you credentials to other sites (eg, Gmail).

http://www.hueniverse.com/hueniverse/2007/09/explaining-oaut.html

Many luxury cars today come with a valet key. It is a special key you give the parking attendant and unlike your regular key, will not allow the car to drive more than a mile or two. Some valet keys will not open the trunk, while others will block access to your onboard cell phone address book. Regardless of what restrictions the valet key imposes, the idea is very clever. You give someone limited access to your car with a special key, while using another key to unlock everything else.

Everyday new websites offer services which tie together functionality from other sites. A photo lab printing your Flickr photos, a social network using your Google address book to look for friends, and APIs to build your own desktop application version of a popular site. These are all great services – what is not so great about some of the implementations available today is their request for your username and password on the other site. Using Twitter as an example, the site simple yet powerful API created a rich community of applications built on top of its platform. But in order for those applications to update your status on Twitter, they must ask for your password. When do so, not only you expose your password to someone else (yes, that same password you also use for online banking), you also give them full access to do as they wish. They can do anything they wanted – even change your password and lock you out.

September 2007

Ryan_Smith

I think the issue of password storage and security is also relatively difficult based on the fact that people want webmasters to be able to get their password for them.

I have a site where I stored all of the password encrypted (probably not correctly, but better than nothing). I kept getting calls from the clients that they had forgotten their password and wanted me to tell it to them.

I told them they would need to use the site’s forgot password functionality because the passwords were encrypted in the database. This always caused problems because they didn’t feel that I needed to go to such lengths to secure the password.

Eventually I won the argument of not storing the users password in plain text by simply refusing to store it in plain text. To this day they still ask me for that change.

September 2007

Richard_H

“…probably because they can’t remember the two dozen unique usernames and passwords they’re forced to have”.

I had two dozen unique account ten years ago. I don’t keep count any more, but the number of accounts I have now is in 3 digits. I don’t even bother writing down passwords, I just click “forgot password” whenever I need to log in again.

September 2007

Guido

A bad example i recently encountered was on Blogger, it requires you to login with you’re gmail account. Now, you and I may know Google has acquired Blogger so it is “probably ok”. But how do I explain to my (grand)mother/father or any other not-so-techsavvy person about what fishing is and the dangers thereof when even mighty Google says it is ok every now and then.

September 2007

Richard_H

"Add a long, unique random salt to each password you store"

I still don't quite get this - if the salt is random, how do we reliably generate the same salt value (for the same user) next time they log in?

You don’t. That would defeat the purpose. You generate a random salt each time the user logs in.

September 2007

Richard_H

Jon H.:

“Whatever you choose to do, you have to send something when you POST your form to the server. If you are using a SALT + HASH, you would send your password in the clear in the form post.”

No. The server sends the salt to the client. The client appends it to the password and sends the hash OF THE WHOLE THING to the server. The server performs the same operation. If the two hashes match, the user typed in the right password (or a probability 1/2^256 accidental match).

September 2007

Somejan

Richard H:

But such a scheme requires the server to ‘know’ the correct password, so it will need to be stored in some reversible way, which is bad. Also, the hashing will probably have to be done in javascript, so it could very well be that just using ssl is as fast and safer.

September 2007

Richard_H

Jon, I never suggested the salt was secret. On the contrary, it must be public or the user can’t log in. What I said was you do NOT generate the same salt value each time the user logs in. If you did that, someone could record your login packets and play them back later to log themselves on as you. You do this:

The client asks to log in.
The server generates a long random salt and sends it to the client.
The user types in his password on the client.
The client calculates the hash of password + salt and sends the hash to the server.
The server calculates the hash of the password + salt.
If the two match, the user typed in the right password. If not, sorry.

You do not store the hash of the password + salt, that is pointless because it’ll change each time.

September 2007

John

“It’s unfortunate that sometimes storing passwords as plain text is a contractual requirement from the client because they don’t want to be forced to create a new one when they forget their original password. Sad world we live in.”

Well, I’m sorry but it would never be part of any contractual requirement to store passwords as plain text. This is in violation of the Data Protection Act. If you want to store your passwords so you can get them back then use a reversable encryption which uses a key, such as BlowFish.

Never ever try to say that storing passwords in plain text files is a requirement. If the client tells you this, explain why it’s not possible. Even if the client can read the passwords, this may be in violation of DPA also.

September 2007

Somejan

disclaimer: I’m not a cryptographer, but I think I understand some of the basics of it.

With a rainbowtable, you basically precompute all possible hashes for a specific hash function and a specific range of paswords (character set and maximum length). It can work with any hash/one way function. Once you have this table, you can easily look up any hash value and read out the accompanying plaintext. The smart part of rainbowtables is in storing the tables in a very smart way that requires only gigabytes instead of terra/exabytes. Generating these tables is more-or-less equivalent to doing a brute force search of the range of passwords. The size of the table is, I believe, more-or-less proportional to the ‘password space’, the number of possible passwords there are within your charset and max length, and it also depends on the ‘accuracy’ of the table. (Read Jeffs previous post about them, it says each table can reverse xx percent of hashes of passwords within the range. Rainbowtables use probablistic methods.) (Although some math on the numbers on the rainbowcrack site show the relation password space - table size isn’t really proportional, so I’m probably saying some things about stuff I don’t actually know enough about.)
Rainbow tables work equally well against any kind of hash function, be it SHA or rot13 (though with rot13 there are other, easier ways to ‘crack’ it). The only factor is if the tables for a specific hash function already exist, or still have to be generated. (Assuming nobody has gone through the trouble of building a rot13 rainbowtable, rot13 is actually /more/ secure against rainbow crackers than md5 or SHA.)

Since md5, sha, windows hashing scheme and the like are well known hash functions, the tables for those can be found for free on the net.
Using a salt with your hashing function, you basically create your own private hashing function, for which new tables will need to be generated.
Generating rainbowtables is fairly expensive, but as the worlds largest supercomputers are botnets, I wouldn’t assume determined crackers won’t do this if the information in the stolen databases is valuable enough, though the bar is quite high. (And, as far as I understand rainbowtables, its very well possible to parrallelize rainbowtable attacks.)

Users passwords are often not very complex, a dictionary attack will find a large percentage of passwords. Salts can be made as complex as you want, by just using a longer string of randomly generated characters. When using a global salt of sufficient complexity, an attacker will have to get to that salt as well, because it won’t be feasible to do a brute force/rainbowtable attack on the database without it. If the attacker has access to the salt, he can then generate a new rainbowtable for the compromised database with the hash function + salt, and once he has done that, he can compromise basically all passwords in the database. (But building the table is at least as expensive as doing a brute force search against the database.)

Using a different salt for each password (which then has to be stored alongside the password) basically makes it harder to generate the rainbowtable, because the attacker now has to combine each attempted password with each of the hash values found in the database. I’m not quite sure if it will be as expensive as doing an individual brute force search against every entry in the database separately. Also, if you only use a global salt, the attacker can start generating the rainbowtable once he has that salt, but before he has the database, and then use it on any user account.

So, AFAIK, the most secure way is to use both a global salt and per-user salts, and keep your global salt stored separately from the database, so an attacker won’t easily get to both of them. Though having just one kind of salt already keeps you safe from an atacker who can’t generate a new rainbowtable.

Of couse, once an attacker has both the database and the salts, the most important thing standing between him and your password is your password’s complexity, so use strong passwords!

September 2007

John

Another thing to add to my previous comment. When developing for the web, NEVER and that is a definate repeat of the word ‘never’ put ANY encryption/decryption/hashing/security algorithm in a piece of javascript code on your html page. That is not what javascript was intended for and it’s not even 1% secure.

All scripts involving security and passwords should execute server-side where the user has no way of seeing or tampering with them.

Giving someone your security algorithms is the same as giving them the password or even passing them a plain text file.

September 2007

CynicalT

@Gregory Magarshak: No!

First: “just uppercase it” as a password input policy unnecessarily weakens user passwords. If someone doesn’t want to remember the case in their password, they won’t put it in.

Second: you should never return a message that says EITHER “account doesn’t exist” OR “wrong password”. All this does is allow people to find out if a particular user name is valid in the system! Bad! It should simply tell you “Bad username/password combination” or something to that effect.

Third: not allowing two logins within five seconds would annoy the crap out of me. I would stop using any website that had this function. I botch a password here and there, in which case I don’t want to have to wait even one second to try again. Now I can appreciate what you’re trying to do. But it’s just as effective to lock out a user (or maybe better, an IP address) for attempting 1,000 logins in some time period (say, a day). No cracking effort should be likely to succeed in 1,000 attempts unless your passwords are ridiculously short.

September 2007

Richard_H

Somejan, you are correct. In our case the passwords are assigned, users do not get to pick them. If you wanted to allow that, you would have to send a salt just for the password and store that, I guess that is what Jon was proposing. In that case I would suggest creating 2 salts, a stored one for the password as Jon suggests, and a temporary public one to prevent replay attacks.

September 2007

lothar1

So, the user’s password, instead of being stored as the hash of “myspace1”, ends up being stored as the hash of 128 characters of random unicode string + “myspace1”.

Instead of 128 random unicode-characters you should go with 256 random bytes. Otherwise some implementations will lead to every other byte being zero (if the implementer just writes a random string of ASCII/Latin1-characters).

Use a cryptographically secure hash.

Why only one and not more. All certificates you can “buy” for the usage in SSL-servers, … use MD5 and SHA1. Using SHA256 instead of SHA1 should please even the most paranoic and performing a rainbow table attack on a system that is secured that way should be quite difficult because there might be passwords leading to the same MD5 or SHAx hash, but both at the same time it’s very unlikely.

More interesting (and not answered here) is how to secure passwords that are used for authentication as client within a server (e.g. for data-transfer-protocols like OFTP). A hash doesn’t work because the password is needed to be transfered (or used for the response of a challenge being sent by the server). And securing the password within a password-protected store leads to a chicken-egg-problem: How to secure the password being used for unlocking the store.

Best regards,

Lothar

September 2007

Richard_H

John, could you explain what is wrong with doing the hashing client side? The server never sends the client any private data. It is irrelevant what the client does to the data, all validation is done server side. In fact, the client HAS to do the hashing to prevent sending private data.

I also disagree that “Giving someone your security algorithms is the same as giving them the password …”. MD5, SHA-256, Rijndal, et. al. are all public algorithms. Their security does not depend on knowing the algorithm. In fact, I would avoid any security product for which the algorithm is not public.

September 2007

John

“John, could you explain what is wrong with doing the hashing client side?”

Im only saying don’t expose algorithms. If you’re using md5 or sha then that’s all well and good. But either way, the more that happens in server scripts like cgi and php the better.

I don’t see any need for javascript except for “interface polishing” as I like to call it. You know, rollovers and alike.

September 2007

GregoryM

CynicalTyler: thanks for responding. I wrote my post with those views partly to elicit some kind of response.

The uppercasing – it does weaken the password by 2x per letter, but still that’s plenty strong. How are they going to crack someone’s password which is one of (26+10)^8 possible passwords, if it’s hashed? On the other hand, though, you won’t have aggravated users who didn’t realize that the caps lock was on when they put in the password. Is the increase in security so necessary that you would make people remember the case of their password?

Secondly: Yeah, I wondered what was so bad about confirming that a username exists in the system. But I think you’re right – there is no reason we should release that information. So “bad username or password” it is.

Third: No, I simply meant to introduce a tarpit – so you can resubmit a request 1 second later, but you won’t get a response until 5 seconds later. Change the 5 seconds to 2 seconds and you get the point… just put a tarpit there… but I guess yeah it’s unnecessary since you’re cutting it off at n daily tries.

ALSO – the captchas these days can easily be solved, right? There are some good solutions ot prevent spam – but that’s for another post :slight_smile:

September 2007

Rik_Hemsley

Please not ‘nonce’: http://en.wikipedia.org/wiki/Nonce_(slang)

September 2007

Scott

I’m a former plaintext-password-storing web developer. A user called me out on this after a year of operation, and until that point I really didn’t see the problem. It was an “oh-duh” moment.

It’s easy to pick out the websites that do this, since they’re the ones that will offer to e-mail your password to you if you forget it. The ones that only offer a password reset are likely to be adequately encrypting your information.

I’m not a cryptographer either, but when I salt the key, I use a couple lengthy constants of special characters, as well as some other constant data about the user. I can’t imagine a pre-computed table big enough to contain every possible combination of 100 character keys.

September 2007

Telos

I store the SA passwords to our databases on a post-it on the front of my monitor?

Is that incorrect?

September 2007

sikander

It’s unfortunate that sometimes storing passwords as plain text is a contractual requirement from the client because they don’t want to be forced to create a new one when they forget their original password. Sad world we live in.

September 2007

Jim

Or don’t store identity at all: http://identity20.com/media/OSCON2005/

September 2007

Dana

The part you mention about how if somebody obtains a forum password it may be dangerous is very true, in the past I used an exploit in phpBB to gain administrative access to the control panel where I was able to take a backup of the forum and extract the admin’s MD5 and then get it cracked, he was also foolish enough to use this same password as the one for the site’s control panel…actually this happened more than once on a few different sites…but I never did anything malicious to the sites, fortunately for them, I hope they learned that lesson though.

September 2007

Telos

@Brandon: What about black ink?

September 2007

Goran

As I user of many sites I find this helpful:
http://angel.net/~nic/passwdlet.html

Basic premise is this: Use a master password and the service url as salt, then hash it. Since your password is generated at the spot - not even you know what it is (nor should you care).

As far as you are concerned - you only need to remember your master password. The service gets a strong password they can store in plain text if they want.

September 2007

Trevel

While we’re on the subject …

And don’t send me the password in my sign-up confirmation email. I know what my password is: Now everyone else can, too.

September 2007

Bob_Armour

“Add a long, unique random salt to each password you store”

I still don’t quite get this - if the salt is random, how do we reliably generate the same salt value (For the same user) next time they log in?

September 2007

DavidL

After reading your last password blog entry, I’ve been slowly changing my passwords to something a bit more arcane. Upon reading the password requirements for one of my banks, I found that their password rule is that they must be 6-9 case-insensitive letters and/or digits. I emailed them and told them that wasn’t very good. They replied that since their web passwords and phone passwords were the same, that’s the best they could do. They claim to be working on a solution. Mind you, this is a BANK.

September 2007

Jim

Even more scary is that some of the same developers who store passwords in plain text are storing your credit card information.

Years ago, after failing to talk a client out of storing credit card information in the first place, I did a lot of research on how best to secure it - knowing that his hosting environment was going to be, shall we say, inexpensive. Scary stuff, and not a responsibility I wanted.

Every time we code these things we’re betting that no hacker on the planet is a better programmer than we are.

September 2007

Not_Yet

Jeff you should respect the term ‘Hacker’
[I prefer the term: ‘Cracker’ ]

If somebody has access to a password database then
what about the whole directory? Hashing the passwords is
less important than securing the local/web files.

September 2007

David

A better solution than using a static salt (or in addition to using a static salt, even better!) is to salt the password using the username (or some the result of some function on it). Otherwise someone could conceivably determine the salt of your website and generate a rainbow table for all your users. If the salt is dependent on the username, a rainbow table is only good for one user.

Cryptography is really a euphemism for competitive paranoia.

September 2007

Roddy

The facebook example is interesting: As facebook needs your gmail password to log into gmail on your behalf, it’s no use them storing just a hash of it - they must need (at some point) the plaintext at every login. Obviously the passwords should be encrypted in the database, but I wonder if there’s a smarter solution…?

September 2007

JrnZ

How do you avoid storing a password in plaintext when a password-recovery-service is required?

September 2007

Powerlord

a href="http://en.wikipedia.org/wiki/Crypt_"http://en.wikipedia.org/wiki/Crypt_/a(Unix) talks about some salted password system commonly used in UNIX-like systems.

The one currently used in Linux and some of the BSDs is the salted MD5 system mentioned on that page.

As Wikipedia puts it:
"First the passphrase and salt are hashed together, yielding an MD5 message digest. Then a new digest is constructed, hashing together the passphrase, the salt, and the first digest, all in a rather complex form. Then this digest is passed through a thousand iterations of a function which rehashes it together with the passphrase and salt in a manner that varies between rounds. The output of the last of these rounds is the resulting passphrase hash.

The fixed iteration count has caused this scheme to lose the computational expense that it once enjoyed. Variable numbers of rounds are now favoured."

(The article does not explain how you would determine the variable numbers the last sentence refers to).

If you ever look at a hashed unix password that uses this system, it looks something like this: $1$RsDzxp4K$y6ARJtx/TRDYnPWp.3vGy/
Which is broken down as follows:
$1$ = Tells the crypt() system call that this is using the algorithm mentioned above
RsDzxp4K = The salt
$ = salt/password delimiter
y6ARJtx/TRDYnPWp.3vGy/ = password hash
(for the record, the password was “test”)

September 2007

Joe_Chin

Since I’ve started as a professional .NET web developer the first thing that gets written is the password page (After the pseudocode and specifications atleast). I’m working on a project now that uses a lot of different security techniques. We’ve put on layers and layers of security. And if we really wanted to we could make it even more secure. But all of that is wasted because the user has to be able to reset their password if they forget it. Which means that either the email or login field has to be unencrypted or easily decrypted in the database. I call this the ‘leaving the key under the garden gnome’ security.

But it will always be a compromise between security and ease of use until their is a better way to store passwords. And a better way to recover credentials if they are lost.

// My facebook habit of adding friends has stopped in its tracks until they offer another method for finding friends. Whatever happened to the email lookup that existed when it was for college alums and students. One thing I’m not doing is opening my address book for anyone.

September 2007

NicolasW

For another example of “bad programmer, bad!”:

I’m an URGE subscriber. Since they have “merged” with Rhapsody, they migrated my account information. Once, long ago, I had tried Rhapsody out, and had reverted to their free 25-plays-a-month plan.

Now, as Jeff said: no one can remember all 30 username/passwords out there. So, I reuse a few. I happened to have the same login for Rhapsody’s old account and URGE’s new account. So, when they migrated, and I try to login, I get the message:

“You have 2 accounts with the exact same username/password combination. Please call customer support.”

Cheebus. I shudder to think what that stuff is stored in. Definitely not salty, probably very plain. Good for crackers.

September 2007

Heffocheffefer

Whenever I store user passes I always use a salted hash, with the salt stored in the database and unique to each user (just to make it that extra bit harder for the cracker). Using a unique hash per user means that AT MOST the cracker can get one password out of his hash table, before having to change the salt and start again. What does concern me is sites where they say “Alpha-numeric characters only”, or " Your password must be between x and y characters long" they just scream “I store my passwords in plaintext”.

September 2007

ChrisH

Yeah I’ve been at places where they view this as really a non-issue since the only access that could be had would be into our system (and therefore not a huge deal as those systems weren’t really mission-critical). Management just couldn’t see any reason to not store passwords as plain-text… but for one system in particular, I just went ahead anyway and chose a very basic symmetric encryption method that incorporated salt. Yeah it wasn’t great and could be bypassed, but it was something and a lot better than plain-text!

The key point that management couldn’t seem to get was that these users are so very likely to be reusing their passwords! I may have a max of 5 unique (some very secure, some not so secure) passwords that I reuse with all the various username+password accounts around the Internet and in work-related systems. I highly doubt that many regular users have up to 5 unique passwords though…

What about the security of browsers storing user-names and passwords (i.e. Password Manager or AutoComplete)? Specifically Firefox and IE… I heavily rely on Firefox and its Password Manager, but I didn’t know until I checked right now that its encryption can be further tightened. How? [On Firefox 2.0] Here are the steps:

  1. Tools - Options - Advanced tab
  2. Encryption sub-tab - Security Devices button
  3. under “NSS Internal FIPS PKCS #11 Module”, click “Change Password”. Set a secure password (gotta have one more don’t we??).
  4. Click “Enable FIPS”.

SecurityFocus has a great and in-depth article on this topic here that I was referring to on this: http://www.securityfocus.com/infocus/1882

September 2007

Oscar7

It seems you fell in love with the “salting strategy”.
Beware! Now you have to protect the “salting key” too!

September 2007

Gareth

@Bob Armour - wow, you don’t get it 3 times as much as you thought you didn’t :wink: However, I think the idea is that the salt is “randomly generated vs. a dictionary word” rather than “randomly generated per database row”, otherwise there’s definitely an issue - you have to store the salt generated for each row.

@Jrn Zaefferer, Scott - Hashing passwords definitely stops the system from ‘remembering’ your password, however there are many 2-way encryption techniques that use a private key to turn a recognisable phrase into something effectively random for storage and back again when required. HTTPS is a prime example of this. Of course, you then need to ramp up the security on the private key

September 2007

David

That’s the magic of it! You don’t really need to protect the “salting key.” Sure, it makes it harder if the attacker doesn’t know it, but even if they do, they still have to crack the hash (by dictionary attack, or generating a new rainbow table), which is a non-trivial operation.

September 2007

JohnR

“It’s unfortunate that sometimes storing passwords as plain text is a contractual requirement from the client because they don’t want to be forced to create a new one when they forget their original password. Sad world we live in.”

You still should not be storing in plaintext. You should be storing it using reversible encryption. That way if someone gets a backup copy of your database, as happened with Reddit, they still will not have will not have the encryption key you used.

September 2007

RG14

Jorn:

2-way hash.

September 2007

ChrisM

Bob Armour wrote:

“If the salt is random, how do we reliably generate the same salt value the next time the user logs in?”

You would have to either store the user-unique hash together with the salt used to generate it, or make the salt a function of some other piece of information unique to the user account, like the user name.

September 2007

JohnR

The SqlMembershipProvider that ships with ASP.NET uses a unique salt for each hash that it stores.

September 2007

Omry

you know, I thought about using a random number as as salt.
in fact, I thought of using the unique installation ID for it, which is already stored in my database.
perfect.

but then I thought:
damn, if someone gets the database, he gets the unique installation ID along with it.
there goes the theory.

September 2007

Josh

Richard,

What you’re doing is essentially duplicating (to a lesser degree) the conversation that takes place during SSL negotiation. Running the login / register page over SSL allows you to bring the focus of your approach back to the server (since you’ve secured your login packets), where you can execute code in an environment you can trust.

FWIW, I’ve always used a per-user hash combined with machine-specific reversible encryption, such as DPAPI.

September 2007

JW19

I’m not sure what the Facebook example has to do with password storage. They say right in the screen shot that they DON’T store passwords. It’s a one-time login, so they can access your address book, and it’s very convenient. How else would they do it? You’re right that it’s vulnerable to phishing though.

September 2007

TheA

It’s fun to blithley throw around absolutes like “never store plaintext passwords,” but in the real world it’s rarely that easy.

I’d estimate that more than half of commonly used authentication protocols (e.g. APOP, HTTP Digest, CRAM-MD5, etc.) require storing plaintext passwords on the server side. These protocols have in common the ability to authenticate a client without either side sending the plaintext password over the wire. This is good, since the wire is typically easier to attack than the database.

It makes more sense to qualify that sentiment as “never store plaintext passwords when the client is expected to send plaintext passwords over the wire during authentication.”

September 2007

Paul

@Arron G: Could you (or anyone else) elaborate on why the username would be a “far worse” choice for a salt than a “static” salt? I’m afraid I don’t see why that would be the case since by adding a unique salt on to each password, a new rainbow table would need to be generated for each user (assuming unique usernames is a constraint). This seems to be better than having the same salt added. What am I missing?

September 2007

rob8

Send this post on over the American Express… Most of the companies in my area that I have to use for utilities need a good lesson on web security. They don’t allow special characters in passwords which drives me nuts – alphanumeric passwords are horrible. I’m just thankful my bank allows me to use my ‘secure’ password.

Another good note for anyone who uses the same password for many sites: append the URL’s acronym to the end of it. So, for example, if your password is “passwd” and the site is codinghorror.com, why not “passwdCH” :slight_smile:

September 2007

Josh74

In the database:

Username: rahrah

Password: (rah34rah)

Salt (hashed): asjodfj$%^insdjfhkidsjf

September 2007

StCredZero

Use KeePass on a thumb drive.

http://keepass.info/

September 2007

chmike

I though a salt was stronger when containing some random bytes.

September 2007

KeithG

@Paul: Aaron G’s not exactly right on the whole “static salt”/password issue. A “static salt” isn’t really a salt at all because it doesn’t obscure identical passwords in a database any more than plain hashing does. Still, usernames aren’t great salts as they tend to be short and use a narrow range of characters rather than the full character set range. Long strings generated by a high-quality PRNG are better. There’s also the problem that if a user uses the same username and password on two sites, they both use the username as the salt, and they both generate their salted hashes the same way, it’s immediately apparent to a cracker that they’re using the same password on one site as the other. The thing about hashes is that their lossy. When the cracker uses rainbow tables to crack a hash, they don’t necessarily get back the original string, but they might get back an equivalent string. If the two sites use the same salt, once the user’s password is cracked on one, it’s cracked on the other, but by using different salts, it has to be cracked for the other as all the cracker might have is a string which hashes to the same value as the password given a certain salt and hash.

September 2007

Josh75

Posted too early…

Salts aren’t designed to protect a single password, they’re designed to protect an entire database by increasing the time cost of generating a table for each individual user. You can crack any password you wish (which isn’t too strong for a dictionary attack). But once again, do you need more than one password? Especially if you see a nice little username called “admin” or “administrator”.

September 2007

KeithG

@Spoon: email isn’t a secure medium. If somebody intercepts the email, they have your password.

@JW: It’s a bit like this: would you give the keys to your house to somebody just so that they could get a number out of your address book? And you give your ATM pin to a random stranger so you could pay for book? What Facebook and sites like it who ask this kind of information from you are doing is just that. They should ask you for your friend’s email addresses, not your first born child.

September 2007

Heffocheffefer

“Add a long, unique random salt to each password you store”

I still don’t quite get this - if the salt is random, how do we reliably generate the same salt value (For the same user) next time they log in?
Bob Armour on September 17, 2007 06:12 AM

The answer is to simply store the generated salt with the user pass.
For example I use PHP and MySQL and so a simple user information table only needs 3 fields: username, pass, salt

When someone tries to log in then you can check if the details are right by using the following:
$user = mysql_real_escape_string(“USERNAME”);
$pass = mysql_real_escape_string(“PASSWORD”);
$result = mysql_query(“SELECT COUNT(username) FROM table WHERE username = ‘$user’ AND pass = MD5(CONCAT(’$pass’, salt ))”);
if(mysql_result($result,0) == 1)
{
echo “Correct details!”;
}
else
{
echo “You silly hacker”;
}

Hopefully that will clear things up for you.

September 2007

GregoryM

For all you out there that are still wondering how exactly to store passwords in the database…

You don’t. Try doing this as a minimum:

SIGN UP:

  1. Create a user account record with a random salt in it
  2. Put a password input
  3. On the backend, handle the submission by getting the random salt stored in the user account record, appending it to the password, and then hashing the whole thing. MD5 or SHA1 or higher, both are too long to break I think. Oh, and try to be forgiving by not enforcing the case for the password, and just uppercase it … i don’t think users really appreciate having to remember the case!

LOG IN:

  1. Get the random salt from the user account record, append to the password, hash and check against the db.
  2. If it fails, please let the user know what exactly went wrong (wrong password or account doesn’t exist).
  3. optional - Set a timer to delay the next login attempt until 5 seconds have elapsed. But don’t put a low limit on the amount of attempts! 20 attempts should be allowed.

FORGOT PASSWORD:

  1. Enter your email, and the site should generate a new password for you, and put it in the email link. Why do you think the good sites never send you your old password? Because they don’t know what it is!!
  2. As soon as you log in, the site should prompt you for your own desired password.

Peace,
Greg

September 2007

JW110

Keith: They do give you the ability to enter email addresses; they just also provide the import tool as a convenience. I don’t really see it as giving my PIN to a stranger – I have used Facebook for long enough to trust them.

This feature turns what could be a long process (log into gmail, export your contacts, arrange them into the right format, import them into Facebook) into a very simple one. For me it’s worth the tradedoff. But it would be nice if there were a way to only grant them access to my addresses, and not my mail.

September 2007

Julian_Bond

The GMail import is an interesting problem faced by almost every Social Network as they almost all now use libraries to make this easy. It’s also faced by untold numbers of Twitter utilities and many other use cases. There are two lines of attack to deal with this which are related.

  1. Come up with a formal API for exporting and syncing Social Graphs between Social Networks. See Brad Fitzpatrick. Then get it adopted widely.

  2. Come up with a formal API equivalent to OpenID to allow a user to authorise Site A to make data requests to Site B on their behalf. See oAuth.

The problem is not Facebook’s. They’re just using a common bit of code to help the user find their contacts. And it’s not GMail’s. They’re just providing a tool for a logged in user to export their contacts. Unfortunately, it’s the industry’s problem for not coming up with a secure method of doing what the user wants to do.

September 2007

VaibhavG

Storing is one thing. I have seen my share of the bad decisions taken while storing the passwords in plain text. However, we have sites on the internet which do not allow strong passwords.

My personal experience with a payment gateway provider recently taught me that. Their rule was 5-8 characters with no special characters allowed. There is a screenshot on my blog: http://blog.gadodia.net/leading-payment-gateway-disallows-strong-passwords/

I couldn’t come up with an 8 character password without a special character that would show up as strong on the Microsoft Password Checker.

September 2007

Eam

@John Rutherford:
"You still should not be storing in plaintext. You should be storing it using reversible encryption. That way if someone gets a backup copy of your database, as happened with Reddit, they still will not have will not have the encryption key you used. "

Man we already went over this in Jeff’s last post on encryption. The attacker will just get the key, too. If it’s an inside job, this will be trivial. If not, and the attacker can’t get the key, why aren’t you securing your database backups the same way as the keys?

Just store the hash. Password-resetting works just fine. There is absolutely no reason to store passwords (sym. encrypted or plaintext) in a database.

September 2007

Me129

In Jan I was at a company meeting. During the presentation, the dufus who put up some wiki service told us that the back of the room had cards layed out with our username/passwords. I looked at mine and it was my generic password that I use (I had logged in and changed my pwrd prior to the meeting).

So I go to bitch to them, and about 10 other people that this idiot has peoples passwords sitting on the table for anyone to look at. The response I got was “Well, it’s just for this service.” Nobody could grasp that people will re-use passwords and this may give them access to their network or other services.

I finally found one of the directors who went and removed them from the table. I got let go 3 months later. I hope the company burns in hell.

September 2007

Catto

Hey Now Jeff,
As always I enjoy reading your post. I’m interested in your thoughts of CardSpace any similar technology as an improvement to this situation we have of many UID’s pw’s.
Thx,
Catto

September 2007

Eam

@Heffocheffefer:
Well you seem to have the database implementation details correct, but if you really want a secure program, I feel like I should tell you that PHP now supports parameterized SQL.

Even if you remember to mysql_real_escape_string() everywhere, it still has issues escaping multi-byte character sets, IIRC.

September 2007

codinghorror

The problem is not Facebook’s. They’re just using a common bit of code to help the user find their contacts.

That’s interesting, because Facebook uses images with one-hour expiration tags to prevent anyone from screen-scraping their contacts. Which is exactly what they do to other services…

http://www.25hoursaday.com/weblog/2007/08/21/FacebookTheSocialGraphRoachMotel.aspx

How do you avoid storing a password in plaintext when a password-recovery-service is required?

Why do we have to email the current password to the user? We can simply reset the user’s password, and let them change it after they log in.

if the salt is random, how do we reliably generate the same salt value

I was confused about this as well. You store the hash of the random, long salt in the user table right next to the hash of the password. It’s not a secret, so you don’t have to hide it.

September 2007

Andy

While I admit that all these cross-site functionalities that require one to tell site A what their creds are for site B are open to phishing attacks, as outlined, if site A hashes the password provided for site B, how is site A supposed to make use of those credentials to interface with site B? Site A should encrypt the credentials somehow, in a reversible fashion, so that the credentials can be used repeatedly (assuming that repeated access to site B is part of the feature, for continuous updates) – hashing won’t provide that.

The real fix for this is that sites need to stop being walled gardens and need to encourage cross pollination by providing features to allow users to designate other people/sites access to their data, and need to provide APIs that can be used to programmatically interface with other sites to avoid having to “login” as a user to access that user’s data.

September 2007

Matt

“You store the hash of the random, long salt in the user table right next to the hash of the password.”

Why would we want/need to hash the random salt value? If it is completely visible and completely random then does it make sense to hash it before adding it to the password? Or am I missing something?

September 2007

Andrew_R

if the salt is random, how do we reliably generate the same salt value

I was confused about this as well. You store the hash of the random, long salt in the user table right next to the hash of the password. It’s not a secret, so you don’t have to hide it.

I thought the main idea was that if the database is compromised that the salt would help protect the hashed passwords. If you store the hashed salt in the database, then the salt is no safer than your hashed passwords.

So this really presents a two simple scenarios.

  1. Entire application is compromised, source, database, everything. In this case you’re totally screwed and you need to roll over to a backup plan.

  2. Just the database is compromised. If you store a hash of the random salt in the database it’s not clear to me how you can determine what the original salt was so that means the algorithm is a simple concatenation. salt + password or password + salt. You cannot create a more complex algorithm than that unless you have a way of determining what the salt is. If you store the password plain text you’re almost better off because now you need to account for the salt as a split string and the attacker has no way of knowing short of compromising the app how to shortcut his way past combining the salt and password.

September 2007

Nathan_Bell

if the salt is random, how do we reliably generate the same salt value

I was confused about this as well. You store the hash of the random, long salt in the user table right next to the hash of the password. It’s not a secret, so you don’t have to hide it.

Are you sure about that? Since hashes are one way, how would you compare a randomly salted password with a provided creditential with out knowing the (unhashed) salt?

September 2007

Eam

@Jeff “Short Flip” Atwood:
“I was confused about this as well. You store the hash of the random, long salt in the user table right next to the hash of the password. It’s not a secret, so you don’t have to hide it.”

What are you talking about, baby? Either that hash is the salt, or you don’t hash the salt. Either way, you need to store the actual salt (possibly encrypted [a]symetrically) in the database.

September 2007

codinghorror

Why would we want/need to hash the random salt value?

I guess I was thinking of storing hashes in both columns just for consistency’s sake:

hashed salt, hashed password

And then we would compute the password hash by appending the hash of the salt instead of the salt itself:

pass = hash(hashed salt + password))

But you’re both right-- it probably doesn’t matter whether we use the actual salt or the hash of the salt.

September 2007

Robert

Jeff,

Excellent post. One other point (perhaps you can add this to your post): Software developers should never, ever ever email passwords to users in plaintext.

A year ago I signed up with a website that provides a minor free service. As soon as I signed up, I received a confirmation email to the effect of “Thanks for signing up! Your username is ABC, and your password is DEF.”

This meant that not only were they storing the passwords in plaintext, they were emailing it around in plaintext for anyone to see. I was astounded by their incompetence. (I sent them an email, but they never responded.) I had not even asked for them to send my password. Rather, they did this for all new sign-ups.

Of course, the username and password were also the same ones I use for my email service, so anyone with half of a brain could have intercepted this email and gained access to my email account (and other online services.)

You can criticize me for repeating user names and passwords, but I can’t remember more than a few passwords without writing them down. I have another more-secure password for financial sites, and that’s it. I refuse on principle to create a new password for every trifling website I visit.

The bottom line is that services should never send passwords via email. If someone forgets the password, they should instead send a password reset and require the user to enter a new one.

September 2007

Eam

There seems to be a ton of confusion about what a hash is. A few points people seem to be missing:

Rainbow table attacks are basically a scan for the “low-hanging fruits” of the password database. They immediately reveal the insecure passwords, but typically will not crack the better ones. Salts prevent these attacks from scanning the whole table at once.

@Aaron G:
Very interesting point. The username/password combination being a dictionary word is fairly intuitive, but you’re absolutely right that even using the hash of the username doesn’t add much security.

September 2007

JimmyB

Great post. I also made one recently about the subject.
Saving passwords in a database? No!
http://jtbworld.blogspot.com/2007/09/saving-passwords-in-database-no.html

September 2007

Andrew_R

@Robert
Excellent post. One other point (perhaps you can add this to your
post): Software developers should never, ever ever email passwords
to users in plaintext.

A year ago I signed up with a website that provides a minor free
service. As soon as I signed up, I received a confirmation email to
the effect of “Thanks for signing up! Your username is ABC, and your
password is DEF.”

I agree with the point you’re making but it would be simple to implement a registration system that emails the user their credentials upon submission and then stores encryped or hashed values into the database for later use.

September 2007

Mark_Nelson

Just got an email from web 2.0 hopeful Joopz, giving me a free upgrade to premier status for one month, along with a helpful copy of my user name and password from a long ago registration.

We need a hall of shame for these people.

September 2007

sobani

For those who still don’t get it: a salt is not some kind of extra password. The entire world may know what the salt is. The salt is a way to lengthen the user password to such an extend that it will be undoable to create a generic rainbow table up front.

If you use a salt, a cracker will have to build a new rainbow table specially for that salt. I don’t know if anyone ever tried to use brute force to retrieve one of their own passwords, but trust me, it’s a pain, as long as the password is long enough. Building a rainbow table is basically doing brute force, but then you also store every combination you generate, so you can check other hashes with earlier attempts.

Of course, after a while a determined cracker will have generated a rainbow table for a specific salt also, so there the user specific salt comes in. If you choose this user specific salt well enough, a cracker will have use brute force for every single password you stored. Saving the results in a rainbow table is useless now, because the majority of the bits that were used to generate the password hash, are unique per user.

[tinfoil_hat] I guess only the NSA has the capacity and the use for such huge rainbow tables. And trying to fight the NSA isn’t going to attract a lot of users, who, after all, only want to see your fluffy bunny dancing.[/tinfoil_hat]

In short: you don’t need to secure the salt, you only need to make it unique, lengthy and random.

September 2007

Foxyshadis

Something I haven’t seen mentioned is row-level encryption of database fields. That protects you from some attacks and not others, of course, and it’s a high-end database feature… but when you have it it makes sense to use it. (And you can always change your database backend code to use it at a higher level - but that’s slow, and an enormous pain to keep synched between backends, especially if you work in several different languages, to say nothing of when you have inline SQL queries.)

September 2007

Foxyshadis

As an aside - I’m quite glad that I don’t even know any of my passwords anymore, aside from the one I use for throwaway sites. It’s amazing how well these password hash systems work. (The downside is that it becomes very hard to change passwords short of complicating the scheme more than I’d like.)

September 2007

brian59

When requesting a password reset, the password for cox cable emails is the word password. You would be surprised at the amount of people dont ever change it. When reseting passwords never use a default.

September 2007

Jeff

Google’s AuthSub is a nice solution to some of these cross site issues. I found it easy to authorize and import Google Docs without seeing a user’s credentials or resorting to the ‘benevolent phishing’ maneuver.

http://code.google.com/apis/accounts/AuthForWebApps.html

Unfortunately it’s not supported for all of their APIs yet.

September 2007

Craig

I believe you’ve made a cardinal mistake, and in fact, your md5(‘deliciously-salty-’ + password) (md5 can be replaced with SHA-2 or any other hashing algorithm) is vulnerable to the very same rainbow table attack!

With a fixed salt (the ‘deliciously-salty-’) part, one can compute a rainbow table for that algorithm and that salt, and crack any arbitrary password (with the larger the table, the more classes of passwords that you can crack).

The correct way to store passwords is to store two values for each user: a salt (which is a randomly generated string of any length, the longer the better to a point), and hash(salt + password). That way, you cannot compute a rainbow table, and cannot crack the password.

As for the speed of a hashing algorithm being a vulnerability, you may be wrong. The security of the algorithm is the important part. md5 is a technically broken algorithm, and SHA-2 is technically better, but we are talking about security experts here - their idea of broken is different than ours. For all practical purposes, especially in this use case with the combination of random salt, md5 is still secure. See http://en.wikipedia.org/wiki/Md5#Vulnerability

For example, for www.goruneasy.com, I used this md5(random-salt + password) method. The salt is a 10 character string, using characters where each character’s ASCII value is between 1 and 253, creating an incredibly large potential space. I don’t believe, unless a truly massive vulnerability is found in the md5 algorithm, that this approach can be compromised.

September 2007

smackfu8

It’s too bad there isn’t a generic authority-granting API. Various sites have hand-rolled ones, like Flickr and Facebook itself. For instance, if you want to use the Facebook Firefox extension, it kicks you off to Facebook, where you enter your password on the Facebook site, and then you allow the extension authority. No password ever given to the extension.

The obvious problem with custom APIs is that each provider needs to write one, so if GMail doesn’t have one, you’re screwed. And you need to write custom code to talk to each one, which is no fun either.

September 2007

EivindU

For those interested I wrote (read: patched together) a Rails plugin that handles authentication using Coda Hale’s bcrypt library:

http://acts-as-authentable.googlecode.com/

September 2007

FiSh

This is the way I’ve always felt about a user’s trust online - if it has a pretty layout and stock models appear to enjoy using the website, the user will trust the website with any information it asks for. Sadly, this applies here - people think that FaceBook is some invulnerable application because it’s large, when these are exactly the types of things that are under such great scrutiny.

September 2007

Tjerk

Salting password is not neccesary, an encryption algorithm like SHA is enough… and offcourse a minimum length for the password.

September 2007

KevinN

I gave up reading the conversation since it is essentially the same one we had with Jeff’s last posting on password storage. I know I brought up a couple points which with further reflection turned out to be incorrect (Not sure what I was thinking). No need for details though, since obviously the conversation continues.

The logical and mostly correct outcome of the discussion is good, stored password hash + random salt = good security. Question is, will this design withstand the test of time.

Everyone is aware of the botnets, and the amount of spam being put out, which is almost an entirely seperate issue. I’m just curious if anyone else is scared to death that these botnets could be turned against our authentication systems themselves. You have a generally accepted good security practice, HASH + random salt stored in database, how long do you think this can stand up against a million or more PC botnet?

What is the targetted lifespan of your system?

What if your end user uses the same password for 10 or more years?

I have nothing against a good password scheme, but rule number 1 should always be, don’t give away your database. Your system security architecture should be so good that the “evil” bad guys are unable to obtain your database from forgetten backups and all the other methods. The true reason we need to secure the passwords in the database, is we’re not sure we can keep the data safe, and it’s also very easy to implement rudimentry protection, that as it stands can discourage your script kiddies.

Rudimentry protection will not always be enough.

September 2007

sobani

woops, my apologies. I didn’t knew my first try got trough already. Please remove the first try (and this reply)…

September 2007

BryanW

Yes, this very issue started with me when Word 2007 came out with its clear-text-password Blog-posting feature. Sad.

September 2007

Mike

It’s pretty spectacular how nobody really understands salts.

The point, people, is so that you can invalidate pre computed hash values (rainbow tables) by pre-pending a constant but random string in front of your password. It doesn’t have to be hidden, it doesn’t have to be random each time. It just needs to be somewhat longer than the clear texts used to create rainbow tables. If a user has a ‘password’ for a password, cracking it will take the duration of a a seek and scan in a DVD full of precomputed hashes. If a user has 128 bytes of garbage + ‘password’ as their password, chances are the DVD won’t have the answer.

I wonder if anyone reads this far down. I know I didn’t…

September 2007

AnonymousC66

Depending on what you actually want to do with the password, you may have to store it in plain-text. Most CHAP implementations require this, for instance. What does using CHAP get you? You’re not asking the client to send his secret over the wire. This is obviously a good thing. Other examples of security protocols that depend on both parties sharing a known secret (e.g. a password/username pair) with similar characteristics can be easily found.

For web development – in particular, for implementations of a classic web “login” service – here are some symptoms that may indicate that you probably need a plain-text password somewhere:

*) One of your requirements is to offer a “password recovery” feature
*) The secret is going to be re-used for other types of authentication (think “Single Sign-On”) that require plain-text secrets
*) The secret may need to be shared with other partners who are unwilling or unable to deal with using your authentication service

September 2007

MatsH

@Tjerk

Salting password is not necessary

Given the information presented so far in this thread, you’re right. So far, salts have been discussed as a mechanism for making the password longer, as a way to defeat rainbow tables (and brute force, for that matter). In this perspective, salts buy you nothing that a longer passphrase wouldn’t buy (except possibly somewhat higher entropy).

The real reason for using salts is not as a password extender (that can be solved with longer passwords) - it is as a password mutator.

The reason that salts are used is that users reuse their passwords between systems. If I crack your password on one site (finding an input string that produces the same hash) I can now log in as you on all other sites that use the same hashing function and where you have used the same password. Unless, that is, the password has been salted differently on all those different sites. Then I could only log in to those other sites as you if I actually have your plain text password, which is not what I get by cracking a hashed password.

Thus, you could acheive the real purpose of having a salt by using the salt value to mutate the password in some way without even making it longer. You could even make the password shorter. The important part is that, even if I use the same password on all sites, my password will be mutated differently on all sites, so that someone who has found a string that results in my hash on one system won’t be able to reuse it on another system.

Of course, mutating the the password so that it becomes shorter would have the negative side effect of making the password easier to crack, so that is obviously not the suggested approach. Correspondingly, if you mutate the password in such a way as to make it longer, you make it a little harder to crack as a bonus. But this is a bonus, and /not/ the primary reason salts are used.

I’ve just written a blog post trying to explain this difference and why, in my opinion, storing passwords in plain text should be illegal.

a href="http://www.matshelander.com/wordpress/?p=73"http://www.matshelander.com/wordpress/?p=73/a

/Mats

September 2007

MatsH

Appending (as is my habit…)

This perspective (salts are primarily for mutation rather than extension) also allows you to understand why early salts were often pretty short.

It is not the case that the makers of those early systems thought a couple-of-bytes salt would be enough to /extend/ the password in a meaningful way, making it more immune against brute-force attacks. Instead, they correctly recognized that it would be enough mutation to serve the primary purpose of using a salt as a mutator, preventing reuse of hacked passwords between systems.

Since then, salts have grown as this allows the secondary bi-effect of making the passwords longer and harder to crack to be exploited - which is, of course, all fine and good.

The problem comes when the primary purpose is forgotten and someone correctly observes that using longer passwords would then make salts unecessary - that’s true with regards to the secondary effect of making passwords longer, but it is not true with regards to mutating passwords between systems.

/Mats

September 2007

Pat_Cahalan

Not storing passwords in plaintext is good in theory, but
in practice it’s not always possible.

In practice it is always possible. I know of no mail client that does not support either TLS or SSL connections; there has not been a need to support plaintext authentication for mail relay for some years now.

And if you tell me that “I have a user that will only use a particular piece of broken software”, the answer to that question is “plaintext passwords are no longer an acceptable security risk in today’s internet, sorry.”

You can’t use telnet for remote administration any more. You ought not to be using unencrypted POP to get your mail, or unencrypted SMTP to send your mail.

Regarding salt, Mr. Helander explains correctly.