I recently committed an extension to dwsCrypto lib module that exposes direct support for cryptographic nonces and tokens.
What are those nonce things?
A cryptographic nonce is a number that is going to be used only once, it is usually a huge number, which will usually be encoded in various, non-decimal ways.
A nonce should be meaningless, impossible to guess, expiring and never reused.
The extension is centered around a Nonces static class that is dedicated to managing “expiring” nonces, or tokens, with a “short” life expectancy. Each nonce has an associated data string.
By default nonces are generated as a string of 20 characters you can place in URLs or anywhere (in more detailed terms, each nonce is 120 bits of cryptographic-strength random, encoded with an URI-safe base 64 scheme).
What are nonces useful for?
There are several uses for nonces. They typically involve a server generating a nonce and passing it to the client, the client then has a limited time to “do something” with the nonce, then has to send back a request alongside the nonce to the server.
- Cross-Site Request Forgery protection: you include a nonce in the form or ajax request fields, and check its validity. This can also be used to detect the same request being submitted twice. The nonce’s associated data can then typically be the session token (to ensure protection across sessions).
- Hash-Based Authentication Challenge: you use the nonce as the key for an HMAC. The server generates a nonce, the client then computes the HMAC of its secret key and your nonce. On the server-side, you first validate that the nonce is correct, then perform the same HMAC computation. This scheme is typically used for REST services to ensure the security of the secret key, or when you need some protection from replay attacks, multiple-submits or Denial of Service (as checking nonce validity is much faster than checking HMAC correctness, an attacker cannot force your server to perform pointless HMAC checks).
- Proof-of-Work Puzzle: the nonce is used as the puzzle for a Proof-of-Work challenge which the client has to solve (as part of anti-brute force protection). A simple scheme can be to send a nonce and ask the client to find a string that, when appended to your nonce, will have a SHA-256 hash beginning or ending with a certain number of zeroes (adjusting the number of zeroes allows adjusting the puzzle difficulty). When getting a puzzle response, check first the nonce validity, then the hash.
Finally another use for nonces can be as “light-weight” session tokens, when sessions are going to be short-lived or are going to be renewed continuously, or do not need to be persisted in a database. In those cases, you will however have to manage the nonce lifetime carefully.
Nonces is exposed as a static class, with only static methods:
- Nonces.Generate(millisecondsUntilExpiration : Integer; data : String = ”) returns a nonce string, with a specified expiration and an optional attached data
- Nonces.CheckAndRemoved(nonce : String; data : String = ”) returns true if the nonce is still valid and if its data matches. The nonce is then removed.
- Nonces.RemoveByData(data : String) removes all nonces with the specified data, typical use case will be when data is a session token and the session is closed (user logging out)
Less commonly used methods
- Nonces.CheckAndKeep(nonce : String; data : String = ”) returns true if the nonce is still valid and if its data matches, but does not remove the nonce.
- Nonces.GetData(nonce : String) will return the data associated to a nonce, if it exists and is still valid, or an empty string otherwise.
- Nonces.Register(nonce, millisecondsUntilExpiration, data) will (re)register a nonce you specify, main use case would be to re-arm a nonce, or if a nonce is externally specified.
- Nonces.Remove(nonce) will remove a particular nonce if it exists.
- Nonces.Clear will purge all active nonces.
Previously you could use DWScript’s expiring Global Storages alongside functions like CryptographicToken to implement nonces with very limited code, but you still had to delete the nonces manually, and Global Storages being enumerable, a misbehaving script could end up leaking information it should not have.
Like Global Storages, the Nonces are process-wide, thread-safe and shared across all scripts, but they are not enumerable (and not guessable, so a script only check the nonces it already knows, and cannot leak nonces from another context).