SRP is very useful but if our DB is leaked, an attacker could brute force a user's password with his associated salt/verifier found in the DB. I'm searching a solution to prevent this.
My first idea is to not store the salt/verifier in DB, but inside a separate binary file encrypted with our company password. The password isn't hard-coded in the source code, it's loaded (ideally in TPM) from our external USB key when we start the RESTful service. This prevent some kind of attacks but not all.
May be we can solve the problem only if the server himself can't check alone when a password is good or not. I mean, the solution is may be to store one piece of the secret on the user's device. Like if in the SRP protocol, the salt wasn't sent by the server but sent by the user's device. Of course, it's not good if the user send each time the same bytes to the server because of possible MITM interception (even if we mitigate the risk because we uses HTTS, HSTS, HPKP and TLS 1.2 minimum required).
My question is, there is a recommended protocol to do this kind of « shared-verification » please?
The best way I've found currently is this one (inspired by the FIDO UAF/U2F challenges) :
When the user sign up:
- A random salt of 32 bytes is generated,
- the user's password is derived with Argon2id and the salt,
- the salt is saved on the user's device DB (indexedDB),
- we use the derived key as a private ECDSA P-512 key and deducing the matching public key associated,
- we send this public key to the server, the server store it in the DB
Then, when the user sign in:
- The server generate a 512 random bits as a challenge,
- the user's device derive the inputted password with Argon2id and the saved salt,
- we use the derived key as a private ECDSA P-512 key and sign the server's challenge,
- we send the signature of the challenge to the server,
- the server use the user's public key to verify the challenge
With this solution, even a sysadmin of our staff can't brute force the password of a user in the DB because he doesn't have all the required elements to known when the password match. Of course, we can also store the user's public key encrypted with our password in a separated binary file to increase the security.
And yes, I known this technique requires that the user authorized each device he want to uses to save each time a new salt on the indexedDB, it's not a problem for our case.
Another idea, more simple, should be to keep SRP, but rather than using the derived user's password directly in SRP, to firstly use a random binary mask (XOR) on the password. The mask is saved on the user's device indexedDB.
I known the « don't roll your own », it's why I'm asking if there is a recommended protocol for that please? :)