Encrypting Cookies

Problem this snippet solves:

This example shows how to encrypt and decrypt a HTTP cookie from within an iRule.

Using HTTP::cookie encrypt / decrypt

Here is a cookie encryption iRule that works in a high-availability setup and is CMP-compatible. If you are running a new enough version of TMOS, yet you don't want to use the built-in cookie encryption provided in the HTTP profile, here is the way to go.

Here is an example which allows you to select the cookie(s) to encrypt by wildcard: Encrypt HTTP cookies with dynamic names

How to use this snippet:

when CLIENT_ACCEPTED {
  set cookiename "MyCookie"
  set encryption_passphrase "abcd1234"
}
when HTTP_RESPONSE {
  if { [HTTP::cookie exists $cookiename] } {
    HTTP::cookie encrypt $cookiename $encryption_passphrase
  }
}
when HTTP_REQUEST {
  if { [HTTP::cookie exists $cookiename] } {
    set decrypted [HTTP::cookie decrypt $cookiename $encryption_passphrase]
    if { ($decrypted eq "") } {
      # Cookie wasn't encrypted, delete it
      HTTP::cookie remove $cookiename
    }
  }
}

Using AES::encrypt / AES::decrypt

The HTTP::cookie encrypt / decrypt functions were added in the LTM 9.0 branch, but in early versions, those commands caused system instability. Here is an iRule designed to work around that limitation by instead using the AES::encrypt and AES::decrypt commands along with the HTTP::cookie command to accomplish much the same goal. (It has been modified from its original incarnation to eliminate global variables, thus making it CMP-friendly.)

First we'll use the RULE_INIT event to define a static encryption key (the same for each request, and the same on both units of a redundant pair.), and to define the name of the cookie to encrypt in responses and decrypt in requests. (Note that the key is stored in plaintext in the configuration file.)

In the HTTP_RESPONSE event from the server, check to see if the cookie exists and has a value. Encrypt the original cookie value, URI encode it, and set the cookie to the new value.

On subsequent client requests in the HTTP_REQUEST event you check to see if the cookie is present, with a value. If so, try to URI decode the value. Use the catch command to prevent a TCL error if the decoding fails. Then try to decrypt the URI decoded value. Use catch again to prevent a TCL error if the decryption fails. You can add additional logic to handle the scenarios if the cookie not being present, not decode-able or not-decryptable.

Pretty simple huh?

Check out the original thread here.

Code :

when CLIENT_ACCEPTED {
   # Define an AES encryption key. Valid key lengths are 128, 192, or 256 bits. 
   # You can use a key generator, or create your own using only HEX characters.
   set aes_key "AES 128 63544a5e7178677b45366b41405f2dab"

   # Name of the cookie to encrypt/decrypt
   set cookie"myCookie"

   # Log debug messages to /var/log/ltm?  1=yes, 0=no.
   set cookie_encryption_debug 0
}

when HTTP_RESPONSE {

   # Check if response contains an error cookie with a value
   if {[string length [HTTP::cookie value $cookie]] > 0}{

      # Log the original error cookie value from the app
      if {$cookie_encryption_debug}{log local0. \
         "Response from app contained our cookie: [HTTP::cookie value $cookie]"}

      # Encrypt the cookie value so the client can't change the value
      HTTP::cookie value $cookie [URI::encode [AES::encrypt $aes_key [HTTP::cookie value $cookie]]]

      # Log the encoded and encrypted error cookie value
      if {$cookie_encryption_debug}{log local0. \
        "Encrypted error cookie to: [URI::encode [AES::encrypt $aes_key [HTTP::cookie value $cookie]]]"}
   }
}

when HTTP_REQUEST {
   # If the error cookie exists with any value, for any requested object, try to decrypt it
   if {[string length [HTTP::cookie value $cookie]]}{

      if {$cookie_encryption_debug}{log local0. \
         "Original error cookie value: [HTTP::cookie value $cookie]"}

      # URI decode the value (catching any errors that occur when trying to 
      # decode the cookie value and save the output to cookie_uri_decoded)
      if {not ([catch {URI::decode [HTTP::cookie value $cookie]} cookie_uri_decoded])}{

         # Log that the cookie was URI decoded
         if {$cookie_encryption_debug}{log local0. "\$cookie_uri_decoded was set successfully"}

         # Decrypt the value
         if {not ([catch {AES::decrypt $aes_key $cookie_uri_decoded} cookie_decrypted])}{

            # Log the decrypted cookie value
            if {$cookie_encryption_debug}{log local0. "\$cookie_decrypted: $cookie_decrypted"}
         } else {

            # URI decoded value couldn't be decrypted.
         }
      } else {
         # Cookie value couldn't be URI decoded
      }
   } else {
      # Cookie wasn't present in the request
   }
}
Published Mar 17, 2015
Version 1.0

Was this article helpful?

No CommentsBe the first to comment