encrypted cookie generation and decryption

Problem this snippet solves:

  • AES::key command in RULE_INIT event doesn't have compatibility with CMP
  • generate dynamic cooke to provide http client and encrypted the cookie before providing to client.

How to use this snippet:

Generate key to use in iRule.

when RULE_INIT {
    log local0. "key value : [b64encode [AES::key 256]]"
}

If iRule is saved in BIG-IP, the command is executed and log on /var/log/ltm file.

Rule /Common/aes_key <RULE_INIT>: key value : QUVTIDI1NiAxYTIyZTdlMzMxZDBhYmQ0NTNlYTVlMTJhODdhZThiNTdmMjRiZGUwYjZiNDI1YzYwZmMxNDk0ZjNkYzNlMmRi

The generated key can be used in any iRule, and the key must to keep in secure place (place in iRule only)

when RULE_INIT {
    set static::my_key_256 "QUVTIDI1NiAxYTIyZTdlMzMxZDBhYmQ0NTNlYTVlMTJhODdhZThiNTdmMjRiZGUwYjZiNDI1YzYwZmMxNDk0ZjNkYzNlMmRi"
    set static::my_key $static::my_key_256
}

when HTTP_REQUEST {
    ...
    # cookie encryption with dynamic value 
    set cookie_data "[IP::client_addr]:[clock seconds]:MY_COOKIE"
    set b64_enc_cookie "[b64encode [AES::encrypt [b64decode $static::my_key] $cookie_data]]"    
    HTTP::respond 302 -version 1.1 Location "http://[HTTP::host][HTTP::uri]" Set-Cookie "MyCookie=$b64_enc_cookie"
    ...
    # cookie decryption
    set d_data [AES::decrypt [b64decode $static::my_key] [b64decode [HTTP::cookie MyCookie]]]
    ...
}

Code :

when RULE_INIT {
# key value and select one of key to decipher HTTP Cookie
# 256 bit key 
set static::my_key_256 "QUVTIDI1NiAxYTIyZTdlMzMxZDBhYmQ0NTNlYTVlMTJhODdhZThiNTdmMjRiZGUwYjZiNDI1YzYwZmMxNDk0ZjNkYzNlMmRi"
# Select one of key
set static::my_key $static::my_key_256
log local0. "selected key : $static::my_key"

# cookie life time
set static::cookie_lifetime "600"
# cookie re-generation time before expire
set static::cookie_exp "15"
}

when HTTP_REQUEST {
# Debug log setting
# enable : 1
# disable : 0
set DEBUG 1

# Cookie data : client_IP::MY_COOKIE
# check cookie value is existence
if { [HTTP::cookie MyCookie] ne "" } {

# decrypt cookie data
set d_data [AES::decrypt [b64decode $static::my_key] [b64decode [HTTP::cookie MyCookie]]]
if { $DEBUG } { log local0. "cookie value : [HTTP::cookie MyCookie]" }
if { $DEBUG } { log local0. "decrypted cookie value : $d_data" }

# check decryption status / set dummy value if the decryption was failed (empty string)
if { $d_data ne "" } {
set cookie_data [split $d_data ":"]
} else {
# set dummy data to send new cookie
set cookie_data {0.0.0.0 1458328520 COOKIE_DUM}
if { $DEBUG } { log local0. "decryption faile (by changing key) and set dummy value" }
}
    
if { (([clock seconds] - [lindex $cookie_data 1]) <= ($static::cookie_lifetime - $static::cookie_exp)) && ([lindex $cookie_data 2] eq "MY_COOKIE") } {
if { $DEBUG } { log local0. "allowed request : [HTTP::host][HTTP::uri]" }
    
} else {
# cookie is invalid or expire soon, and set a new cookie
if { $DEBUG } { log local0. "cookie value is invalid or expired and re-generate a new cookie" }
call redirect_with_cookie $DEBUG

}

# HTTP request doesn't have MyCookie
} else {
if { $DEBUG } { log local0. "No MyCookie cookie in HTTP request and generate a new cookie" }
call redirect_with_cookie $DEBUG
}
}

proc redirect_with_cookie args { 
set cookie_data "[IP::client_addr]:[clock seconds]:MY_COOKIE"
set b64_enc_cookie "[b64encode [AES::encrypt [b64decode $static::my_key] $cookie_data]]"
if { $args } { log local0. "new generated cookie : $b64_enc_cookie" }

HTTP::respond 302 -version 1.1 Location "http://[HTTP::host][HTTP::uri]" Set-Cookie "MyCookie=$b64_enc_cookie"
}
Updated Jun 06, 2023
Version 2.0
  • Hi Wonsoo, very nice and neat irule. I have a question, HTTP profiles already allow us to encrypt cookies, we just need to specify the cookie name and passphrase. I am not sure which encryption method is used but probably is enough for the majority of the cases and more efficient. AES command is quite resource demanding for the nature of the operation. Am I missing something? Thanks!