What is the use of a client nonce?
After reading Part I of Ross Anderson's book, Security Engineering, and clarifying some topics on Wikipedia, I came across the idea of Client Nonce (cnonce). Ross never mentions it in his book and I'm struggling to understand the purpose it serves in user authentication.
A normal nonce is used to avoid replay attacks which involve using an expired response to gain privileges. The server provides the client with a nonce (Number used ONCE) which the client is forced to use to hash its response, the server then hashes the response it expects with the nonce it provided and if the hash of the client matches the hash of the server then the server can verify that the request is valid and fresh. This is all it verifies; valid and fresh.
The explanations I've found for a client nonce however are less straight forward and questionable. The Wikipedia page for digest access authentication and several responses here on Stack Overflow seem to suggest that a client nonce is used to avoid chosen-plaintext attacks. I have several problems with this idea:
- If a person can sniff and insert packets, the greatest vulnerability is a man-in-the-middle attack which neither a nonce nor a cnonce can overcome, therefore making both meaningless.
- Assuming for a second that the attacker doesn't want to engage in a man-in-the-middle attack and wants to recover the authentication details, how does a cnonce provide additional protection? If the attacker intercepts communication and replies to a request with its own nonce, then the response from the client will be a hash of the nonce, data and cnonce in addition to the cnonce in unencrypted form. Now the attacker has access to the nonce, cnonce and the hash. The attacker can now hash its rainbow tables with the nonce and cnonce and find a match. Therefore the cnonce provides zero additional protection.
So what is the purpose of a cnonce?
I assume there is some part of the equation I'm not understanding but I haven't yet found an explanation for what that part is.
EDIT Some answers have suggested that the client can provide a nonce and it will serve the same purpose. This breaks the challenge-response model however, what are the implications of this?
A nonce is a unique value chosen by an entity in a protocol, and it is used to protect that entity against attacks which fall under the very large umbrella of "replay".
For instance, consider a password-based authentication protocol which goes like this:
- server sends a "challenge" (a supposedly random value c) to the client
- client shall respond by sending h(c || p) where h is a secure hash function (e.g. SHA-256), p is the user password, and '||' denotes concatenation
- server looks up the password in its own database, recomputes the expected client response, and sees if it matches what the client sent
Passwords are secret values which fits in human brains; as such, they cannot be very complex, and it is possible to build a big dictionary which will contain the user password with high probability. By "big" I mean "can be enumerated with a medium-scale cluster in a few weeks". For the current discussion, we accept than an attacker will be able to break a single password by spending a few weeks of computation; this is the security level that we want to achieve.
Imagine a passive attacker: the attacker eavesdrops but does not alter the messages. He sees c and h(c || p), so he can use his cluster to enumerate potential passwords until a match is found. This will be expensive for him. If the attacker wants to attack two passwords then he must do the job twice. The attacker would like to have a bit of cost sharing between the two attack instances, using precomputed tables ("rainbow tables" are just a kind of precomputed table with optimized storage; but building a rainbow table still requires enumerating the complete dictionary and hashing each password). However, the random challenge defeats the attacker: since each instance involves a new challenge, the hash function input will be different for every session, even if the same password is used. Thus, the attacker cannot build useful precomputed tables, in particular rainbow tables.
Now suppose that the attacker becomes active. Instead of simply observing the messages, he will actively alter messages, dropping some, duplicating others, or inserting messages of its own. The attacker can now intercept a connection attempt from the client. The attacker chooses and sends his own challenge (c') and waits for the client response (h(c' || p)). Note that the true server is not contacted; the attacker just drops the connection abruptly immediately after the client response, so as to simulate a benign network error. In this attack model, the attacker has made a big improvement: he still has a challenge c' and the corresponding response, but the challenge is a value that the attacker has chosen as he saw fit. What the attacker will do is always server the same challenge c'. Using the same challenge every time allows the attacker to perform precomputations: he can build precomputed tables (i.e. rainbow tables) which use that special "challenge". Now the attacker can attack several distinct passwords without incurring the dictionary-enumeration cost for each.
A client nonce avoids this issue. The protocol becomes:
- server sends a random challenge c
- client chooses a nonce n (should be distinct every time)
- client sends n || h(c || n || p)
- server recomputes h(c || n || p) (using the p from its database) and sees if this value matches what the client sent
Since the client includes a new random value (the "nonce") in the hash function input for each session, the hash function input will be distinct every time, even if the attacker can choose the challenge. This defeats precomputed (rainbow) tables and restores our intended security level.
A crude emulation of a unique nonce is the user name. Two distinct users within the same system will have distinct names. However, the user will keep his name when he changes his password; and two distinct users may have the same name on two distinct systems (e.g. every Unix-like system has a "root" user). So the user name is not a good nonce (but it is still better than having no client nonce at all).
To sum up, the client nonce is about protecting the client from a replay attack (the "server" being in fact an attacker, who will send the same challenge to every client he wishes to attack). This is not needed if the challenge is executed over a channel which includes strong server authentication (such as SSL). Password Authenticated Key Exchange are advanced protocols which ensure mutual password-based authentication between client and server, without needing some a priori trust (the "root certificates" when a SSL client authenticates the SSL server certificate) and protecting against active and passive attackers (including the "cluster-for-two-weeks" attack on a single password, so that's strictly better than the protocol above, nonce or no nonce).
In digest authentication the server sends a nonce and then the client sends that same nonce back. Seems to me that a client nonce is only really useful where the server is taking what the client says is the nonce at face value instead of what the server, itself, generated? If the HTTP connection was keep-alive it seems to me that the server could know what the nonce it just sent was.
@paynes_bay Statelessness often is a desirable property when using HTTP, especially for reasons of scalability and high availability. Not sending the nonce back to the server would make Digest Authentication stateful.
Out of curiousity - is it an important component of the client nonce that the server tracks and records each such that authentication is rejected when a client nonce is also reused?
Just to make it clear: Client nonce is particularly for in case the attacker is the server, right? Otherwise, even if I am over a secure channel, someone/interceptor still simply forward the request again (replay) without having to decrypt it. But for such sort of attacks, we use other mechanisms, like a request counter (per nonce) and such.