1

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? :)

lakano
  • 51
  • 6

1 Answers1

1

Actually, if you assume that the client is able to store a secret long-term, it becomes rather easy; just have the client store the private key (possibly encrypted by the password); the server gets the public key.

Then, when it comes time to authenticate, the client takes the password, decrypts the private key, and then uses the private key to authenticate to the server (and ideally generate some shared symmetric keys that can be used to protect the following traffic; defeating MITM is important).

Someone who breaks into the server (and possibly records some transcripts of the authentication exchanges) gets no information about the passwords, all he sees is a series of public keys. And, with a bit of care, someone who breaks into the client may get no information about the password either (if we are careful to pick a public key algorithm whose private keys look random; ECC is good with this).

Now, one aspect that your protocol doesn't address is 'how does the client make sure he is logging into the valid server'; the easiest way for that is to store the server's public key in with the data the client is keeping around anyways.

With that, one simple way may be the simple STS protocol; the client picks a random DH key, and sends its public key share (signed by its private signature key). The server picks a random DH key and sends its public key share (signed by its private signature key). Both sides verifies the received signatures, generate the shared DH secret, and so have keys which can be used to protect further traffic.

Alternatively, you could go a bit fancier and use TLS with client certificates; that's more work, but is certainly standard; it may make preventing dictionary attacks on someone who captures the client a bit more challenging, though...

Of course, the drawback to this 'store some of the secret on the user's device' solution is the assumption that the user will always use that device to log in; he can't use any other. I suspect that constraint may be why we don't see it more often...

poncho
  • 154,064
  • 12
  • 239
  • 382