2

If a client/server application uses a challenge/response pattern for authentication, e.g. SCRAM or alike, it often involves the usage of nonces (client nonce and server nonce) for preventing replay attacks.

The server will generate a server nonce, based on a secure random generated number concatenated with the client nonce. Supposing that the server stores the most recent received client nonce, and issued server nonce, to guarantee that "older" or "invalid" nonces will not be accepted, this would open an attack vector.

An attacker could brute-force request challenges to userid's that he guesses, in order to override the valid and agreed client/server nonce with a new value, that the actual client doesn't know. If this happens in between the actual client's challenge and response, the server will deny access as the nonce will not be valid anymore. Which would be some kind of Denial Of Service attack.

If the server decides to only update the actually valid server/client nonce in storage only if the challenge/response was successfully executed as a whole, it would need to decline challenge requests for users that have not responded to the most recent challenge. This would also open an an attack window. The attack could request challenges to (guessed) users in order to prevent them from requesting a challenge in the first place.

Assuming that the server will keep track of a list of unused nonces, both attacks would be prevented, but this opens another vector for the attacker to request huge amount of challenges, leading the server to store all of those nonces in storage. Provoking I/O load and potentially leading to DoS again.

Anyhow I am currently not understanding how to securely implement nonce handling on the server-side to prevent those DoS attacks. Currently I have the feeling that one trades the protection against replay attacks in favour of DoS.

I know that there are other means to prevent this, via request throttling on firewalls etc, but I'd like to solve this problem on the challenge/response implementation level if possible. Thanks for ideas and answers.

  • SCRAM is intended to allow authentication over unencrypted communication channels. Just use SSL and you'll be fine. Authentication is a well understood problem. Unless there's a reason you can't use industry best practices, use them. – Neil Smithline Apr 20 '16 at 15:21
  • Neil, this is not a question of wether or not to use SSL/TLS, in fact SCRAM can go alongside with TLS and is even intended to with its channel binding capabilities. Yet I want to understand how a good nonce handling strategy can look like that mitigates the attack vectors I pointed out. – Tobias N. Sasse Apr 20 '16 at 15:23
  • Fair enough. My comment was partially based on your concern that somehow SSL is not secure enough for password authentication. But as you expressed those concerns in a [previous question](https://security.stackexchange.com/questions/115913/recommended-end-user-authentication-for-openid-connect-oauth-2) they aren't relevant to this question. – Neil Smithline Apr 20 '16 at 15:54
  • In addition to Neil's answer, I would note that it is important to ensure that the client response is compared with the expected result value using a linear time comparison method, not an early-out optimised string comparison such as strcmp. I recently discovered a vulnerability in an application based on exactly this, and it's remarkably feasible to perform a timing attack against poor implementations over the network. – Polynomial Apr 20 '16 at 16:20
  • Yes, but in the other post I also did not neglect SSL. It's more that I want to understand how stuff should work. SSL provides authentication capabilities but requires a PKI with client certificates, which is not feasible for all use cases such as mobile... My questions here so far come from a theoretical standpoint, not going towards how to solve it in a certain real world problem. Thanks for your feedback though! – Tobias N. Sasse Apr 20 '16 at 16:25

1 Answers1

3

The two concerns you've raised are:

  1. The server's copy of the server nonce can be altered by an attacker who doesn't know the password.
  2. As the server's list of client nonces grows without bounds, it can be used in a DoS.

A common technique is to time-limit the nonces. Say, for M minutes for an appropriate M.

For the first problem, by time-limiting the nonces, the server can maintain multiple authentication sessions with the client, each one keeping track of it's own nonce. This isn't a large resource drain on the server as these sessions are automatically deleted after M minutes.

The second problem is resolved by time-restricting client nonces. For this to work, the client nonce must include a timestamp. Otherwise you're open to post-timeout replay attacks, when the server cleans out its expired nonces, thereby "forgetting" used nonces. So the client's nonce should be timestamp + secure random number. By including the timestamp in the nonce, it ensures that the nonce cannot be used post-timeout.

WHen determining the value of M, it needs to be large enough to handle network communication times and clock differences between the server and the client. M needs to be small enough to sufficiently lower your resource requirements. M being 1, or even less than 1, may be appropriate if no user interaction is required during the authentication process. If there's user input required, a larger M will be needed.

A well-resourced attacker may still be able to execute a DoS upon you as there is still a window of M minutes for this to occur. But this is a small window and would require a lot of attacker resources. That is, it would be a DDoS and not a straight DoS. Surviving DDoS attacks are a problem of their own.

Neil Smithline
  • 14,621
  • 4
  • 38
  • 55