1
$\begingroup$

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

$\endgroup$
1
  • $\begingroup$ An augmented PAKE such as SPAKE2+ will achieve this. $\endgroup$ Dec 8, 2017 at 21:03

1 Answer 1

1
$\begingroup$

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...

$\endgroup$
3
  • $\begingroup$ I know from experience that device-tied keys are indeed often a problem. $\endgroup$
    – Maarten Bodewes
    Nov 8, 2017 at 22:22
  • $\begingroup$ Thank you for your detailed answer poncho! The WebCrypto API have a « wrapKey » function to protect a private key with a password, this was my first idea too, but the problem with this idea is it's possible to brute-force on client-side without the need to connect to the server. The WebCrypto API answer when the key is correctly unwrapped or not. I would like to force the server to known if someone trying multiple times a password, to permit to inform the account owner and to limiting the number of trying. EDIT: I forgot to mention, it's a good idea to use the STS protocol BTW, I can use it :) $\endgroup$
    – lakano
    Nov 8, 2017 at 22:57
  • $\begingroup$ @MaartenBodewes Could you add some example please? We known this require some reconfiguration if the user clear is IndexedDB data, re-install his browser, OS, etc, but it's not a problem for us, in fact the user need to keep a printed QRCode to rescue their account (similar to backups codes of U2F keys), protected by a simple 4 digits PIN (but it's another subject). Excepted the possible bad user-experience in this kind of situation, did you see security problem please? $\endgroup$
    – lakano
    Nov 8, 2017 at 23:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.