Just to be clear with you, the mistake here is that the salt is being generated. This means that you are not storing H(salt, pass) in your DB but probably something that is “password-like,” in that if you know it you can log in as that user.
In a more secure auth flow you instead have:
Request 1:
-> Can I get a login CSRF token for `crdrost`?
- generate random string and store on the users table with an exp date
<- Sure here is a login token
Request 2:
-> Here is my token and my plaintext password. (!)
- Users table: select CSRF token, salt, KDF(salt, pass) previously computed
- compute KDF(salt, pass), compare with previous computation
- generate session token
<- Sure here is your session token
In terms of KDFs you might use Blowfish or PBKDF2 or Scrypt or more recently Argon2, you can also HMAC or hash-concat if you have strong enough complexity requirements that you are not worried about brute force attacks, e.g. “when you sign up I will generate a random password for you.”
The remaining security vulnerability is typically that you accidentally auto-log plaintext passwords so this requires vigilance around that.
But the point is that at no time does the database store anything which can be used to complete a login. Suppose I do the KDF on the client side, then its output is “password-like” and if I know that output by reading a row accidentally from the users table, I can log in as that user. Similarly by overhearing an HTTP login over WiFi, I can log in as that user.
Similarly you have a “challenge/response” system because you don't want plaintext passwords to even make it to the API, this is a noble aim but it absolutely requires public key crypto to be done correctly: you store a public key derived from the private key; login page uses password to generate private key and then signs a request to sign in, you confirm the signature with the public key. A full scheme, so that you are not rolling your own crypto, is described by the Secure Remote Password protocol.
The security risks there are just that the process has become very complex and complex things are easier to get wrong.
Yeah I mean that comment is about achieving challenge/response without storing something password-like; obviously a non-challenge/response login is not going to be a counterexample.
While CR does not need the full force of public key crypto it has properties which require a distinctive subset of those features in this context—I want to be able to take a password and derive two values (K, V) such that g(V, f(K, s)) = h(V, s) for some large family of s'es, but f(K, s) cannot be computed as j(V, s) efficiently. Public key crypto is more or less the case where h(V, s) = s, giving an option to maybe do something interesting when h is nontrivial.
[Just to give an example that I should have given yesterday for anyone who finds this in the future, in particular if you omit some of the safeguards of SRP then the “core” of it has h(V, s) = V^s (mod N) for some N and in some sense it is not doing full public key crypto but rather the seemingly-weaker subset that is Diffie-Hellman key exchange. But of course then ElGamal came and proved that at the core of Diffie-Hellman you can find a public key crypto algorithm so they are clearly very strongly related to each other even if this doesn't need to use the full force of it.]
In a more secure auth flow you instead have:
In terms of KDFs you might use Blowfish or PBKDF2 or Scrypt or more recently Argon2, you can also HMAC or hash-concat if you have strong enough complexity requirements that you are not worried about brute force attacks, e.g. “when you sign up I will generate a random password for you.”The remaining security vulnerability is typically that you accidentally auto-log plaintext passwords so this requires vigilance around that.
But the point is that at no time does the database store anything which can be used to complete a login. Suppose I do the KDF on the client side, then its output is “password-like” and if I know that output by reading a row accidentally from the users table, I can log in as that user. Similarly by overhearing an HTTP login over WiFi, I can log in as that user.
Similarly you have a “challenge/response” system because you don't want plaintext passwords to even make it to the API, this is a noble aim but it absolutely requires public key crypto to be done correctly: you store a public key derived from the private key; login page uses password to generate private key and then signs a request to sign in, you confirm the signature with the public key. A full scheme, so that you are not rolling your own crypto, is described by the Secure Remote Password protocol.
The security risks there are just that the process has become very complex and complex things are easier to get wrong.