title: REST API authentication: how to prevent man-in-the-middle replays?
body: <p>I am writing a REST API and would like to implement an authentication system similar to AWS.</p>
  
  <p><a href="http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html" rel="nofollow">http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html</a></p>
  
  <p>Basicly, on AWS the client encrypts the Authorization header with some request data using a secret key that is shared between client and server. (Authorization: AWS user: )</p>
  
  <p>The server uses the key to decrypt the header using the shared key and compare to the request data. If successful, this means the client is legit (or at least is in possession of a legitimate key).</p>
  
  <p>The next step can be to execute the request or, preferrably, send the client a unique, time-based token (ex.: 30 minutes) that will be used on the actual request (added to a Token header, for example). This token cannot be decrypted by the client (uses a server-only key).</p>
  
  <p>On next requests, the server checks the token (not Authorization anymore) and authorizes the request to be executed.</p>
  
  <p>However, is it possible to have a man-in-the-middle, even on SSL-encrypted connections, that replays these token-authenticated requests? Even if the MITM does not know what's inside the message, he/she could cause damage for example by ordering a product many times. If the server receives a replayed message and the token is still within the valid timestamp, the server will assume this is a valid request and execute it.</p>
  
  <p>AWS tries to solve this with a timestamp requirement:</p>
  
  <blockquote>
    <p>A valid time stamp (using either the HTTP Date header or an x-amz-date
    alternative) is mandatory for authenticated requests. Furthermore, the
    client timestamp included with an authenticated request must be within
    15 minutes of the Amazon S3 system time when the request is received.
    If not, the request will fail with the RequestTimeTooSkewed error
    code. The intention of these restrictions is to limit the possibility
    that intercepted requests could be replayed by an adversary. For
    stronger protection against eavesdropping, use the HTTPS transport for
    authenticated requests.</p>
  </blockquote>
  
  <p>However, 15 minutes is still enough for requests to be replayed, isn't it? What can be done to prevent replay attacks in this scenario? Or am I overthinking and a certain degree of uncertainty is acceptable if you provide enough mechanisms?</p>
  
  <p>I am thinking about requiring the client to add a unique string on each request body. This string will be transport-encrypted and unavailable to MITM for modification. On first receipt, the server will record this string and reject any new requests that contain the same string in the same context (example: two POSTS are rejected, but a POST and a DELETE are OK).</p>
  
  <p><strong>EDIT</strong></p>
  
  <p>Thanks for the info. It seems the cnonce is what I need. On the wikipedia diagram it seems the cnonce is only sent once, and then a token is generated, leaving it open to reuse. I guess it is necessary to send a new cnonce on every call with the same token. The cnonce should be included on the body (transport-protected) or shared-key-protected and included on a header. Body-protection seems the best (with obvious SSL) since it avoids some extra processing on both sides, but it could be shared-key-encrypted and included on a header (most likely prepended to the temp token). The server would be able to read it directly on the body or decrypt it from the header (extra processing).</p>