Hacker News new | past | comments | ask | show | jobs | submit login
Salted Password Hashing – Doing It Right (crackstation.net)
22 points by pmoriarty on Dec 23, 2014 | hide | past | favorite | 91 comments



Obligatory link to "How to safely store a password".

http://codahale.com/how-to-safely-store-a-password/


If you're simply trying to solve the problem of storing passwords, Coda's article is better than this one.


Yeah. I think defuse wrote that page 3-4 years ago and hasn't really maintained it since then.

For PHP Devs, these are the two best options available:

* https://github.com/ircmaxell/password_compat

* https://github.com/DomBlack/php-scrypt


Quoted:

"In step 4, never tell the user if it was the username or password they got wrong. Always display a generic message like "Invalid username or password." This prevents attackers from enumerating valid usernames without knowing their passwords. "

Completely, utterly wrong. It 'looks' secure. We're not telling the user if it's a login or password.

But if you try to create an account with the username, it tells you "CANNOT CREATE, USER ALREADY EXISTS".

So, it's an anti-pattern that serves to confuse the user but fails to stop a scripted attack.


They are correct, it is important to show a generic message on the login. The login is the first place an attacker will look for user enumeration. Just because you may be able to find user enumeration somewhere else doesn't mean you should leave it open everywhere.

For user enumeration on registration you have two choices:

1. Provide a unique registration link to an email for signup. The prospective user goes to the registration page, submits and email, checks their email, then follows the link to a registration page. On this page it's easy to see if someone is enumerating usernames, and every request contains the token from their unique signup link so the token can be invalidated quickly.

2. Provide a slow rate limited lookup to verify an existing username, every 2-3 seconds, which shouldn't negatively affect users as they signup because they have to fill out a registration form in the mean time. This will however greatly slow down a bot.


That still goes back to user interface implementation.

You can have a website that tells you "Bad password", and the user knows what it is. They fix it, on they go.

If there's a bad actor, it says "bad password". Same warning. Now, you slow down the response so that after 5-10 times, the website gets dog-slow. It's still useful if you're a legitimate user.

And if someone is script-attacking you, they're going to get an enumeration of your usernames by using a different script. Or they'll dump the username:passwd database if they get in. In that case, obfuscating usernames is moot anyways.

It's security through obscurity, and it's not that obscure. And it's bad UI.


It's defense in depth. Why tell a probable attacker that they have the correct username if you can hide it from them. The less you give them the better. Most users will know if they got their username incorrect, it's right there in front of them on the screen.

The slowed down responses (exponential back-off) is a the preferred method of rate limiting over account lockout.

"Or they'll dump the username:passwd database if they get in. In that case, obfuscating usernames is moot anyways."

Well if they can dump your DB it's game over for your whole app and possibly infrastructure anyways.


> Just because you may be able to find user enumeration somewhere else doesn't mean you should leave it open everywhere.

Why not? Rather than parroting conventional wisdom, how about making a cost/benefit case?

We're pitting a significant UX benefit against a tiny marginal security benefit.

Unless you're demanding a higher level security across the entire service, in which case you don't want user enumeration anywhere, then the correct answer to implement throttling on anything that would make the usernames discoverable. That's more flexible solution that does not conflict with good UX.


I don't think it is a significant UX benefit to reveal to a user that their username is correct but their password is incorrect. How many times has an incorrect username been what's blocking you from logging into an application? Just look at the username you entered right there in front of you. Is it correct? No? Then enter the correct one. The hangup during login most of the time is people fat fingering or forgetting their password. Telling them that their password is incorrect isn't going to help, they will assume that and re-type their password again anyways.

I agree, implement throttling anywhere you have authentication or registration, that's a good idea to have in place in any case. I'm not arguing that.

It seems there is always the problem of balancing security, performance, and usability. You just have to decide which is more important when examining features. I this case I would advocate security. The decision you make with your applications is up to you, but it's important to understand you are making a tradeoff.


All the fucking time. Everything I signed up for when I used gmail uses my gmail address; everything after a different address. Guessing one then the other then the first again is like plugging in a USB adapter in the dark.


To be honest: every now and then.

Old (forum, ...) accounts, >5 years of inactivity. What e-mail did I use for this again? I end up just typing every e-mail address I can remember in the reset password field because it's faster than the combinatorially exhaustive search with the three / four probable passwords from way back when.

EDIT: My main objection is that taking computer literate people as the litmus users is a UX anti-pattern. We talk a lot, but we easily forget just how much hand-holding, clarity and patience a large (and silent) chunk of our users need.


No, it's not wrong – you're conflating this with another issue.

User enumeration attacks are real and bad. A better solution to that would be to not leak this information when trying to create an account, instead. Since most sign-up processes seem to require email confirmation anyway, nothing is really lost there.

Of course, if you don't require email confirmation, then go right ahead – you'll have to use other approaches to avoid enumeration (like rate limits), but then you should be doing that anyway.


First mistake is to let user to select arbitrary username os password. Just provide them with secure ones, that's what I do. I always have wondered also the fact, what's the point of having separate username and passworld fields in the first place. Username: bjdndgEC2S4rHRZy7c8rdQ Password: 6TWe8EvxfRxxCvcyZTaBM6 Isn't it enough to concatenate username and password, it's just as secure to use one field instead of two. Btw. Do many of these services pay enough attention to potential weaknesses presented by the potentially weak(er) session cookies?


Link to one of these services? I'd love to see this in action for myself.


But if you try to create an account with the username, it tells you "CANNOT CREATE, USER ALREADY EXISTS".

Then don't do it, give a generic error message and send an email to the accounts email address saying "Did you try to sign-up, you already have an account, here is the reset link in case you forgot the password"


Sending an email to the registered account is not a solution, because that doesn't tell the registering user that the username is unavailable.


If a username isn't obtainable, it would be fair to assume the username is in use.

I know of no situations that seed "unobtainable usernames" in a DB. Although now, I would expect that.


I was just about to post this.


This page is old. Nowadays, PHP developers are encouraged to use password_hash() and password_verify().

But if you want PBKDF2, defuse's github has more up-to-date code that, IIRC, he hasn't taken the time to copy/paste into the page linked.

https://github.com/defuse/password-hashing


If you want PBKDF2 and are using PHP >= 5.5, there's the hash_pbkdf2 function built in to ext/hash, which should be available by default in most installations.

There's also another implementation in PHP-CryptLib by Anthony Ferrara, the gentlemen that brought the current password API to PHP. https://github.com/ircmaxell/PHP-CryptLib


The PBKDF2 code that defuse wrote will use hash_pbkdf2() if it's available. :)


If you’re using PHP 5.5+, this should be all you need to securely save passwords:

  $sHash = password_hash('ThePassword', PASSWORD_BCRYPT, ['cost' => 12]);
Checking is as easily as:

  if (password_verify('ThePassword', $sHash)) {…}
Or do you guys have other thoughts?


base64 encode the password, reverse the encoded result.


What security advantage would that yield?


http://cryptofails.com -- I believe they're referring to 46ESAB the worst password hashing algorithm ever


That’s hilarious! :D


If you're using Rails (or ActiveRecord/ActiveModel specifically), you should probably skip the suggested Ruby example and just use has_secure_password. It's built in, uses bcrypt, and greatly reduces the likelihood of making mistakes in a custom implementation.


Overall, the article is solid. It is only missing key stretching with fast cryptographic hashing algorithms like SHA-1 or SHA-2. Instead, it jumps right into PBKDF2 and bcrypt.

That's fine, but it's not the full story, and as such, does a disservice for those wanting to know about securely storing passwords on disk. PBKDF2 and bcrypt can be a performance killer for authentication applications, if the host is a busy host. Instead, changing the number of rotations on a fast hashing algorithm gives you finer granularity on brute force speed versus application and host reliability.


Many of the largest, busiest applications in the world authenticate passwords with bcrypt. Misplaced concern about its performance implications are as approximately as old as the algorithm itself.

Hardware slices through iterations of fast hash functions --- functions that are designed to be quickly executed on hardware --- like a red-hot knife through warm butter. Developers who think they're getting "fine-grained control" over brute force speed by tinkering with SHA2 are deluding themselves. PBKDF2 is not simply the repeated application of SHA2.

Don't use fast hashes for passwords. Don't design constructions that use fast hashes for passwords. That work has been done for you already: use scrypt, instead of an underspecified, half-functional, and insecure homebrew approximation of scrypt.


Software library support for bcrypt and scrypt is still light (although there is admittedly more support for the former than the latter). Which would could cause you to roll your own in-house solution. This is less optimal. There is ubiquitous library support for key stretching with fast hashes.


Name a single widespread environment for which no secure password hash is available.


MySQL for bcrypt and/or scrypt.


Plenty of applications built on MySQL use bcrypt. For example: see virtually every Rails app.


CREATE USER 'tptacek'@'db.example.com' IDENTIFIED BY 'su3rl337P@$sw0rd';

Let me know when MySQL supports bcrypt/scrypt.


I don't see how this is even relevant. What do MySQL's limitations have to do with your decision to store a password hash? Are you writing your entire application in MySQL?


I'm curious - is that a common practice with backend applications - writing only with MySql application code and not using anything else like Java/PHP/Python/C# etc?

I know Oracle has pretty sophisticated stored procedures, but even so, most of the application logic of systems I've seen had program code written in an "external" language.


In 10 years of consulting with a large team for companies big and small I saw a total of none applications built this way.


See comment downthread about "competence".


Really? I'm pretty sure that there's near-ubiquitous support for bcrypt for any language or framework, no?


> It is only missing key stretching with fast cryptographic hashing algorithms like SHA-1 or SHA-2. Instead, it jumps right into PBKDF2 and bcrypt.

Key stretching with SHA-1 or SHA-2 is hard to do right, and if you do it right, you've reached a solution that is basically equivalent to PBKDF2 or bcrypt. If you're interested in how PBKDF2 or bcrypt are implemented, that's one thing, but if you're rolling your own password stretching on top of SHA-1 or SHA-2, you're probably not doing it correctly and performing [security theater](http://en.wikipedia.org/wiki/Security_theater).

> PBKDF2 and bcrypt can be a performance killer for authentication applications, if the host is a busy host. Instead, changing the number of rotations on a fast hashing algorithm gives you finer granularity on brute force speed versus application and host reliability.

This is already provided by PBKDF2 and bcrypt. Both can be configured to run more or fewer rounds.


The whole point of bcrypt is to be slow. You can set the number of rounds to fine-tune that too, and can even do it on a user by user basis since the number of rounds and version is stored within the hash output.


Of course bcrypt is supposed to be slow. However, the "fastest" bcrypt can operate, might be a local DDoS for your sever, if the authentication app is a busy one. Key stretching cryptographic hashing algorithms gives you more granular control in that regard.


So does every database lookup every application does. The solution to that problem is rate limiting, not (weird that I have to say this) weakening your password authenticators!


Security margins here (IE: bcrypt versus SHA-2) are estimated with entropy, which is also completely missing in the article. A weak password is a weak password, bcrypt or not. If there is sufficient entropy behind the password, 500,000 rotations of SHA-512 is not "weaker" than bcrypt, Only faster. You should know this (weird that I had to say that).


Speeding up your password hash mechanism makes it weaker. The faster your password hash system, the more quickly your password list can be broken.

This is probably the best commentary I've seen on the topic of how many rounds you should incorporate into your KDF (Scrypt/Bcrypt/PBKDF2 all let you dial as many as you wish), so I won't try and improve on it: http://security.stackexchange.com/a/3993


You're overlooking the entropy behind the hash though. If entropy is sufficient for creating the password (120-bits or so), no matter of brute force speed will recover the text that created the hash. You'll instead need to break the hashing algorithm itself. The math is against you.


If you have 120 bits of entropy, then a single round of unsalted SHA-2 is sufficient.

If you have typical users, with typical user passwords, then take a few minutes to read through: http://security.stackexchange.com/a/3993 (it discusses the importance of taking into account entropy) to determine what work factor is appropriate for your situation, then just deploy one of scrypt/bcrypt/PBKDF2 with that work factor.


Yes. The basic job of a password hash is to improve the security of low-entropy secrets.

The argument here seems to be that if people simply don't use passwords, but instead secure AES keys, password hashes won't matter. Ok, but we're talking about passwords, and so was he, upthread.


> If there is sufficient entropy behind the password, 500,000 rotations of SHA-512 is not "weaker" than bcrypt, Only faster.

Given that the strength of security is measured in how long it takes to break it, and hash time is directly correlated with brute force time, for the same password, faster is weaker.

Having high-entropy passwords certainly increases security, but it's a well-known fact that users don't use high-entropy passwords, so that's pointless to talk about.


If you server cannot hash incoming authentication attempts properly with bcrypt or scrypt, then the solution is to upgrade the server, not weaken your authentication to compensate.


Are you offering to upgrade my hardware infrastructure for me?


I assess the vulnerability of applications for a living and I have been told over and over again by dev groups and ops that they can't upgrade their systems because it is too expensive. That's fine, but you need to understand you are making a security for money tradeoff and realize the risks you are bringing on in doing so. Make your own cost benefit analysis, but know that you are making a tradeoff and what that entails.

This is a solved problem: use 10,000+ rounds of PBKDF2, 4-5+ rounds of Bcrypt, or a sufficient work factor for Scrypt.


I work for a local ISP that does shared web, email, and database hosting, among other things. I am one of the core system administrators. I am deeply familiar with hardware performance as it relates to software libraries, authentication, and busy systems. Feel free to wave a hand, ignoring the issue. But the fact remains that bcrypt can be a performance killer on busy systems.


No, it isn't, not on competently designed systems. But I freely concede that incompetence can make intractable problems out of all sorts of basic challenges.


So lack of deep financial pockets means incompetently designed systems? If a busy system can't handle bcrypt, it's incompetently designed?


No. Yes.


It is a mystery to me how you would design a web application that required bcrypt on every page reference. For session-based browser apps, you use a cookie (properly secured) to note the session.

For applications requiring basic auth, you could cache the username/password combination after the first login.

For bcrypt to be a killer on modern systems, you are botching something in your authentication system.


I am not ignoring the issue, I am advocating the more secure system configuration. I know that it is expensive, and it can introduce additional performance requirements. When choosing to implement proper password hashing or not there is a tradeoff. That is a decision that needs to be made on a case by case basis.

None of that changes the fact that the _more secure_ thing to do is implement bcrypt/scrpt/PBKDF2. I bet there are plenty of people at Sony, Target, Adobe, Home Depot, Staples, etc. that wished they had taken the more secure route and spent that extra money.


Fast cryptographic hashes like SHA-1/2 are heavily discouraged for password storage (even with a salt). As they are very easy to implement in parallel.

Yes salting prevents as effective brute forcing. Yet modern computing 8 char passwords + salt can be exhausted within 24-48 hours (on a <$20k GPU cluster) if you using SHA-1/2 + salt.

bcrypt/scrypt/PBKDF2 are much harder to brute force (by design) and circumvent this weakness.


Tangent:

Salts do zero to mitigate brute-force attacks.

Salts defend against one idiosyncratic lookup-table attack that was briefly popular in the early 2000s because of a widely-deployed password hash function that, unlike every password hash since the mid-1970s, didn't randomize. This is the attack to which "rainbow tables" are applied.

If you're considering rainbow tables as part of your threat model, you're already so boned that you should give up and just use a real password hash. If you're not considering rainbow tables, you don't have to consider salts.

The only good thing about "strong salts" is that they function as a kind of shibboleth so you can tell if people understand what problems they're contending with when storing passwords.


> "every password hash since the mid-1970s"

Back then systems used no password at all or stored it in plain text.

In the mid-1970s the NSA just finished DES.

Password shadowing first appeared in UNIX systems with the development of System V Release 3.2 in 1988 - see: http://en.wikipedia.org/wiki/Passwd#History

> "briefly popular in the early 2000s"

Til the dot-com-bubble timeframe many websites stored plain text passwords in databases, later they shifted to SHA1/MD5 hashed passwords without salt.

Only with the Sony hacks a few years ago, many added some kind of salting.


The original Unix crypt function was, IIRC, salted.

To head off an unproductive discussion, I'll just repeat:

* salts do zero to mitigate brute-force attacks

* even trivial salt schemes break table-based attacks

* the overwhelming majority of passwords are cracked through brute-force, which is attack vector that real-world password hashes need to be evaluated on.


Salts can mitigate brute-force attacks in the specific case that the salt is stored separately from the hash (and only one is leaked).


The job of a password hash is to strengthen weak secrets in compromised databases. Your suggestion defines the problem away: "never lose the whole database", it suggests, "and you don't have a problem".


Insofar as I have seen, the salt is stored right next to the hash, so how do you get one and not the other?


^ THIS!

If anyone wants to claim that salts do anything to stop brute-force attacks, take a sample of your passwords and run it through FL Cracker:

https://scott.arciszewski.me/public/FL-Cracker.txt


Page was timing out for me. Here's the google cache: http://webcache.googleusercontent.com/search?q=cache:S76Yg0P...


I like this article. If every developer read it. Significant part of any database would be useless for attackers.

Cudos to the author.



From the link:

    ITERATIONS = 600
    ...
    crypto.pbkdf2 pwd, salt, ITERATIONS, LEN, (err, hash) ->

That's way too small for the number of iterations. Something like 100K would be a better choice.

Alternatively here's a version that uses bcrypt:

    bcrypt = require 'bcrypt'
    rounds = Number(process.env.BCRYPT_ROUNDS || 12)

    module.exports =
      hash: (password, cb) ->
        bcrypt.hash password, rounds, cb

      compare: (password, hashedPassword, cb) ->
        bcrypt.compare password, hashedPassword, cb


From my testing 600 took about 15ms. 100k would take about 2.5 seconds.


For me 600 iterations takes about 3ms (I guess my laptop is a bit faster). A decent range to shoot for is .5-1 sec.

Test program:

    crypto = require 'crypto'

    password = 'testing'
    len = 128
    salt = crypto.randomBytes(len)

    iters = Number(process.argv[2] || 600)

    console.log 'Testing iters=%s', iters
    for i in [1..10]
      start = Date.now()
      crypto.pbkdf2Sync password, salt, iters, len
      elapsed = Date.now() - start
      console.log '   Test #%s - %s ms', i, elapsed
Output:

      $ coffee pbkdf2-test.coffee 100000
      Testing iters=100000
         Test #1 - 497 ms
         Test #2 - 510 ms
         Test #3 - 496 ms
         Test #4 - 525 ms
         Test #5 - 510 ms
         Test #6 - 493 ms
         Test #7 - 521 ms
         Test #8 - 518 ms
         Test #9 - 510 ms
         Test #10 - 498 ms

      $ coffee pbkdf2-test.coffee 10000
      Testing iters=10000
         Test #1 - 54 ms
         Test #2 - 50 ms
         Test #3 - 50 ms
         Test #4 - 55 ms
         Test #5 - 51 ms
         Test #6 - 52 ms
         Test #7 - 50 ms
         Test #8 - 49 ms
         Test #9 - 51 ms
         Test #10 - 50 ms

      $ coffee pbkdf2-test.coffee 600
      Testing iters=600
         Test #1 - 3 ms
         Test #2 - 3 ms
         Test #3 - 3 ms
         Test #4 - 3 ms
         Test #5 - 3 ms
         Test #6 - 4 ms
         Test #7 - 3 ms
         Test #8 - 4 ms
         Test #9 - 3 ms
         Test #10 - 3 ms


Nice, I was actually testing on my server hardware which is obviously lower end. This is hopefully useful for people though.

For me 1 second seems pretty aggressive, that's CPU time/latency per login.


The fact that we're still talking about password hashing shows how much we're losing the war on security. Whether or not a service stores passwords correctly cannot be verified by the user. There is no up-front cost to storing passwords incorrectly, so sites have inadequate incentive to store their passwords safely. As such users must use different passwords for every site. This simply is too technical an issue for most users: no amount of education will fix this, and password managers are too much work for most users. The end result is that even if you hash your passwords correctly, your user's passwords will be compromised on other systems and this will lead to accounts on your system being compromised.

The solution to this is zero-knowledge password proofs[1]. Essentially, you should never be passing your password to another party. Instead, you should be providing the authenticating party with a prover (analogous to a public key in asymmetric-key encryption, but based off your password) when you sign up. Then when you want to authenticate, you provide the server with a proof based off your password which exposes no information about your password but can be used to verify that you have your password using the prover (analogous to a signature in asymmetric-key encryption, but again based off your password). There are a number of ways to generate these provers and proofs using existing asymmetric-key algorithms such as RSA, ElGamal, or ECDSA.

Once this becomes pervasive, browsers and other network applications can provide obnoxious security warnings similar to those currently provided for untrusted certificates. This will create an up-front cost for people still using password hashing and shame them into moving to ZKPP, while providing a user-friendly way for users to tell if their password is being used insecurely. Only once people are no longer giving their passwords to anyone with a login page can we be sure that poor security on other sites won't compromise our own servers.

EDIT: Additionally, ZKPP mitigates some of the damage caused by man-in-the-middle attacks. Currently, if an attacker can gain access to communications between a user and server, they can access the password in plaintext when it is passing over the wire, even if it is adequately hashed on the server. This has both permanence (the password continues to be useful after the vulnerability is discovered--until the user changes their password) and wide application (the password can be used on multiple sites).

With ZKPP the attacker only has access to the proof of the password. This might allow the attacker to authenticate with the server during the attack. However, a proper ZKPP implementation uses unique nonces from the server to create the proofs and rejects non-unique proofs, so the proof cannot be used after the vulnerability has been fixed (the server will check that it is unique) and it cannot be used on other sites (the nonce is provided by the server).

[1] http://en.wikipedia.org/wiki/Zero-knowledge_password_proof


Ask me which I'd trust more: a website that stores passwords using whatever hash a PHP developer came up with, or a website that implemented some kind of PAKE, like SRP, to authenticate passwords.

What's especially ironic about your comment is that password-authenticated key exchanges still require servers to store authenticators which can be attacked offline. PAKEs actually make the problem we're talking about harder, not easier, because the authenticator format has to be compatible with the protocol.


> Ask me which I'd trust more: a website that stores passwords using whatever hash a PHP developer came up with, or a website that implemented some kind of PAKE, like SRP, to authenticate passwords.

If you're asking that question you don't understand the purpose of SRP or ZKPP. If you're giving a password you use elsewhere to a website, you're trusting them with your private data, and you shouldn't. As developers it's our jobs to prevent users from making this mistake if we can.

When using SRP or another ZKPP scheme, trust doesn't enter the equation. You aren't giving the server your password, you're giving them a piece of data which is verifiably difficult to reverse to obtain your password, so you don't need to trust them to store it properly.

> What's especially ironic about your comment is that password-authenticated key exchanges still require servers to store authenticators which can be attacked offline.

This isn't ironic: this is exactly what I would expect from kerkelsager's comment. Again you're just showing your ignorance. Yes, you can attack an authenticator. The point of ZKPP is that it allows the client to verify that such an attack is computationally difficult. If you've given the server your password in plain text (or reversibly encrypted form), you can no longer verify that obtaining the password from the authenticator is computationally difficult. For all you know, the server stores your password in plain text. This isn't a theoretical problem: there are numerous examples of this happening.

> PAKEs actually make the problem we're talking about harder, not easier, because the authenticator format has to be compatible with the protocol.

If you're objecting to implementing things correctly because it's hard, software might not be the right career for you.


It's always possible that I just don't know how SRP works, I suppose. Or: it's possible that I'm right, and that using a PAKE to handle simple logins to web and mobile applications is a really bad idea that doesn't make any of the problems we're talking about on this thread easier.


SRP solves a problem that password hashing doesn't solve. Obviously SRP is harder to implement than password hashing. If you're still talking about which is "easier" you're still missing the point of SRP (and ZKPP).


You're missing me. SRP doesn't solve the password storage problem --- its authenticators are crackable --- and introduces new ones. SRP does not address the problem we're talking about on this thread. We don't have password storage problems simply because applications don't use "ZKPPs" and PAKEs.


There is no good solution to the "password storage problem", as you call it. The fundamental issue is that "storing passwords securely" is the wrong problem to solve.

Think from the perspective of a non-technical user. You're lazy, so you want to use a short password that's easy to remember, and you want to use it on every website.

Now think from the perspective of a software engineer. Your non-technical users will use short passwords that are easy to remember and therefore easy to break. And they will use that password on every website. So no matter how you store your user's passwords, some idiot server administrator somewhere will store those same passwords in plain text, and they'll get hacked, and the hackers will have access to your user's passwords.

So the problem isn't "how do I store passwords securely", it's "how do I prevent my users from giving their passwords to an idiot server administrator who won't store them securely".

And as a technical user, I also have this problem, which is "how do I know if my server administrator is an idiot and is storing my passwords in plain text?" The solution to this is to use different high-entropy passwords on different sites, but this is tedious.

If ZKPP (zero-knowledge password proof) is widely adopted and supported in browsers, it solves both the server administrator's problem and the technical user's problem:

1. It stops idiot server administrators from storing passwords in plain text. The "zero knowledge" part of ZKPP means that users never give server administrators their password or any knowledge about their password, so administrators can't store the password stupidly.

2. As a technical user, I can now use the same password on multiple sites, provided a) my password is significantly entropic and b) all those sites use a ZKPP scheme. Since I never give the password to any site, I don't have to worry that one of them will store my password stupidly. My browser does the job of providing different authenticators to different sites, so breaking one authenticator doesn't break all of them.

3. A non-technical user with a low-entropy password on multiple still runs the risk that their password will be broken one one site, breaking it for all sites. However, the non-technical user is still better off because a) their password is at least properly hashed on all sites, rather than being stored in plain text, which will make an attack more costly, and b) caching password hashes amortizes the performance hit of password hashing, so we can afford to use more secure hashes, which again makes an attack more costly.

NOTE: I don't know the details of SRP well enough to know whether all these benefits apply. I do know that SRP claims to provide a ZKPP, so I'll tentatively lump it in with ZKPPs, but I haven't actually verified the algorithm personally so I can't speak to its security.


2. As a technical user, I can now use the same password on multiple sites, provided a) my password is significantly entropic and b) all those sites use a ZKPP scheme. Since I never give the password to any site, I don't have to worry that one of them will store my password stupidly. My browser does the job of providing different authenticators to different sites, so breaking one authenticator doesn't break all of them.

Go through the exercise of cracking an SRP authenticator to see the problem with this logic.

Weirdly, despite saying upthread that I must not know how SRP works to say what I'd said, you now say that you're not familiar with SRP. If it helps, substitute your favorite password protocol instead of SRP. I believe the problem will be the same.

If not: happy to learn something new.


> Go through the exercise of cracking an SRP authenticator to see the problem with this logic.

There are mathematical proofs of SRP's security. Yes, there are some issues with some implementations of SRP, but those are problems with implementations, not with SRP. Frankly, this is just one of those arguments at this point where it's clear you don't actually understand the fundamentals of security and you're too committed to your argument and too proud to admit you don't know. Since you can't actually make an argument, you're just presenting me with difficult/impossible tasks and claiming that if I did them it would prove your point, knowing full well that I won't do them. If you actually were knowledgeable on this topic, you could explain it: I have explained everything I said so far.

> Weirdly, despite saying upthread that I must not know how SRP works to say what I'd said, you now say that you're not familiar with SRP.

I don't know all the exact implementation details of SRP, but I do understand the general architecture. The problem is that the devil in security is often in the details. I know enough to know the limitations of my knowledge. The important thing for the sake of what I'm saying is that I know what problem SRP is trying to solve.

> If not: happy to learn something new.

The only thing I'm going to try to teach you at this point is this: if you're going to even bother forming an opinion on something technical, you had better be damn sure you're right. Because if you're wrong, it's human nature to react negatively when someone tells you you're wrong, so you'll try to argue about something you're wrong about, and the result is: you'll never learn, and you'll probably impress some people who know even less than you, but you'll embarrass yourself in front of anyone who actually knows what they're talking about, and you'll limit your progress as an expert in your field. You'll never get smarter until you stop trying to prove how smart you already are.


> The fact that we're still talking about password hashing shows how much we're losing the war on security.

This post was written years ago.

> Whether or not a service stores passwords correctly cannot be verified by the user, and as such users must use different passwords for every site.

Actually, in PHP applications, if passwords are stored plaintext or via unsalted MD5/SHA1 and are compared with the non-strict == operator, we can test it remotely.

https://eval.in/108854

Granted, this is technically exploiting a security vulnerability, but it's pretty conclusive if it works. :)

As for ZKPPs, I'm looking forward to SQRL for anonymous, Ed25519 challenge-response based authentication that takes place without requiring technical knowledge, personally.


Link is four oh four, but I assume you're talking about a string comparison timing attack? Those don't really work over a network on modern hardware. Most string comparison functions actually compare words (8 bytes), and string comparison increases faster over the years than network latency. For more info see the Time Trial paper by Daniel Mayer and Joel Sandin ( https://www.blackhat.com/docs/us-14/materials/us-14-Mayer-Ti... / http://matasano.com/research/TimeTrial.pdf / https://github.com/dmayer/time_trial )


Err, no, I'm not talking about a timing attack.

    <?php
    $a = md5('240610708');
    $b = md5('QNKCDZO');
    
    echo "$a\n";
    echo "$b\n";
    echo "\n";
    
    var_dump($a == $b);
Run that code.

Then change the == to an === and observe the difference.


Also, not sure if I actually have to mention Matasano in a post to get you to see this, but it'd be great if you could link to a blog/github/Twitter/something on your HN profile. :)


Wow, the level of crazy there is very high. Up until today I thought that PHP was fine, but nobody should ever use it for anything remotely real. You have changed my mind. We must kill PHP with fire.


PHP offers hash_equals() since 5.6 and password_hash()/password_verify() since 5.5 (and === in all versions) -- this is a problem that plagues poorly designed legacy code.

The problem is not PHP, the problem is ignorant developers who do not know [how] to use password_hash() and password_verify().

[Also, "Matasano". I feel like I'm pressing the summonthensa.com button but w/e.]


I'm going to have to disagree. Any programming language where string comparison works "normally" for everything except for certain magic string values is Wrong. Like, I see where they're going with it, but it's probably a source of undetected Heisenbugs on a significant proportion of PHP sites. Not just talking about password hashes and other security critical operations here, just good old bugs.


Whole hashing and salting etc stuff is pointless. What does matter? Is the fact that passwords aren't reused anyway. Do I really care if you know that my password for service X was: c'EyqXnrq-bCyfF_dK67$j I don't really couldn't care less, if you get it hashed or not, really. If they owned the system, and they were after my data, they got it already. Password(s) is just minute and meaningless detail. I've always wondered this pointless discussion about passwords. It just doesn't make any sense.


> Is the fact that passwords aren't reused anyway.

Completely wrong. People reuse passwords all the time.




Join us for AI Startup School this June 16-17 in San Francisco!

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

Search: