0

I am attempting to use SRP to verify clients when they authenticate with a webserver, so that the password is never sent over the wire.

Looking at the SRP procedure, when a client registers with the server it sends v (verifier), s (salt), and I (the username or identifier) to the server who stores these values. However, it is stated that:

[The salt] could be chosen by either side but is done by [the client] so
that [it] can register I, s and v in a single registration request.

If the salt can be chosen by either the server or the client, then we can just assume the server generates it.

When the client later tries to authenticate with the server, the client sends I and the server responds with s. Then the client uses s and other data to preform the proof of password.

My question is, why is s static? Why does it need to be stored at all?

The salt is sent out to whoever requests it, and because of this an attacker could attempt to build a targeted rainbow table by requesting the salt of a specific user. This is brought up in this question, at bullet point #2.

Wouldn't it provide more security for the server to randomly generate a salt upon a ClientHello message? On each separate request, a different salt would be sent, preventing the attacker from being able to compile a targeted rainbow table. Additionally, the salt wouldn't be stored on the server, which would make the information even less useful in the event of a data breach.

Notably, this method might open up an attack vector where the attacker continually initiates the authentication procedure until the server responds with a favorable salt. However, if the entropy of the salt s is sufficiently large this would be infeasible. Additionally, the server could throttle the number of authentication attempts per username I, so that an attacker couldn't run this attack in parallel with a botnet

  • For example: After initiating an authentication attempt for I, the server would not respond to subsequent attempts to authenticate as I within a time frame of say, half a second.
ExecutionByFork
  • 437
  • 3
  • 7

1 Answers1

1

You are absolutely correct that making the salt publicly available brings with it some security risks (which I will return to), but first let me address why the salt does need to be static.

The client must be able to derive from the user provided password the x that corresponds to the verifier, v that the server stored. The client authenticates to the server by proving that it knows (or can compute) x while the server authenticates to the client by proving that it knows v.

This means that the client will need to derive the same x each time, as it is mathematically related to the v which the server stores. The client computes x from the password and a salt. To produce the same x it needs the same password and salt each time.

Making the salt opaque

As you (and others) have noted, the fact that the salt is fully public means that an attacker does not need to wait for a breach of the server to start cracking. The attacker can precompute a large number of candidate v and then in the event of a server breach, when the real v is discovered, the attacker can see if that is a v that they have a password guess for.

This issue is true of every prior (asymmetric) PAKE as was pointed on in a brilliant paper released earlier this year: OPAQUE: An Asymmetric PAKE Protocol Secure Against Pre-Computation Attacks. The authors propose a new construction that wraps a more traditional PAKE in a way that does not suffer from this problem.

Although I'm the primary contributor to an SRP implementation, I posted the following picture after learning about OPAQUE.

Me, SRP, and OPAQUE reaction

Jeffrey Goldberg
  • 5,839
  • 13
  • 18
  • So, if I'm understanding this correctly, x and v have a similar relationship to public private keys. If the salt changes, the input to generate x changes which means that v would need to also be regenerated? – ExecutionByFork Dec 01 '18 at 21:27
  • Yes. Although _x_ and _v_ both need to remain secret, they are bound to each other. If you go back and look at the protocol, you will see that _v_ is computed from _x_. – Jeffrey Goldberg Dec 03 '18 at 05:04