Hacker News new | past | comments | ask | show | jobs | submit login
How To Safely Store A Password (2010) (codahale.com)
93 points by baddate on Dec 3, 2020 | hide | past | favorite | 61 comments



This blog post was instrumental in convincing large swaths of programmers 10 years ago why normal hashing doesn't cut it. This was in a time that PHP code snippets doing md5($password) were widespread. If people were even hashing passwords at all. It was a time when lots of crypto was hard to use for programmers, and the jargon gap between cryptographers and programmers was even bigger than it was now. A blog post that unambiguously told people what to was uncommon and much needed.

This post truly is internet history. Complaining that there's alternatives today that solve the same problem better than bcrypt is beside the point. The fundamental insight hasn't changed, only the best available algorithm.


Strong agree, noting also that bcrypt still holds up well.

Articles like these set off a bit of a research fad in designing password hashes, which is great, but also created the impression that using the wrong password hash is like using SHA1 or 1024 bit RSA, which is not the case. By all means, use Argon2 if you like; it is "better", but not decisively so. Or just put PBKDF2, scrypt, bcrypt, and Argon2 on a wall and throw a dart.

The danger is in not using a password hash at all, but rather using a "salted hash".


With password storing, you want to cover your ass. One way to do it is follow guidelines of known authority, e.g. NIST or OWASP.

OWASP has nice document: https://cheatsheetseries.owasp.org/cheatsheets/Password_Stor...

It boils down to this:

> Bcrypt is the most widely supported of the algorithms and should be the default choice unless there are specific requirements for PBKDF2, or appropriate knowledge to tune Argon2.


Interesting how many corporate security policies act like they don't even know NIST exists. Password rotations for users are audit crown jewels but recommended against by NIST


The problem is really the opposite – too many organizations slavishly follow the pre-2017 NIST guidance!

Per wikipedia:

> From 2004, the “NIST Special Publication 800-63. Appendix A,”[2] advised people to use irregular capitalization, special characters, and at least one numeral. It also recommended changing passwords regularly, at least every 90 days. This was the advice that most systems followed, and was "baked into" a number of standards that businesses needed to follow.


I agree. I cannot recall a single corporate password policy in my working life that did not require regular password resets. And now that I think about it, I am surprised that Google does not ask me to reset my password on a regular basis. I guess Google follows the latest NIST advice!

(For other readers: It seems that quote comes from here: https://en.wikipedia.org/wiki/Password_policy)


NIST used to recommend password rotations not that long ago, pretty recent change.

I work in a compliance heavy environment and have tried getting the rotation policy changed, but it's baked into so many contracts at this point it will take another 5+ years before we to the ~2018 era guidelines.


50% company doesn't know or care, 50% the company knows and wants to implement security but the auditors are stuck in 2005 (PCI Compliance: unless you somehow documented clearly your 'mitigations' because you are NOT rotating your passwords, you fail somehow).


>recommended against by NIST

As a layman who has too many passwords that rotate too often to keep in memory effectively, I'd like to pass this along to our IT department. Can someone post a link to the NIST best password practices?



It's also important to note that password rotations are not recommended by NIST as long as the other guidance is also being followed, i.e. password length requirements. I've seen people quote small sections of NIST recommendations while missing out on the context.


Bcrypt doesn't have memory-hardness, so has high susceptibility to ASIC attacks. In particular, it incurs the same or lower cost factor on the attacker than the user.

More recent designs such as scrypt and Argon2 force high memory usage as well as computation time, incurring little cost on the users but making ASIC and GPU attacks significantly less cost-effective.

Of course, any of these will still give better protection than plain cryptographic hashes.


In general it is is not true that Argon2 should be recommended over bcrypt. Even even some of the people on the experts panel for the PHC (where Argon2 won) won’t recommend Argon2 over Bcrypt: https://twitter.com/TerahashCorp/status/1155129705034653698

Looks like for the typical case (~200ms calculating the hash) bcrypt beats argon2. I guess that’s what I understand from those discussions, I’m not an expert by any means. It is related with cache hardness: https://twitter.com/Sc00bzT/status/1149963675069026304


Interesting, I hadn't seen this before. I find it hard to believe, as Argon2 does psuedorandom access over a large array. As soon as this array gets larger than the local GPU cache (much smaller than CPU cache), we should get pretty good protection. What have I missed?

In particular, in terms of ASIC attacks, bcrypt and other non-memory-hard KDFs have extremely efficient implementations. Silicon is cheap, computation is cheap, memory access is extremely expensive- both in terms of time and power usage.


Wow. Never heard that before. Would love a proper article on that. I wonder how scrypt holds up


I am not a security expert, but this looks pretty useful: https://security.stackexchange.com/questions/193351/in-2018-...

And that Twitter link (https://twitter.com/TerahashCorp/status/1155129705034653698) leads here: https://www.password-hashing.net/ ... but, on that website, I could not find an explanation about why to use argon2 over bcrypt.


Is there any scrypt or argon2 implementation for nodejs that has as nice an api surface as the bcrypt package? Specifically, it will generate a salt for you (included at the beginning of the generated hash). This has the great properties of: can't forget to use or store the salt; use a weak salt; or forget to use the time-safe compare function. I want to minimize the number of footguns available to the person coming after me, who I suspect will not do the same depth of research and understanding before making changes as I have when setting this system up.


This argon2 implementation[0] looks good to me. It uses a native module so it should be fast, and I like the look of the API. It returns the salt and params with the hash in one string, so storing and verifying looks real simple. It appears to be maintained. It has TS type declarations, if you are into that sort of thing.

Here is an scrypt just in JS[1]. It will also run in the browser, if you need to hash client side for some reason. On node, it will use the built in crypto api which IIRC is a wrapper around openSSL so perf should be native. I'm not a big fan of the API, you have to concern yourself with buffers and normalization. Maybe that is important for non-latin alphabets? I don't actually know, I'm too anglo-centric.

Then there is good ol bcrypt[2]. Certainly the most mature, it has been around a while. Like [0], it also uses a native module with node-gyp.

All three support async/await so you can avoid blocking the event loop during expensive hashing operations. I should note I haven't really used any of them. I was just curious so I did some googling.

Based on your criteria, I think [0] fits the bill best. Very hard to forget the salt, as it is generated by default and stored with the hash.

I'm always really curious about other people's code, so I hope you don't mind me asking: I typically use a library/framework that handles details like password hashing. That said, sometimes i like to avoid libs and really understand every aspect. Can I inquire about your stack? Are you using express or koa or anything like that?

[0] https://github.com/ranisalt/node-argon2

[1] https://github.com/ricmoo/scrypt-js

[2] https://github.com/kelektiv/node.bcrypt.js


I'm using express, and currently "good ol' brcrypt" (your [2]) for the reasons I mentioned and because it is battle-tested, as you say. On the "battle-tested" note in particular, I am not confident in my ability to evaluate the trustworthiness and technical competence of most of the libraries out there. And while something like this[0] provides algorithm recommendations that I trust, there are no specific implementations referenced. "Good ol' bcrypt" is widely referenced enough that I feel comfortable using it, and I would also feel comfortable using node's built-in scrypt, except for the shortcomings in its api that you and I have already mentioned (aka "things that I do not want to concern my employer with once my contract is finished").

I think it's fine enough if I stick with bcrypt, and that's what I'm planning to do, but I saw this was on the front page, so I opportunistically made the comment hoping that someone with experience in this area (e.g. tptacek) might see the question and jump in :)

[0] https://latacora.micro.blog/2018/04/03/cryptographic-right-a...


Yes, scrypt-kdf works great:

    const scryptParams = { logN: 15, r: 8, p: 1 };
    async function hashPassword(password: string): Promise<string> {
    const password_hash: Buffer = await scrypt.kdf(password, scryptParams);
    return password_hash.toString("base64");
    }
    async function verifyPassword(hash, password): Promise<boolean> {
        return await scrypt.verify(Buffer.from(hash, "base64"), password);
    }


Is scrypt actually recommended? When I think of scrypt, I think of the Litecoin and the numerous "altcoins" that use scrypt that were forked from Litecoin in late 2013/early 2014.

I know that Litecoin used scrypt to harden it against GPU/ASIC mining, but GPU/ASIC miners ended up coming out anyways. With this in mind, is scrypt actually a better option than bcrypt?


Came here to say this. I'm guessing we are both just the unlucky saps whom the algorithm chose to screen new submissions.


Surely HN doesn't do that... Pardon me if I missed your joke. More likely explanation is that CA isn't awake yet!


For what it's worth the php implementation of password hashing offers a function to determine whether it's time to rehash a password. https://www.php.net/manual/en/function.password-needs-rehash...

The idea is to alert an application program to the need to regenerate the hash at the time it has the plaintext password in hand (when the user has just presented it for login).

This is a great idea; rehashing a long-standing bcrypt password with a larger work factor makes it safer.

And, an extension or new version of the runtime can add a new hashing scheme.

It would be sweet if other password-hashing APIs added the same kind of thing. User accounts can last far longer than LTS versions of software runtimes, and this can help future-proof them.


PHP truly has exemplary built in security functions, other language / standard library teams should look at this in awe. It's pretty unique that a language, among its included batteries, actually makes it easy to correctly not roll your own crypto.


On the other hand, this is also the language that implemented off-spec Rijndael in mcrypt and named it as if it were a standard AES encryption function.


I cracked a lot of sha512crypt and PBKDF2-HMAC-SHA256 hashes with a cheap GPU at Defcon this year. Here's the write-up.

(Cracking Passwords with Cheap Hardware at Defcon):

https://github.com/62726164/cmiyc2020


Do I understand correctly that you cracked about half of the 12,000-iteration PBKDF2 hashes using a first-gen ThreadRipper and a GTX 1060, and would have cracked more except for a formatting problem in the hashes? That's eye opening.

Is Word Machine publicly available, or is it the sort of thing that has an audience of one?


Yes, that's right. I may have not cracked them during the contest (but just after). I don't recall. Once I figured out the pattern, I could attack it much more efficiently. So, it's not as impressive as it seems.

And, unfortunately, wm has an audience of one. Mostly because I'm ashamed to share it.


I recently did a write up on Bcrypt, for anyone who is unfamiliar with it's technicalities: https://qvault.io/2020/08/24/bcrypt-step-by-step/


I have started to look at a model where the device itself is the password. How often do we realistically need to concern ourselves with the scenario where multiple users are utilizing the same physical device in 2020?

Imagine every device has a cookie/token with 256-512 CSPRNG bytes which uniquely identify it. The server uses this as the exclusive means of authentication. For sensitive application scenarios, an in-app PIN mechanism can be used as a soft protective measure (e.g. Robinhood mobile apps use this). The device you initially sign up on can be used to activate additional devices by way of scanning a QR code, offline recovery codes, SMS, etc.

This model makes it so that a user has no username or password to remember. They just need to make sure they have a backup device and/or offline recovery options available. I find that side-stepping the problem altogether might be the best solution for all involved. Users loathe remembering passwords. Developers screw up password hashing constantly. Malicious actors should grow to strongly dislike this approach.

This also provides a much stricter chain of custody over how additional devices are added to an account. You have to already have a trusted device to bring another. Making the "What you have" (device) the first factor, and the "What you know" (i.e. pin code) the second factor seems to work out a lot better looking forward.


That's pretty much the webauthn specification that is already available in most major browsers.


> They just need to make sure they have a backup device and/or offline recovery options available.

There's the hard part.

Go to the World of Warcraft forums and ask how many people have had trouble dealing with identity verification with Blizzard because they lost or destroyed their phone and no longer have access to the Blizzard Authenticator app and are therefore locked out of their account. Sure, the app will give you backup codes you can use to restore the Authenticator on a new device, but clearly very few people are actually recording those somewhere.

> Developers screw up password hashing constantly.

Developers should know better. There's no excuse for continuing to use poor/no hashing for password storage.

> Malicious actors should grow to strongly dislike this approach.

Not as much as you think. Considering how many people still think that fingerprints are secure, if stealing someone's device means having access to everything they have, then "your device is your password" is flawed. PINs and swipe patterns are trivial to shoulder surf.


So there's a bunch of people here saying Argon2, whereas I thought one of the current best recommendations was scrypt. Can someone explain the trade-off between them?

Why would you pick one over the other? Or are both "pretty much fine" for most workloads and a casual user shouldn't worry too much?


Both are pretty much fine. Just choose one. With certainty approaching 1, you will not run into a situation where this is a meaningful decision for you. There are a lot of security decisions that really require more thought, this is not one of them.

bcrypt, scrypt, Argon2: it doesn't practically matter. Actual cryptographers don't stop recommending safe and well-tested algorithms just because newer ones have been published. There has been no cryptanalytic break in bcrypt or scrypt. The benefits of Argon2 are largely academic for common workloads.


Going off of memory, happy to be corrected.

So something like pbkdf2 is intended to be "CPU hard" ie: it bottlenecks you on CPU. Then people started using GPUs for pbkdf2.

So we got bcrypt, which is CPU hard and uses enough memory that a GPU stops being particularly practical.

And then people build ASICs to bruteforce bcrypt faster. So we got scrypt and argon2, which are memory hard.

But the thing is that even PBKDF2 is pretty good. You can always just bump up the iteration count for PBKDF2 to increase security. I use a combination of PBKDF2 and bcrypt myself (pbkdf2 on the frontend, bcrypt on the backend).



Several days ago I favorited this comment, which is a list of authentication vendors and open source projects:

https://news.ycombinator.com/item?id=25212694


This works for me...

https://www.google.co.uk/amp/s/nakedsecurity.sophos.com/2013...

(Apologies for the blasted Amp link... on my phone)


Cryptographic hashing decreases entropy because it is based on a compression function. Most password stretching algorithms are not optimal in that respect, especially if they repeatedly lengthen the plaintext before hashing it again.

There are constructions to avoid this problem but they are not commonly used.


This is definitely true as far as the math goes, applying a prf does reduce entropy. But does it decrease it in a way that an attacker can take advantage of?


Just me quibbling about language, but this article should really be titled "How To Safely Store A Hash That Lets You Verify A Password". Nobody who knows what they're doing (including the author) advocates storing passwords, even encrypted.

But an article with that title would probably be less visible to the audience that really needs to read it.


How To Safely Store a Password (2020): Don't

Feeling glib, but passwords are hot potatoes best to avoid if you can. There are plenty of OpenID Connect providers to pass off the buck to, or an increasing number of "passwordless" options including the simple scheme of one-time codes delivered to user email addresses.


> So I’m not saying salts are without purpose, I’m saying that they don’t prevent dictionary or brute force attacks (which they don’t)

Only true if you don't know the salt. Of course, most folks store the hash and salt in the same table or column (Django).


Just get rid of passwords.


Ten years ago, bcrypt was a fine suggestion. Today, I'd suggest Argon2.


I guess every article on password security should have a disclaimer: "If this is more than 5 years old, take it with a grain of salt and look into current best practices".


What's "not fine" about bcrypt today?


> Use bcrypt. Use bcrypt. Use bcrypt. Use bcrypt. Use bcrypt. Use bcrypt. Use bcrypt. Use bcrypt. Use bcrypt.

Use argon2. Use argon2. Use argon2. Use argon2. Use argon2. Use argon2. Use argon2. Use argon2. Use argon2.

https://github.com/P-H-C/phc-winner-argon2


It doesn't matter. Just choose either of them. You are almost certainly not going to run into a situation where choosing Argon2 over bcrypt made a difference in your security posture.


I think argon2 is harder to suggest over bcrypt for a general recommendation since it has more parameters and therefore easier for users shoot themselves in the foot.


Is Argon2 as tried and tested as bcrypt?


It doesn't matter. For password hashing, Argon2 is fine. bcrypt is fine. scrypt is fine. You should distrust people who make a big deal out of which one you use.


I always say the best piece of advice on this is, "Don't store passwords." Like shown in other comments, the landscape of what should be used changes frequently. Truthfully, I haven't had to write anything that stores passwords for several years, and until now I hadn't heard of Argon2. That's frightening to me and shows how far out of the game I am now.

Finding a trusted 3rd party who's responsibility is to stay on top of it, is definitely the way to go if you're not in the security space. It's scary how many people don't understand the basics of hashing and encryption that have written authentication systems. When people ask me if we should do something like this, I normally say, "If you're asking me, then you probably already know the answer."


Counterpoint: A dedicated "authentication party" is a privacy nightmare and a single point of failure.

See https://news.ycombinator.com/item?id=25091420


Very true, there are drawbacks to using 3rd party authentication and I think a good (at least) middle ground is to purchase a hosted appliance that handles storage and authentication. Of course if you are a large organization that can hire people who do know what they are doing, you are golden. Sadly, these are not the companies that I generally interact with.


Oh, I think I misunderstood your comment. I thought you were referring to third-party auth specifically.

Another option more on the cheaper side would be a library that handles algorithm selection and migration in a "black box" way. I.e. the public interface is only `db.put(user,newPass)`, `db.compare(user,suppliedPass)` and maybe something like `db.doMaintenance()`. You would need to handle storage yourself in that case but I don't see the downside of this when you are storing your users' data anyways. I'm not aware if such a library exists though.


See also this list of vendors and open source projects (disclaimer, my employer is one):

https://news.ycombinator.com/item?id=25212694

What hosted appliances offerings have you taken a look at?


What's the backup plan when 3rd party will ban your website because of any reasons?


Send people emails to reset their password with your new auth solution.


> Like shown in other comments, the landscape of what should be used changes frequently.

It does not. I agree with you that you shouldn't store passwords if you don't have to, but bcrypt and scrypt are still absolutely fine. You do not need to choose Argon2. Cryptographic algorithms shouldn't be deprecated just because something new came out, they should only be deprecated when there is a specific, published cryptanalysis that weakens them.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: