3

I have a scheme for a cookie with high-level confidentiality of information. The information to be hidden from the client is the expiration time of the cookie. I am wondering what insecurities i am opening myself up to with this scheme.

Note below that | denotes concatenation and (text)k is text encrypted using key k.

cookie = creation_time | (expiration_time)k | HMAC(creation_time|expiration_time|server_key , k) where k = HMAC(creation_time, server_key)

Steps for key validation are:

  1. Ensure creation_time is valid time stamp
  2. create k = HMAC(creation_time, server_key)
  3. decrypt (expiration_time)k using k.
  4. ensure (expiration_time - creation_time <= T) && current_time < expiration_time where T is a server allowed TTL for a cookie.
  5. compute HMAC(creation_time | expiration_time| server_key, k) and compare against the cookie value. if they are the same the cookie is valid.

The whole point of this cookie is to allow me ensure a cookie is received by the user at one point and pinged back through ajax within a time T.

  • I don't quite understand the need for all the effort? Why not just set the equivalent of a session id in the cookie, store its creation time on the server, and then validate the expiration time based on the server's own record of when the cookie was created? Why do you have to store the creation time in the cookie at all? – Conor Mancone Aug 18 '17 at 20:13
  • @ConorMancone i'm trying to accomplish this without needing server side storage. the client i'm doing this for has a shared hosting plan and so i cannot use distributed caching systems like redis. otherwise it would be simple. – lluisrojass Aug 18 '17 at 20:16
  • @lluisrojass You don't need storage for this approach; just make the expiration part of the session variables (available in every modern web language!) – Polynomial Aug 18 '17 at 20:19
  • the cookie i'm creating is to start a session. previously i have a PHP Session created everytime a new user GETs /index.php. My client has limited hosting space and so i'm trying to prevent someone cURL requesting every 2 seconds and just eating up space. So now an initial request to index.php kicks off an ajax ping back with this cookie. this way i can better ensure the user is legitimate. – lluisrojass Aug 18 '17 at 20:30
1

There are a few things wrong with this construction.

You didn't define which encryption algorithm you're using. If you were to use a block cipher mode with padding, such as CBC, your design would be potentially vulnerable to a padding oracle attack, since your server must decrypt the encrypted expiration_time value before validating the authenticity record against the plaintext. You should apply authenticity checks against the ciphertext wherever possible.

It's also not clear how the delimiters work between fields. You should define how each individual field is separately produced to avoid any confusion on the decoding process.

While not critical, it's also bad practice to have a single shared key for both encryption/decryption and authenticity (HMAC). You should always aim to have independent keys for these.

All in all this is an overly complex design.

A simpler way is to just store the expiry time as a session variable, like this in PHP:

session_start();
$_SESSION['expiry'] = time() + 60 * 60 * 24; // now +24 hours

And then in each request:

session_start();
if (!isset($_SESSION['expiry']) || !is_int($_SESSION['expiry']))
{
    // expiry time has been unset or corrupted somewhere, log and fail
}
if ($_SESSION['expiry'] < time())
{
    // session expired, do whatever you need to do about this
}

This saves the complex cryptographic scheme and the client-side access to the token.

  • I am trying to implement this cookie to facilitate the creation of a valid session. My client has limited space, and currently i have a session being created every time a new user GETs /index.php. To prevent someone cURL requesting every 2 seconds and eating up space, what i want to do is return index.php and have it ajax ping back with this cookie, if the cookie is valid it creates a session, and returns the PHPSESSID, if not then it does not. – lluisrojass Aug 18 '17 at 20:43
  • 1
    Then this is an XY problem. You should have asked how to avoid a disk exhaustion DoS attack in PHP. – Polynomial Aug 18 '17 at 20:46
  • i'm sorry :(, do you have any advice as to how to mitigate this issue? – lluisrojass Aug 18 '17 at 20:52
  • @Polynomial indeed. I'm not sure if this is the way to prevent DoS either. This may prevent some stuff being written to the hard-drive, but encryption/decryption can be CPU intensive. As a result you may be trading a space-eating DoS "attack" for a CPU eating DoS "attack". Either way your server may die – Conor Mancone Aug 18 '17 at 20:52
  • 1
    @lluisrojass Rate limiting in mod_security is a good start. If you've got access to iptables rules you could set those up as another layer of rate limiting. After that you can set session.gc_maxlifetime to a reasonable value to try to ensure session files are cleaned up quickly when unused. – Polynomial Aug 18 '17 at 20:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.