17 ms·
Enough with the Salts: Updates on Secure Password Schemes
- sarciszewski 12y agoI've been saying "scrypt, bcrypt, PBKDF2, or bust" for years. Also, there's a large industry trend of, "let's 'pepper' our hashes too!" whereby they have a sitewide salt. This is a mistake. If you want to add a site-specific layer of security to your passwords, encrypting them makes far better sense than adding to the salt. https://github.com/lizardhq/php_bcrypt_aes https://github.com/lizardhq/php_bcrypt_aes http://blog.ircmaxell.com/2015/03/security-issue-combining-bcrypt-with.html http://blog.ircmaxell.com/2015/03/security-issue-combining-b...
- nmc 12y agoFound the "unnamed blog" post giving the "terrible" salting advice: http://blog.codinghorror.com/rainbow-hash-cracking/ http://blog.codinghorror.com/rainbow-hash-cracking/
- xxxyy 12y agoThe title seems to be misleading. Nowhere in the article does the author explicitly state that salts should not be used, because well, they should be used. His point was that salts are not enough, you need to couple them with a possibly slowest, yet acceptable hash function. And then hope that Moore's law does not breach your passwords.
- MichaelGG 12y agoYes. But he's also pointing out tons of the advice given, perhaps by people that are well-known and respected-by-some, is just wrong. Iterative hashing with per-user salts has been a known pattern. Practical Cryptography covered it in the first edition. The relevant parts should be derivable for most engineers. There's no reason there should be any confusion or crazy blog posts.
- mdavidn 12y agoSalt has one other important property: Salt makes grouping users by password more difficult. Some subset of your users will inevitably use the same terrible password as another user. Or one user will create multiple accounts using the same strong password. These passwords should appear unique in storage. You still need salt, and that salt must be unique for each password. That's the peril of PBKDF2 password storage: I've seen applications completely botch salting by using one for all users. Bcrypt and scrypt avoid this common error by salting internally.
- shadowfiend 12y agoComputing the hash of a known password is trivial, though—once you know one user used Passw0rd$, it's easy to check every user for that password, even if you have a salt, because the salt is not hidden. So you're just running n password checks in the number of users—admittedly, this is still n checks, but the difficulty of that pales in comparison to brute forcing passwords, and while it's strictly slower than just checking “is anyone else using exactly this”, it's not that much slower in the larger scheme of breaking a set of passwords. At least that's my understanding... I am not a security expert! :)
- icebraining 12y agoChecking every user for a specific password is equivalent to a dictionary attack, using a single word. In fact, commonly found passwords from previous leaks are usually incorporated in such dictionaries.
- nathanaldensr 12y agoI think this is why one is supposed to use random salts per password. That way, you can't use the successfully-guessed password's hash to assume other passwords with the same hash represent the same clear-text password.
- mdavidn 12y agoThat's a fair point, but an unsalted hash gives an adversary information before they brute force any password. In the "user with multiple accounts but one strong password" scenario, for instance, grouping by password would highlight which users are inclined to use the same strong password with multiple accounts, perhaps on other web sites. Multiple accounts would give an adversary more identifiers to use when cross-referencing other leaked databases or the web.
- hueving 12y agoThis is missing something pretty important about salts. They hide the fact that two users have the same password. That's a huge security risk if that correlation is leaked. Correct me if this is mentioned in the article, but based on several mentions of how salts were effectively useless, I think this was overlooked.
- homulilly 12y agoI didn't get the impression the author was saying salts are useless, obviously you still have to use them and bcrypt and scrypt both do. The point is that a lot of programmers naively assume that a salt (or salt+pepper) will make their password storage secure on its own when that isn't really true anymore.
- moxie 12y agoIt's easy to say "use bcrypt" or "use scrypt," but I think it's important to acknowledge the challenges of deploying those functions in large scale high performance environments. It's straightforward and effective when password hashing happens client-side (like local encryption for a bitcoin wallet), but using scrypt or bcrypt server-side at effective difficulty levels will either destroy your L1/L2 cache or exceed your CPU budget. In practice, from what I've seen, this means scrypt is never used, and bcrypt is used with a work factor that's tuned low. I think this is just a fundamental asymmetry, and that at the end of the day people use bcrypt so that they can say "we used bcrypt!" and get a nod when their entire user database is compromised, even though it provides very little value the way it's deployed.
- djb_hackernews 12y agoWhat is authenticating millions of users per second? Facebook has 900M monthly users, 30M per day and probably most of those are cookied in. Even if not that's only 350 authentications/sec...
- proksoup 12y agoMaybe each request needs to be authenticated?
- stanmancan 12y agoIf you're authenticating with a username and password on every request you're doing something wrong. Once a user is logged in you should be setting a cookie, session, or some other token to identify the user.
- ryan-c 12y agoI believe HTTP basic auth checks the username and password on every request. It's pretty rarely used these days though.
- 12y ago
- djb_hackernews 12y agoI'd be interested to hear more about the approaches a hacker would take in each case if they came across the hashed passwords and have no knowledge of the salts, etc. For instance in the first case where hash = md5('deliciously-salty-' + password) I'm not sure how easy it is for an attacker to reverse the hash if they don't know the salt. (I understand you need to assume the attacker has the salt, but just posing a constrained hypothetical here)
- icebraining 12y agoIt's equivalent of attacking md5('deliciously-salty-'), since the password can be known, e.g., by using the hash from their own account. Attacking md5 is not really that hard, nowadays - the article mentions 180 billion tries/second. Yes, it requires a rig with 25 GPUs, but this is almost the perfect use for the "cloud" - you can rent those for a few bucks just for a specific attack. There are even dedicated services nowadays, with no programming knowledge required - you just submit the hashes, and out come the found passwords.
- djb_hackernews 12y agoHmm I still don't understand, but thanks for replying to my (downvoted) honest question. If all you have is a hash and know the password you still dont know if it's md5sum('salt:' + password) or md5sum(password + '-salt') or md5sum('salt+' + password + '=salt') etc I suppose you'd need to brute force a large key space and look for any results which contain your known password. Does that sound right?
- nathanaldensr 12y agoThat's true, but once you discover the salt pattern used, then you can crack a specific password and look for the resultant hash in the database. The idea is to use a random salt per password to close this attack vector. That way, even if you do guess the password and you have the salt, the resultant hash is only useful for that one password, even if the same clear-text password is used in other hashes. Think about it: adding a known global salt to each password in the same manner before hashing is effectively the same (in the long run) as not salting. Once the attacker figures out the pattern you used, he can proceed to crack specific passwords, then search for the resultant hashes in the database.
- danbruc 12y agoThere is one thing that I think is often omitted. A lot of user use trivial passwords and they reuse them. These users' passwords will fall essentially no matter what you do because making the check so slow that a dictionary attack with a couple thousand very common passwords becomes impractical is itself borderline impractical. On the other hand strong passwords will withstand an attack even if they are hashed with plain MD5 or SHA1 - at least right now, there are already some serious collision attacks. The user group really benefiting from strong password hashing schemes is the one between the two mentioned extremes. So if you really want to protect all your users and use simple password authentication you have to enforce strong passwords policies which is itself not trivial and will definitely badly annoy some users.
- jjarmoc 12y ago> There is one thing that I think is often omitted. A lot of user use trivial passwords and they reuse them. These users' passwords will fall essentially no matter what you do because making the check so slow that a dictionary attack with a couple thousand very common passwords becomes impractical is itself borderline impractical. Sure. This is something I touched on very briefly near the end of the post. Password re-use is a huge problem and could easily be an blogpost of its own. > On the other hand strong passwords will withstand an attack even if they are hashed with plain MD5 or SHA1 - at least right now, there are already some serious collision attacks. For some value of 'strong' sure. If you're password is long enough, random enough, and of a broad character set then yes, an md5() of that may well be beyond the reach of most attackers. But that's not the sort of password most people, even security conscious people, choose. A preimage against MD5 would quickly change this too, and that's a risky gamble. > The user group really benefiting from strong password hashing schemes is the one between the two mentioned extremes. The best we can do is make attacker costs a function of the password that the user has chosen. If someone makes their password 'password' there's no degree of magic that's going to help. Mostly, the benefit comes if/when disclosure occurs and there's an active incident response effort. > So if you really want to protect all your users and use simple password authentication you have to enforce strong passwords policies which is itself not trivial and will definitely badly annoy some users. It's not a zero sum game. When a breach occurs, the rough points in time are something like: 1) Attacker compromises digests (let's just assume all are obtained in an instant, rather than exfiltrated over time) 2) Attacker recovers 1 password 3) Attacker recovers n passwords 4) Attacker recovers all passwords Our goal isn't to eliminate these steps except hopefully the extreme of 4. Rather, it's to increase the time between 2 and 4, and make sure 3 is closer to 2 than 4. On the other side of the coin, there's a few points in time: a) Victim org. realizes digests have been compromised. b) Some credentials valid at 1 are made invalid. c) All credentials valid at 1 are made invalid. If you accept my previous point that at some extreme there's nothing that can be done to prevent brute force, then you should also see that storing passwords in this fashion isn't meant to be a perfect defense. By minimizing the number of compromised accounts at a given point in time, we can maximize the benefits of our response. We can notify users and force resets, invalidating some set of credentials before they're recovered. We want b and c to be closer in time to 2 than 4, and minimize the value of n when we get there.
- kpcyrd 12y agoPassword hashing is crypto, too. Don't roll your own crypto.
- sarciszewski 12y agoI agree with this advice, even though I'm probably the worst offender. I have: - Rolled my own password library (linked elsewhere in this thread) - Rewritten an existing AES-CBC + HMAC-SHA-256 library to use a different underlying driver (mcrypt is basically a mummy at this point) - Did both of these things in PHP, which a lot of people assume is inherently incompatible with security However, everything I've done in this vein has been passed before people who are far smarter than myself, to which I received no complaints. And I constantly seek out criticism from people who understand crypto too. (Aside: Most crypto people are dicks. But they mean well.)
- ZoFreX 12y agoOne question: _Why?_ However many people have reviewed your code, far more people have reviewed libraries like bcrypt!
- sarciszewski 12y agoMy code uses bcrypt. It's a wrapper around password_hash() and it also passes it through an authenticated encryption library. When I said I wrote my own crypto code, I don't mean like something that belonged in a PHC entry.
- ryan-c 12y agoThis article says salting hashes is only useful against rainbow tables. That does not make sense to me. Say you have a password database with 10,000 users in it. You want to see if any of them used "Passw0rd$". Without salt, you compute the hash once and check it against all the users (perhaps with a bloom filter). With per-user salts, you have to compute the hash for each user. I think salting offers pretty clear benefits against other attacks if you have more than one user. Edit: The point I'm trying to make here is that it is N_USERS times better to have a unique salt per user, regardless of the hash. One should use bcrypt/scrypt/pbkdf2 with unique per-user salts.
- icebraining 12y agoA single hash per user is not any significant protection. As the article pointed out, the rig could compute 71000 bcrypt hashes per second, so even if you had 1M users, that would take less than 30s/password.
- maxerickson 12y agoThat calculation can't be done without knowing the bcrypt costs used to benchmark the rig and on the unknown password (I was pondering a similar calculation on another story and the only thing I found was a brief statement that pw crackers report performance for cost=5 (just by habit/convention).)
- icebraining 12y agoFair enough, and it seems the same cost was used in this case! http://passwords12.at.ifi.uio.no/Jeremi_Gosney_Password_Cracking_HPC_Passwords12.pdf http://passwords12.at.ifi.uio.no/Jeremi_Gosney_Password_Crac...
- kasey_junk 12y agoThe salt is typically assumed to not be secret. With modern hardware recalculating the hash is not hard for "fast" hashes, regardless of salting. That's why choosing a slow hash is more important for this vector of attack than anything else. Of course salting is better than no salting, but its orders of magnitude less important than choosing a good hashing mechanism. Luckily, the good hashing mechanisms do the salting for you so fixating on salting really just serves as a proxy for letting us know that you don't understand the attack vector.
- tootie 12y agoI fail to understand why salting is bad. Seems like he's saying it's not a cureall. We knew that. But it's at least marginally better than not salting and it's easy, so why the hell not?
- amouat 12y agoYeah, salting definitely isn't bad, in fact it's actually essential. What the author is saying is that it's not enough - salting won't save you when your attacker can test 10s or 100s of thousands of hashes a sec. The article could have been phrased better.
- dickfickling 12y agoWhat he's saying is that a salt should be a no-brainer. FTA: "Storing passwords as unsalted hashes is a grievous mistake of course, and breaches disclosing poorly stored passwords are still too common." He's simply saying that a salt isn't enough to keep your passwords secure - you should also be using a slow hashing / memory intensive hashing function.
- masklinn 12y agoNobody's saying salting is bad, the blog is saying that salting is a given, if it's not you don't belong anywhere near passwords.
- femto113 12y ago> I see the mantra ‘salt your password hashes!’ > repeated over and over, when its only real > value is against rainbow tables This is dangerously incomplete reasoning. Salts real value is that if multiple password hashes are Leaked simultaneously then each must be cracked individually. In the Adobe leak password hints were included, which allowed for very easy guessing of passwords, and because there were no salts even if you had no hint if someone else had the same password and an obvious hint you were cracked.
- worklogin 12y agoI was about to make the same post. If a database is popped and people know John123's password, and his hash is the same as Worklogin456's hash, then they know my password.
- nopar8 12y agoI am extremely ignorant about this topic. But I don't think that's how it works. Can someone else weigh in please.
- cheapsteak 12y agounsalted: username | sha256 hash john123 | ef92b778bafe771e89245b89ecbc08a44a4e166c06659911881f383d4473e94f joe456 | ef92b778bafe771e89245b89ecbc08a44a4e166c06659911881f383d4473e94f salted: username | salt | sha256 hash john123 | ponies | 98d4c01710b2b775e41b0bf4984f0cec7621ae1dfc4304047b196af46ed589b2 joe456 | beards | 0f7c74279db5daa1f4de41cc7f6acc94651da754c41675dcde8dcf151d14f5bf their passwords are all `password123`
- elchief 12y agoSince the author didn't bother to mention any threat models, we can assume that the threat is the most common one, SQL Injection. You don't need SQL Injection if you can directly read the database file, or can operate as the web server user, therefore if you're doing SQL Injection you don't have those privileges. If you can HMAC or encrypt passwords (prior to hashing them) in the database with a key only on the web server, then that's an extra level of protection. You can't get that key with SQL Injection alone. https://blog.mozilla.org/webdev/2012/06/08/lets-talk-about-password-storage/ https://blog.mozilla.org/webdev/2012/06/08/lets-talk-about-p... password_hash(base64_encode(hash_hmac("sha512", $password, $key, true)), PASSWORD_BCRYPT)
- ajanuary 12y ago> we can assume that the threat is the most common one No we can't.
- DenisM 12y agoIf you are using .NET, you will be glad to know that .NET framework has a standard implementation of PBKDF2, one of the recommended choices in the article. var hash = new System.Security.Cryptography.Rfc2898DeriveBytes(password, salt, workfactor).GetBytes(32); Using a NIST-approved function that's continuously supported by a large player seems like a good choice.
- jameshart 12y agoThe implementation iterates HMACSHA1, which is fine, of course, but which raised concerns on at least one audit I went through because, well, why would anybody want to use SHA1 when SHA2 exists? Wound up having to implement my own version of PBKDF2 that lets you specify the HMAC algorithm.
- k__ 12y agoDoes this mean we should drop the salts, simply scrypt and be done with it? Or should we still include salts in addition to scrypt? If yes, only one global or many user specific or both?
- btilly 12y agoThe need for unique passwords brings me to a stupid idea that I've had for a while. Imagine a service which just stores hashes of every password that it can find from everywhere. Any site that wants can check whether a given password is in use..somewhere..and reject it if it is. Any site that wants can add more passwords to the list. Internally the service would work from a bloom table designed for a fixed false positive rate. (You can actually layer bloom tables in front of bloom tables with parameters to make this possible.) So even if someone compromises that site, there is no direct record of the actual hashes for passwords. Basically let sites say, "You have to choose a unique password, and do not reuse a password that anyone has used elsewhere!"
- sarciszewski 12y agoThis would only work if you could achieve this search with the use of a zero-knowledge proof. Actually disclosing your password to the service would defeat the point.
- btilly 12y agoYes, this is a weakness. The password would need to be disclosed in the form of a hash of the password, and the hash algorithm has to match what everyone else does. If the service and your site were both compromised, then it would be possible to match up incoming hashed passwords to users by timestamp. But even so, the fact that no passwords were reused will hopefully make cracking the hashes harder. So..probably a bad idea. :-(
- wffurr 12y agoLastpass has a password-auditing feature that checks your passwords against a list of known-leaked common passwords.
- jacquesm 12y agoCompromises are not points in time, they tend to be intervals. A long enough interval could do more harm than good here.
- throwaway832975 12y ago
- noinsight 12y agoIt's not just the scheme that's important, it's also the implementation of it that's important. If I'm doing the smart thing and not rolling my own crypto, can I trust the existing implementation that I've chosen? It's hard to say. Does it have secure defaults or do I need to choose and why do I need to choose, why aren't the defaults secure? I'm not a crypto expert, I'm not qualified to judge and therefore I don't even care (as such) - why aren't the defaults secure? For example, I'm writing an app that requires a password setup in Python so I was investigating this issue: 1. Passlib - https://pythonhosted.org/passlib/ https://pythonhosted.org/passlib/ - "implementations of over 30 password hashing algorithms" - What? I'm not qualified to judge what's secure so I don't even care, I just want something secure! 2. python bcrypt - https://pypi.python.org/pypi/bcrypt/1.0.1 https://pypi.python.org/pypi/bcrypt/1.0.1 - OK standard bcrypt, supposedly that's secure - "Author: Donald Stufft" - who is Donald Stufft? Is the code good? I don't know C and I'm not qualified to judge! 3. python scrypt - https://pypi.python.org/pypi/scrypt/ https://pypi.python.org/pypi/scrypt/ - OK it's Colin Percival's code, it's probably good, "Author: Magnus Hallin" - did Magnus Hallin screw it up though? "Burstaholic on Bitbucket provided the necessary changes to make the library build on Windows." Eh. Did "Burstaholic" ruin the crypto? Who knows. Also, in my case I needed something cross-platform, primarily for Windows. bcrypt worked out of the box. The scrypt library required building on Windows with OpenSSL development headers or whatever and all that - I just said "pass". Nacl is fantastic and simple to use, it can't get much easier than this: https://libnacl.readthedocs.org/en/latest/topics/public.html https://libnacl.readthedocs.org/en/latest/topics/public.html Something similar should exist for passwords - I just want to call compare(password, storedhash) or whatever and be done with it, I'm not qualified to judge the crypto. And it should be cross-platform.
- im3w1l 12y agoThis is why I love the (modern) php approach. It's in the standard library and you don't need to supply an algorithm name or salt or anything. It is also designed so that a future version of php can have upgraded algorithms without breaking current code. It is trivially easy to write code that upgrades old hashes when the user logins in. http://php.net/manual/en/function.password-needs-rehash.php http://php.net/manual/en/function.password-needs-rehash.php
- borski 12y agoJeff's and Thomas' posts are totally on the money. We wrote a piece as well, specifically to talk about how encryption and hashing are not the same thing. You'd be surprised how often people screw that up. https://www.tinfoilsecurity.com/blog/store-data-securely-encryption-hashing-how-to-guide https://www.tinfoilsecurity.com/blog/store-data-securely-enc...
- biot 12y agoThe points made here are covered in Coda Hale's post: http://codahale.com/how-to-safely-store-a-password/ http://codahale.com/how-to-safely-store-a-password/ While it recommends using bcrypt, if you augment that with "or scrypt or PBKDF2" the same principles apply.
- pstrateman 12y ago"The value of salts is limited to thwarting attacks leveraged pre calculated lookup tables such as rainbow tables." This is absolute drivel. Salts prevent checking an attempt against all the hashes in parallel. That is to say if the attacker has a dump of 1 million salted hashes, they have 1 million times the work to do compared to 1 million unsalted hashes.
- deleted 12y ago[deleted]
- unreal37 12y agoI am also suspicious of the claim that a fixed salt+password hash scheme is "just as insecure" as a no-salt password hash scheme. The salt (unknown to the attacker) has to add at least a few order of magnitudes more security just by turning "password123" into "somesalt65634734password123" right? Just from the added password length alone it has to be "way more" secure, right? Would love some professional crypto opinion on this.
- MertsA 12y agoIf it's fixed it is limited to just preventing rainbow tables from being used in practice. If they have a copy of your database already ex-filtrated, there's a pretty good chance that they also have access to "somesalt65634734" so while the attacker certainly isn't going to be able to find a rainbow table with every password prefixed with "somesalt65634734" they certainly won't just check every combination of a 32 character password, they'll just check passwords 8 characters or less starting with "somesalt65634734" and if it's unique across your whole site and your site has N users then they just sped up their password cracking with a factor of N. If N = 1000000 and it's just SHA("somesalt65634734" + password) then the attacker is just about guaranteed to be rolling in tons of cracked passwords in no time. Whereas with bcrypt or a unique salt per password you don't get that massive speedup by a factor of N.
- pstrateman 12y agoStrictly speaking... it depends. Lets assume the hash function being used is SHA2-256. The input block size there is 512 bits (64 bytes). So if adding the salt pushes the total length of the hash input past 512 bits then it doubles the runtime. I do not see any particular advantage there over simply running the hash function twice.
- kyberias 12y agoUrghh... I hate these articles that list bad examples of salt use and then doesn't explain the reasoning why exactly these are bad. Just trying to prove to the world how smart the author is. Maybe he doesn't really know how to explain it?
- codahale 12y agoUse bcry—ah, fuck it.
- seanwilson 12y agoHow about using a tested login library instead and consider using OAuth as well (e.g. Google account to login)? Rolling your own login system, dealing with hash functions and checking passwords yourself is far too low level and dangerous for most apps (as this thread demonstrates).
- zobzu 12y agowhile we're at it and throwing stuff around as if its an easy fix: lets stop using passwords. Use keys. Use a trust model on these keys. So many advantages.. you don't receive the cleartext password no more (because really I DONT CARE if you use triplezscrypt.. SINCE YOU GET MY PASSWORD IN CLEAR TEXT during authentication.. its not like if compromises were "on the database". Its always at the application level.) Beside it makes rotation easier, and not having to remember multiple passwords, or having a password manager, etc. a thing. Oh wait ;) Google and others are actually attempting to make this work with U2F: https://support.google.com/accounts/answer/6103523?hl=en https://support.google.com/accounts/answer/6103523?hl=en (yes it works with gmail. Right. Now.) https://www.yubico.com/applications/fido/ https://www.yubico.com/applications/fido/
- ghshephard 12y agoAnd, as always - these discussions about Salts/bcrypt/scrypt are only relevant to people where passwords/security are important, but not critical. For anybody who has critical security needs, just use an HSM already. Sophos/Utimaco makes a nice one, and it is a nice foundation for password security.
- Sami_Lehtinen 12y agoHow about not reusing passwords and always using a strong password? SHA256 alone is enough, when you just do that. And so what if someone got my password. If they had already access to the system, they could have also stolen the data they were after anyway. Today's password: .P`éA@O?/^2HNVSé%@ÖY it contains more than 256 bits of entropy. Based on this SHA256 collision attacks and cracking AES128 should be trivial. I personally consider passwords to be unique shared secret blobs / service.
- slasaus 12y agoI've recently found out about Diceware and the importance of a strong password [1][2]. Often users choose a really weak password to begin with. I've read [3] that if you have a strong password (like a 7 word Diceware password) even MD4 or MD5 would suffice :O. I'm really curious if this is true. [1] http://world.std.com/~reinhold/diceware.html http://world.std.com/~reinhold/diceware.html [2] https://firstlook.org/theintercept/2015/03/26/passphrases-can-memorize-attackers-cant-guess/ https://firstlook.org/theintercept/2015/03/26/passphrases-ca... [3] https://github.com/freedomofpress/securedrop/issues/180#issuecomment-29760395 https://github.com/freedomofpress/securedrop/issues/180#issu... ps. for those that use bcrypt and want to ensure a constant user experience on their server see https://www.npmjs.com/package/bcrypt-speed https://www.npmjs.com/package/bcrypt-speed
- xai3luGi 12y agoWhy are we still using passwords in 2015?