If you are securing web services, replay attacks is one of the things that you should watch out for. Replayed messages can cause duplicate transactions and can be used to create DOS attacks. Note that replay messages don’t necessarily have to come from malicious users; in environments where exactly-once message delivery is not guaranteed, they are actually expected to happen.
The countermeasures to detect these situations are basically these two:
- Timestamping: Incoming messages include a timestamp field that is checked by the server against its clock. If the timestamp from the client message differs by a predefined factor from the current server time, then the message is suspicious of being replayed an it’s discarded. With timestamping we can avoid replay attacks that happen over the server replay window maximum value (for example 5 minutes) but what if the hacker manages to replay the message within the window? Nonces to the rescue.
- Nonce tracking. Incoming message includes a nonce (randomly generated string by the client). The server keeps track of the nonces arrived within the replay window. When a new message arrives with a timestamp that falls within the valid window, the server checks if the message nonce can be found in its nonce cache and if it does, we have proof that the message has been replayed. In a server farm scenario, all nodes in the farm should share the same nonce cache, otherwise in the worse-case scenario messages could be successfully replayed N-1 times, where N is the number of nodes in the farm.
Note: It goes without saying that both Timestamp and Nonce must be signed otherwise they could (and they would) be tampered.
Now, WCF implements a replay detection mechanism and provides a bunch of configuration options to tune the Timestamping and nonce tracking procedures (i.e: ReplayWindow, ReplayCacheSize for the nonce cache).
However, there doesn’t seem to be any extensibility point for custom nonce cache implementations. Internally (thanks Reflector!), WCF uses the class NonceCache (declared as Internal and Sealed) which is a in-memory cache. If you’re using IIS to host your services, you can imagine what happens to the cache when IIS pool is recycled!
Interestingly enough, the missing hook in WCF was available in WSE 3.0. In you look at that WSE article, you’ll see that for that sample, they used back then a DB table as a nonce cache; today I’d probably go for an AppFabric cache for a better performance and high availability, but this is a different story!
Maybe in WCF 5.0?