Home


Hot Topics


Download


Tutorials


Multimedia


Community

Login | Register




1st Place Partner Winner

iRule Developer:
Sake Blok

iRule Name:
EncryptOutgoingSoaRequest

iRule Description:
"This iRule makes it possible to dynamically secure SOA traffic to multiple hosts over an insecure network. This is comparing the Common Name listed in the certificate with the host-header in the SOA request. "

Key Challenges:
"Our customer was faced with an infrastructure of many information providers that need to be contacted over an insecure network. They were also faced with many mutations in these information providers. To be able to check all SSL credentials, a virtual and a serverssl profile needs to be created for each and every information provider to be able to verify the common name of each information provider. This would result in a huge (and constant) administrative burdon. This iRule makes it possible to create a general virtual and serverssl profile and let the iRule dynamically check the common name in the certificate against the hostname in the HTTP header of the SOA request."

Alternatives:
"The only alternative available was creating a virtual and serverssl profile for every information provider.
Reduced Costs: This iRule initially saved hundreds of hours that were otherwise needed to configure a serverssl profile for each and every information provider. It also saves many hours needed to handle all the mutations."

How it works:
"When a SOA request comes in, this iRule extracts the hostname from the HTTP header of the request. It will use the server ip address that the SOA request was sent to initiate a SSL session to. When the server presents its certificate, the iRule extracts the Common Name from it and compares the Common Name to the hostname that was extracted from the SOA request earlier. If they do not match, a HTTP message will be sent back to the initiating client informing it about the failure (this is done with a clientside tcp-respond and a tcp-close on the serverside as the http-respond can not be used in the SERVERSSL_HANDSHAKE event). The serverside connection will then be closed."

rule EncryptOutgoingSoaRequest {
when RULE_INIT {
   # Debug off (0), Errors-only(1), On(2) or Verbose(3)
   set ::debug 3
   if { $::debug>=2 } { log local0. "Log level set to $::debug" }
}
when CLIENT_ACCEPTED {
   # Remember the address of the destination SOA server
   set SoaServerIP [IP::local_addr]
   if { $::debug>=3 } { log local0. "$SoaServerIP: Outgoing connection requested" }
}

when HTTP_REQUEST {
   # Extract the hostname of the SOA server from the HTTP request
   # This name will must match the common name in the certificate 
   # of the SOA server when the SSL session is set up.
   set SoaServerName [string tolower [substr [HTTP::host] 0 ":"]]
   if { $::debug>=3 } { log local0. "$SoaServerIP: Hostname = $SoaServerName" }

   # Overrule the dummy address in the default pool of the virtual
   # and change it to the address of the SoaServer. Also change the 
   # destination port from 80 to 443.
   node $SoaServer 443
}

when SERVERSSL_HANDSHAKE {
   # Extract the server certificate from the SOA server ServerHello message
   set SoaServerCert [SSL::cert 0]

   # Extract the common name from the server certificate
   set CommonName [string tolower [findstr [X509::subject $SoaServerCert] "CN=" 3 ","]]
   if { $::debug>=3 } { log local0. "$SoaServerIP: Common Name = $CommonName" }

   if { $CommonName ne $SoaServerName } {
      clientside {TCP::respond "HTTP/1.1 403 WRONG CERTIFICATE\r\n\r\nThe common name $CommonName `
in the certificate at $SoaServerIP does not match to hostname $SoaServerName in the SOA request.\r\n"}
      TCP::close
      if { $::debug>=1 } { log local0. "$SoaServerIP: Name mismatch CN=$CommonName, Hostname=$SoaServerName" }
   } else {
      # Create a log entry for this (successful) request
      if { $::debug>=2 } { log local0. "$SoaServerIP: Request to $SoaServerName successfully forwarded" }
   }
}
} 

iRule Developer:
Sake Blok

iRule Name:
EncryptOutgoingSoaRequest

iRule Description:
"This iRule makes it possible to dynamically secure SOA traffic to multiple hosts over an insecure network. This is comparing the Common Name listed in the certificate with the host-header in the SOA request. "

Key Challenges:
"Our customer was faced with an infrastructure of many information providers that need to be contacted over an insecure network. They were also faced with many mutations in these information providers. To be able to check all SSL credentials, a virtual and a serverssl profile needs to be created for each and every information provider to be able to verify the common name of each information provider. This would result in a huge (and constant) administrative burdon. This iRule makes it possible to create a general virtual and serverssl profile and let the iRule dynamically check the common name in the certificate against the hostname in the HTTP header of the SOA request."

Alternatives:
"The only alternative available was creating a virtual and serverssl profile for every information provider.
Reduced Costs: This iRule initially saved hundreds of hours that were otherwise needed to configure a serverssl profile for each and every information provider. It also saves many hours needed to handle all the mutations."

How it works:
"When a SOA request comes in, this iRule extracts the hostname from the HTTP header of the request. It will use the server ip address that the SOA request was sent to initiate a SSL session to. When the server presents its certificate, the iRule extracts the Common Name from it and compares the Common Name to the hostname that was extracted from the SOA request earlier. If they do not match, a HTTP message will be sent back to the initiating client informing it about the failure (this is done with a clientside tcp-respond and a tcp-close on the serverside as the http-respond can not be used in the SERVERSSL_HANDSHAKE event). The serverside connection will then be closed."

rule EncryptOutgoingSoaRequest {
when RULE_INIT {
   # Debug off (0), Errors-only(1), On(2) or Verbose(3)
   set ::debug 3
   if { $::debug>=2 } { log local0. "Log level set to $::debug" }
}
when CLIENT_ACCEPTED {
   # Remember the address of the destination SOA server
   set SoaServerIP [IP::local_addr]
   if { $::debug>=3 } { log local0. "$SoaServerIP: Outgoing connection requested" }
}

when HTTP_REQUEST {
   # Extract the hostname of the SOA server from the HTTP request
   # This name will must match the common name in the certificate 
   # of the SOA server when the SSL session is set up.
   set SoaServerName [string tolower [substr [HTTP::host] 0 ":"]]
   if { $::debug>=3 } { log local0. "$SoaServerIP: Hostname = $SoaServerName" }

   # Overrule the dummy address in the default pool of the virtual
   # and change it to the address of the SoaServer. Also change the 
   # destination port from 80 to 443.
   node $SoaServer 443
}

when SERVERSSL_HANDSHAKE {
   # Extract the server certificate from the SOA server ServerHello message
   set SoaServerCert [SSL::cert 0]

   # Extract the common name from the server certificate
   set CommonName [string tolower [findstr [X509::subject $SoaServerCert] "CN=" 3 ","]]
   if { $::debug>=3 } { log local0. "$SoaServerIP: Common Name = $CommonName" }

   if { $CommonName ne $SoaServerName } {
      clientside {TCP::respond "HTTP/1.1 403 WRONG CERTIFICATE\r\n\r\nThe common name $CommonName `
in the certificate at $SoaServerIP does not match to hostname $SoaServerName in the SOA request.\r\n"}
      TCP::close
      if { $::debug>=1 } { log local0. "$SoaServerIP: Name mismatch CN=$CommonName, Hostname=$SoaServerName" }
   } else {
      # Create a log entry for this (successful) request
      if { $::debug>=2 } { log local0. "$SoaServerIP: Request to $SoaServerName successfully forwarded" }
   }
}
} 

2nd Place Partner Winner

iRule Developer:
Henrik Gyllkrans

iRule Name:
Cookie Tampering PRevention

iRule Description:
"The iRule prevents cookie tampering by sending along another (encrypted) cookie that contains hashes of all individual cookies. When a request comes in it hashes the incoming cookies and compare the results with the hashes stored in the extra cookie. The idea behind this originated from the ASM, and was developed as an alternative for those that wish to increase security but do not have an ASM."

Key Challenges:
"Since the HTTP protocol is stateless, stateful applications typically keep track of clients with the help of cookies, storing session information or other type of state information about the session. That means that this data is available to the client which can tamper with it. The iRule prevents cookie tampering by keeping track of the data in the cookies sent out and when the data comes back can make sure that the data hasnt been changed by the client."

Alternatives:
"The easy way out to prevent cookie tampering would be to encrypt all cookies, and this would be a good complement to the iRule. But on the odd chance that someone manages to brute force that encryption theres no easy way of telling that this has happened or prevent that it is exploited. Unless you have an ASM. The iRule takes a more thorough approach, since the iRule checks that the values in the cookies hasnt changed since the response was sent to the client."

How it works:
"It should be noted that v10 offers a new feature that this iRule benefits from with the static namespace. That means we only need to define the "system settings" once, when the iRule is initiated. One idea was to create an iRule that would work for both v10 and v9, but it was impractical and a separate version of the iRule was created for v9. In this version the "system setting" varaibles are declared on each TCP connection which isnt optimal but it is better than to sacrifice CMP by using global variables. The iRule can optionally use a Data Group to also verify that the cookies received from a client are approved cookies. The Data Group is simply a list of authorised cookies: class allowed_cookies { { "examplecookie1" "examplecookie2 } } The iRule uses a few static variables for system settings, such as log levels, syslog server and so on. All log messages are sent to a syslog server rather than to file for performance purposes. On a response from the server, the iRule loops through all cookies and performs a hash on the value. The hash is converted to hex string and cookiename/hash is added to a string. The string is inserted as a cookie and encrypted. On a request the iRule first checks if cookie authorisation should be performed and if so it loops through the cookies and compares the names with the Data Group. If a unathorised cookie is found a the connection is dropped and a response is sent to the client informing of the occured (That response isnt very pretty so itll probably need to customised according to each implementation). Next it checks if the hash cookie is present and if so it decrypts the hash cookie. Then it checks that the decryption seems OK and if so loops through the cookies listed in there. For each listed cookie it takes the corresponding cookie from the request and performs the same hash calculation on it as it did on the cookies from the response and then compares the value from the request with the value from the response. If theres a mismatch the connection will again be dropped and a response is sent to the client informing of the occured (again with the requirement to customise the response). If the decryption went wrong its probably due to a tampered hash cookie so it will strip the request from all cookies and send the request to the startpage instead which should start a new session since the client has tampered with this one. If the hash cookie wasnt present but other cookies are the hash cookie has probably been deleted so it will strip all cookies from the request and send it to the startpage as above."

----------------------------------------------------
V10 Version
----------------------------------------------------
when RULE_INIT {
##############################################################################
#
# Cookie tampering prevention iRule
# This is the version 10 variant of the iRule which has a lot better
# than the version 9 due to the introduction of the static namespace.
#
# Setting some variables that controls global behaviour of the iRule.
# The settings are:
#
# debug:      Sets logging level, valid settings are:
#             0 - off
#             1 - logs suspicious activities
#             2 - logs suspicious activities and troubleshooting info
#
# log_host:   All logs are sent to a syslog server for performance purposes,
#             valid settings are an IP-address or a hostname, and an optional
#             port. Example: 192.168.1.1:514.
#
# Checkvalid: Enables/disables the checking of valid cookies which means that
#             on HTTP requests the cookies will be matched against a
#             Data Group, allowed_cookies to see that no unauthorised cookies
#             has been injected. Valid settings are 0 for off or 1 for on.
#
# h_cookie:   The name of the cookie to be inserted into the responses
#             containing the hashes of the other cookies
#
##############################################################################

   set static::debug 2
   set static::log_host "172.31.20.9"
   set static::checkvalid 1
   set static::h_cookie cookiejar

##############################################################################
#
# Set an encryption key with which to encrypt/decrypt the cookie sent to the
# client.
#
##############################################################################

   binary scan "1234567890" H* static::key

}
when HTTP_RESPONSE {

##############################################################################
#
# Make individual hashes of values contained in all cookies and put it in a
# list separated by spaces. The hash contains special characters that causes
# problems so it will be converted to a hex string instead.
#
##############################################################################

   foreach c_name [HTTP::cookie names] {
      binary scan [md5 [HTTP::cookie $c_name]] H* hexhash
      append cookie_hash $c_name " " $hexhash " "
      if { $static::debug == 2 }{
         log $static::log_host local0. "[IP::client_addr]: Response cookie processing: $cookie_hash"
      }
   }

##############################################################################
#
# Insert the list as a cookie and encrypt it
#
##############################################################################

   if { $static::debug ==2 }{
      log $static::log_host local0.info "[IP::client_addr]: Setting cookie, value: $cookie_hash"
   }
   HTTP::cookie insert name $static::h_cookie value $cookie_hash
   HTTP::cookie encrypt $static::h_cookie $static::key
}
when HTTP_REQUEST {

##############################################################################
#
# Check if cookies are valid, depending on the checkvalid-variable.
#
##############################################################################

   if {$static::checkvalid}{
      if { $static::debug == 2}{
         log $static::log_host local0.info "[IP::client_addr]: Checking valid cookies"
      }
      foreach c_name [HTTP::cookie names] {
         if { !([matchclass $::allowed_cookies contains $c_name] || $c_name equals $static::h_cookie) }{
            HTTP::respond 200 content "Cookie injection detected, the offending cookie $c_name caused an error."
            if {$static::debug}{
               log $static::log_host local0.info `
"Cookie injection detected, cookie $c_name sent from [IP::client_addr]"
            }
            TCP::close
            return
         }
      }
   }

##############################################################################
#
# Decrypt the cookie and assign it to a variable
#
##############################################################################

   if { [HTTP::cookie exists $static::h_cookie] }{
      set d_cookie [HTTP::cookie decrypt $static::h_cookie $static::key]

      if { $static::debug == 2 }{
         log $static::log_host local0. "[IP::client_addr]: Verifying request cookies, `
encrypted cookie: [HTTP::cookie $static::h_cookie], decrypted: $d_cookie"
      }

##############################################################################
#
# Make sure that the cookie was decrypted properly
#
##############################################################################

      if { !($d_cookie equals "") }{

##############################################################################
#
# Loop through the cookies in the request
#
##############################################################################

         foreach {c_name c_value} $d_cookie {
            if { $static::debug == 2 }{
               log $static::log_host local0. `
"[IP::client_addr]: Cookie - $c_name, value - [HTTP::cookie $c_name], stored hash - $c_value"
            }

##############################################################################
#
# Make a hash of the present cookie and turn it to hex and compare the result
# with the hexed hash from the hash cookie.
#
##############################################################################

            binary scan [md5 [HTTP::cookie $c_name]] H* hexhash
            if { !($c_value equals $hexhash)}{
               HTTP::respond 200 content `
"Cookie tampering detected, offending cookie $c_name did not match original content."
               if {$static::debug}{
                  log $static::log_host local0.info `
"Cookie tampering detected, offending cookie $c_name sent from [IP::client_addr]"
               }
               TCP::close
               return
            }
         }
      }
      else {

##############################################################################
#
# The hash cookie did not decrypt properly so that means someone has tampered
# with the hash cookie itself, probably to cirumvent the tampering prevention.
# To combat this all cookies will be removed and the request will be rewritten
# to the start page, thereby dropping the current session and starting a new.
#
##############################################################################

         if {$static::debug}{
            log $static::log_host local0.info `
"Request with tampered hash cookie sent from [IP::client_addr], dropping session."
         }
         foreach c_name [HTTP::cookie names] {
            HTTP::cookie remove $c_name
         }

##############################################################################
#
# Make sure that the following URI is to the startpage of the application
#
##############################################################################

         HTTP::uri /
      }

##############################################################################
#
# Clean up the request before it is forwarded to the server
#
##############################################################################

      HTTP::cookie remove $static::h_cookie
   }
   elseif { [HTTP::cookie count] }{

##############################################################################
#
# The hash cookie is not present but other cookies are. The most probable
# explanation is that the user deleted the hash cookie to circumvent the
# tampering prevention. To combat this all cookies will be removed an the
# request will be rewritten to the startpage, as with the tampered hash cookie
# above.
#
##############################################################################

      if {$static::debug}{
         log $static::log_host local0.info `
"Request with missing hash cookie sent from [IP::client_addr], dropping session."
      }
      foreach c_name [HTTP::cookie names] {
         HTTP::cookie remove $c_name
      }

##############################################################################
#
# Make sure that the following URI is to the startpage of the application
#
##############################################################################

      HTTP::uri /
   }
}
----------------------------------------------------
V9 Version
----------------------------------------------------
when CLIENT_ACCEPTED {
##############################################################################
#
# Cookie tampering prevention iRule
# This is the version 9 variant, which a bit less efficient than the v10
# variant. To convert it to v10, change the CLIENT_ACCEPTED event to RULE_INIT
# and put all the variables defined in this event in the static namespace
#
# Setting some variables that controls global behaviour of the iRule.
# The settings are:
#
# debug:      Sets logging level, valid settings are:
#             0 - off
#             1 - logs suspicious activities
#             2 - logs suspicious activities and troubleshooting info
#
# log_host:   All logs are sent to a syslog server for performance purposes,
#             valid settings are an IP-address or a hostname, and an optional
#             port. Example: 192.168.1.1:514.
#
# Checkvalid: Enables/disables the checking of valid cookies which means that
#             on HTTP requests the cookies will be matched against a
#             Data Group, allowed_cookies to see that no unauthorised cookies
#             has been injected. Valid settings are 0 for off or 1 for on.
#
# h_cookie:   The name of the cookie to be inserted into the responses
#             containing the hashes of the other cookies
#
##############################################################################

   set debug 2
   set log_host "172.31.20.9"
   set checkvalid 1
   set h_cookie cookiejar

##############################################################################
#
# Set an encryption key with which to encrypt/decrypt the cookie sent to the
# client.
#
##############################################################################

   binary scan "1234567890" H* key

}
when HTTP_RESPONSE {

##############################################################################
#
# Make individual hashes of values contained in all cookies and put it in a
# list separated by spaces. The hash contains special characters that causes
# problems so it will be converted to a hex string instead.
#
##############################################################################

   foreach c_name [HTTP::cookie names] {
      binary scan [md5 [HTTP::cookie $c_name]] H* hexhash
      append cookie_hash $c_name " " $hexhash " "
      if { $debug == 2 }{
         log $log_host local0. "[IP::client_addr]: Response cookie processing: $cookie_hash"
      }
   }

##############################################################################
#
# Insert the list as a cookie and encrypt it
#
##############################################################################

   if { $debug ==2 }{
      log $log_host local0.info "[IP::client_addr]: Setting cookie, value: $cookie_hash"
   }
   HTTP::cookie insert name $h_cookie value $cookie_hash
   HTTP::cookie encrypt $h_cookie $key
}
when HTTP_REQUEST {

##############################################################################
#
# Check if cookies are valid, depending on the checkvalid-variable.
#
##############################################################################

   if {$checkvalid}{
      if { $debug == 2}{
         log $log_host local0.info "[IP::client_addr]: Checking valid cookies"
      }
      foreach c_name [HTTP::cookie names] {
         if { !([matchclass $::allowed_cookies contains $c_name] || $c_name equals $h_cookie) }{
            HTTP::respond 200 content `
"Cookie injection detected, the offending cookie $c_name caused an error. Please contact an administrator."
            if {$debug}{
               log $log_host local0.info `
"Cookie injection detected, offending cookie $c_name sent from [IP::client_addr]"
            }
            TCP::close
            return
         }
      }
   }

##############################################################################
#
# Decrypt the cookie and assign it to a variable
#
##############################################################################

   if { [HTTP::cookie exists $h_cookie] }{
      set d_cookie [HTTP::cookie decrypt $h_cookie $key]

      if { $debug == 2 }{
         log $log_host local0. `
"[IP::client_addr]: Verifying request cookies, encrypted cookie: [HTTP::cookie $h_cookie], decrypted: $d_cookie"
      }

##############################################################################
#
# Make sure that the cookie was decrypted properly
#
##############################################################################

      if { !($d_cookie equals "") }{

##############################################################################
#
# Loop through the cookies in the request
#
##############################################################################

         foreach {c_name c_value} $d_cookie {
            if { $debug == 2 }{
               log $log_host local0. `
"[IP::client_addr]: Cookie - $c_name, value - [HTTP::cookie $c_name], stored hash - $c_value"
            }

##############################################################################
#
# Make a hash of the present cookie and turn it to hex and compare the result
# with the hexed hash from the hash cookie.
#
##############################################################################

            binary scan [md5 [HTTP::cookie $c_name]] H* hexhash
            if { !($c_value equals $hexhash)}{
               HTTP::respond 200 content `
"Cookie tampering detected, offending cookie $c_name did not match original content. Please contact an administrator."
               if {$debug}{
                  log $log_host local0.info `
"Cookie tampering detected, offending cookie $c_name sent from [IP::client_addr]"
               }
               TCP::close
               return
            }
         }
      }
      else {

##############################################################################
#
# The hash cookie did not decrypt properly so that means someone has tampered
# with the hash cookie itself, probably to cirumvent the tampering prevention.
# To combat this all cookies will be removed and the request will be rewritten
# to the start page, thereby dropping the current session and starting a new.
#
##############################################################################

         if {$debug}{
            log $log_host local0.info `
"Request with tampered hash cookie sent from [IP::client_addr], dropping session."
         }
         foreach c_name [HTTP::cookie names] {
            HTTP::cookie remove $c_name
         }

##############################################################################
#
# Make sure that the following URI is to the startpage of the application
#
##############################################################################

         HTTP::uri /
      }

##############################################################################
#
# Clean up the request before it is forwarded to the server
#
##############################################################################

      HTTP::cookie remove $h_cookie
   }
   elseif { [HTTP::cookie count] }{

##############################################################################
#
# The hash cookie is not present but other cookies are. The most probable
# explanation is that the user deleted the hash cookie to circumvent the
# tampering prevention. To combat this all cookies will be removed an the
# request will be rewritten to the startpage, as with the tampered hash cookie
# above.
#
##############################################################################

      if {$debug}{
         log $log_host local0.info `
"Request with missing hash cookie sent from [IP::client_addr], dropping session."
      }
      foreach c_name [HTTP::cookie names] {
         HTTP::cookie remove $c_name
      }

##############################################################################
#
# Make sure that the following URI is to the startpage of the application
#
##############################################################################

      HTTP::uri /
   }
}

iRule Developer:
Henrik Gyllkrans

iRule Name:
Cookie Tampering PRevention

iRule Description:
"The iRule prevents cookie tampering by sending along another (encrypted) cookie that contains hashes of all individual cookies. When a request comes in it hashes the incoming cookies and compare the results with the hashes stored in the extra cookie. The idea behind this originated from the ASM, and was developed as an alternative for those that wish to increase security but do not have an ASM."

Key Challenges:
"Since the HTTP protocol is stateless, stateful applications typically keep track of clients with the help of cookies, storing session information or other type of state information about the session. That means that this data is available to the client which can tamper with it. The iRule prevents cookie tampering by keeping track of the data in the cookies sent out and when the data comes back can make sure that the data hasnt been changed by the client."

Alternatives:
"The easy way out to prevent cookie tampering would be to encrypt all cookies, and this would be a good complement to the iRule. But on the odd chance that someone manages to brute force that encryption theres no easy way of telling that this has happened or prevent that it is exploited. Unless you have an ASM. The iRule takes a more thorough approach, since the iRule checks that the values in the cookies hasnt changed since the response was sent to the client."

How it works:
"It should be noted that v10 offers a new feature that this iRule benefits from with the static namespace. That means we only need to define the "system settings" once, when the iRule is initiated. One idea was to create an iRule that would work for both v10 and v9, but it was impractical and a separate version of the iRule was created for v9. In this version the "system setting" varaibles are declared on each TCP connection which isnt optimal but it is better than to sacrifice CMP by using global variables. The iRule can optionally use a Data Group to also verify that the cookies received from a client are approved cookies. The Data Group is simply a list of authorised cookies: class allowed_cookies { { "examplecookie1" "examplecookie2 } } The iRule uses a few static variables for system settings, such as log levels, syslog server and so on. All log messages are sent to a syslog server rather than to file for performance purposes. On a response from the server, the iRule loops through all cookies and performs a hash on the value. The hash is converted to hex string and cookiename/hash is added to a string. The string is inserted as a cookie and encrypted. On a request the iRule first checks if cookie authorisation should be performed and if so it loops through the cookies and compares the names with the Data Group. If a unathorised cookie is found a the connection is dropped and a response is sent to the client informing of the occured (That response isnt very pretty so itll probably need to customised according to each implementation). Next it checks if the hash cookie is present and if so it decrypts the hash cookie. Then it checks that the decryption seems OK and if so loops through the cookies listed in there. For each listed cookie it takes the corresponding cookie from the request and performs the same hash calculation on it as it did on the cookies from the response and then compares the value from the request with the value from the response. If theres a mismatch the connection will again be dropped and a response is sent to the client informing of the occured (again with the requirement to customise the response). If the decryption went wrong its probably due to a tampered hash cookie so it will strip the request from all cookies and send the request to the startpage instead which should start a new session since the client has tampered with this one. If the hash cookie wasnt present but other cookies are the hash cookie has probably been deleted so it will strip all cookies from the request and send it to the startpage as above."

----------------------------------------------------
V10 Version
----------------------------------------------------
when RULE_INIT {
##############################################################################
#
# Cookie tampering prevention iRule
# This is the version 10 variant of the iRule which has a lot better
# than the version 9 due to the introduction of the static namespace.
#
# Setting some variables that controls global behaviour of the iRule.
# The settings are:
#
# debug:      Sets logging level, valid settings are:
#             0 - off
#             1 - logs suspicious activities
#             2 - logs suspicious activities and troubleshooting info
#
# log_host:   All logs are sent to a syslog server for performance purposes,
#             valid settings are an IP-address or a hostname, and an optional
#             port. Example: 192.168.1.1:514.
#
# Checkvalid: Enables/disables the checking of valid cookies which means that
#             on HTTP requests the cookies will be matched against a
#             Data Group, allowed_cookies to see that no unauthorised cookies
#             has been injected. Valid settings are 0 for off or 1 for on.
#
# h_cookie:   The name of the cookie to be inserted into the responses
#             containing the hashes of the other cookies
#
##############################################################################

   set static::debug 2
   set static::log_host "172.31.20.9"
   set static::checkvalid 1
   set static::h_cookie cookiejar

##############################################################################
#
# Set an encryption key with which to encrypt/decrypt the cookie sent to the
# client.
#
##############################################################################

   binary scan "1234567890" H* static::key

}
when HTTP_RESPONSE {

##############################################################################
#
# Make individual hashes of values contained in all cookies and put it in a
# list separated by spaces. The hash contains special characters that causes
# problems so it will be converted to a hex string instead.
#
##############################################################################

   foreach c_name [HTTP::cookie names] {
      binary scan [md5 [HTTP::cookie $c_name]] H* hexhash
      append cookie_hash $c_name " " $hexhash " "
      if { $static::debug == 2 }{
         log $static::log_host local0. "[IP::client_addr]: Response cookie processing: $cookie_hash"
      }
   }

##############################################################################
#
# Insert the list as a cookie and encrypt it
#
##############################################################################

   if { $static::debug ==2 }{
      log $static::log_host local0.info "[IP::client_addr]: Setting cookie, value: $cookie_hash"
   }
   HTTP::cookie insert name $static::h_cookie value $cookie_hash
   HTTP::cookie encrypt $static::h_cookie $static::key
}
when HTTP_REQUEST {

##############################################################################
#
# Check if cookies are valid, depending on the checkvalid-variable.
#
##############################################################################

   if {$static::checkvalid}{
      if { $static::debug == 2}{
         log $static::log_host local0.info "[IP::client_addr]: Checking valid cookies"
      }
      foreach c_name [HTTP::cookie names] {
         if { !([matchclass $::allowed_cookies contains $c_name] || $c_name equals $static::h_cookie) }{
            HTTP::respond 200 content "Cookie injection detected, the offending cookie $c_name caused an error."
            if {$static::debug}{
               log $static::log_host local0.info `
"Cookie injection detected, cookie $c_name sent from [IP::client_addr]"
            }
            TCP::close
            return
         }
      }
   }

##############################################################################
#
# Decrypt the cookie and assign it to a variable
#
##############################################################################

   if { [HTTP::cookie exists $static::h_cookie] }{
      set d_cookie [HTTP::cookie decrypt $static::h_cookie $static::key]

      if { $static::debug == 2 }{
         log $static::log_host local0. "[IP::client_addr]: Verifying request cookies, `
encrypted cookie: [HTTP::cookie $static::h_cookie], decrypted: $d_cookie"
      }

##############################################################################
#
# Make sure that the cookie was decrypted properly
#
##############################################################################

      if { !($d_cookie equals "") }{

##############################################################################
#
# Loop through the cookies in the request
#
##############################################################################

         foreach {c_name c_value} $d_cookie {
            if { $static::debug == 2 }{
               log $static::log_host local0. `
"[IP::client_addr]: Cookie - $c_name, value - [HTTP::cookie $c_name], stored hash - $c_value"
            }

##############################################################################
#
# Make a hash of the present cookie and turn it to hex and compare the result
# with the hexed hash from the hash cookie.
#
##############################################################################

            binary scan [md5 [HTTP::cookie $c_name]] H* hexhash
            if { !($c_value equals $hexhash)}{
               HTTP::respond 200 content `
"Cookie tampering detected, offending cookie $c_name did not match original content."
               if {$static::debug}{
                  log $static::log_host local0.info `
"Cookie tampering detected, offending cookie $c_name sent from [IP::client_addr]"
               }
               TCP::close
               return
            }
         }
      }
      else {

##############################################################################
#
# The hash cookie did not decrypt properly so that means someone has tampered
# with the hash cookie itself, probably to cirumvent the tampering prevention.
# To combat this all cookies will be removed and the request will be rewritten
# to the start page, thereby dropping the current session and starting a new.
#
##############################################################################

         if {$static::debug}{
            log $static::log_host local0.info `
"Request with tampered hash cookie sent from [IP::client_addr], dropping session."
         }
         foreach c_name [HTTP::cookie names] {
            HTTP::cookie remove $c_name
         }

##############################################################################
#
# Make sure that the following URI is to the startpage of the application
#
##############################################################################

         HTTP::uri /
      }

##############################################################################
#
# Clean up the request before it is forwarded to the server
#
##############################################################################

      HTTP::cookie remove $static::h_cookie
   }
   elseif { [HTTP::cookie count] }{

##############################################################################
#
# The hash cookie is not present but other cookies are. The most probable
# explanation is that the user deleted the hash cookie to circumvent the
# tampering prevention. To combat this all cookies will be removed an the
# request will be rewritten to the startpage, as with the tampered hash cookie
# above.
#
##############################################################################

      if {$static::debug}{
         log $static::log_host local0.info `
"Request with missing hash cookie sent from [IP::client_addr], dropping session."
      }
      foreach c_name [HTTP::cookie names] {
         HTTP::cookie remove $c_name
      }

##############################################################################
#
# Make sure that the following URI is to the startpage of the application
#
##############################################################################

      HTTP::uri /
   }
}
----------------------------------------------------
V9 Version
----------------------------------------------------
when CLIENT_ACCEPTED {
##############################################################################
#
# Cookie tampering prevention iRule
# This is the version 9 variant, which a bit less efficient than the v10
# variant. To convert it to v10, change the CLIENT_ACCEPTED event to RULE_INIT
# and put all the variables defined in this event in the static namespace
#
# Setting some variables that controls global behaviour of the iRule.
# The settings are:
#
# debug:      Sets logging level, valid settings are:
#             0 - off
#             1 - logs suspicious activities
#             2 - logs suspicious activities and troubleshooting info
#
# log_host:   All logs are sent to a syslog server for performance purposes,
#             valid settings are an IP-address or a hostname, and an optional
#             port. Example: 192.168.1.1:514.
#
# Checkvalid: Enables/disables the checking of valid cookies which means that
#             on HTTP requests the cookies will be matched against a
#             Data Group, allowed_cookies to see that no unauthorised cookies
#             has been injected. Valid settings are 0 for off or 1 for on.
#
# h_cookie:   The name of the cookie to be inserted into the responses
#             containing the hashes of the other cookies
#
##############################################################################

   set debug 2
   set log_host "172.31.20.9"
   set checkvalid 1
   set h_cookie cookiejar

##############################################################################
#
# Set an encryption key with which to encrypt/decrypt the cookie sent to the
# client.
#
##############################################################################

   binary scan "1234567890" H* key

}
when HTTP_RESPONSE {

##############################################################################
#
# Make individual hashes of values contained in all cookies and put it in a
# list separated by spaces. The hash contains special characters that causes
# problems so it will be converted to a hex string instead.
#
##############################################################################

   foreach c_name [HTTP::cookie names] {
      binary scan [md5 [HTTP::cookie $c_name]] H* hexhash
      append cookie_hash $c_name " " $hexhash " "
      if { $debug == 2 }{
         log $log_host local0. "[IP::client_addr]: Response cookie processing: $cookie_hash"
      }
   }

##############################################################################
#
# Insert the list as a cookie and encrypt it
#
##############################################################################

   if { $debug ==2 }{
      log $log_host local0.info "[IP::client_addr]: Setting cookie, value: $cookie_hash"
   }
   HTTP::cookie insert name $h_cookie value $cookie_hash
   HTTP::cookie encrypt $h_cookie $key
}
when HTTP_REQUEST {

##############################################################################
#
# Check if cookies are valid, depending on the checkvalid-variable.
#
##############################################################################

   if {$checkvalid}{
      if { $debug == 2}{
         log $log_host local0.info "[IP::client_addr]: Checking valid cookies"
      }
      foreach c_name [HTTP::cookie names] {
         if { !([matchclass $::allowed_cookies contains $c_name] || $c_name equals $h_cookie) }{
            HTTP::respond 200 content `
"Cookie injection detected, the offending cookie $c_name caused an error. Please contact an administrator."
            if {$debug}{
               log $log_host local0.info `
"Cookie injection detected, offending cookie $c_name sent from [IP::client_addr]"
            }
            TCP::close
            return
         }
      }
   }

##############################################################################
#
# Decrypt the cookie and assign it to a variable
#
##############################################################################

   if { [HTTP::cookie exists $h_cookie] }{
      set d_cookie [HTTP::cookie decrypt $h_cookie $key]

      if { $debug == 2 }{
         log $log_host local0. `
"[IP::client_addr]: Verifying request cookies, encrypted cookie: [HTTP::cookie $h_cookie], decrypted: $d_cookie"
      }

##############################################################################
#
# Make sure that the cookie was decrypted properly
#
##############################################################################

      if { !($d_cookie equals "") }{

##############################################################################
#
# Loop through the cookies in the request
#
##############################################################################

         foreach {c_name c_value} $d_cookie {
            if { $debug == 2 }{
               log $log_host local0. `
"[IP::client_addr]: Cookie - $c_name, value - [HTTP::cookie $c_name], stored hash - $c_value"
            }

##############################################################################
#
# Make a hash of the present cookie and turn it to hex and compare the result
# with the hexed hash from the hash cookie.
#
##############################################################################

            binary scan [md5 [HTTP::cookie $c_name]] H* hexhash
            if { !($c_value equals $hexhash)}{
               HTTP::respond 200 content `
"Cookie tampering detected, offending cookie $c_name did not match original content. Please contact an administrator."
               if {$debug}{
                  log $log_host local0.info `
"Cookie tampering detected, offending cookie $c_name sent from [IP::client_addr]"
               }
               TCP::close
               return
            }
         }
      }
      else {

##############################################################################
#
# The hash cookie did not decrypt properly so that means someone has tampered
# with the hash cookie itself, probably to cirumvent the tampering prevention.
# To combat this all cookies will be removed and the request will be rewritten
# to the start page, thereby dropping the current session and starting a new.
#
##############################################################################

         if {$debug}{
            log $log_host local0.info `
"Request with tampered hash cookie sent from [IP::client_addr], dropping session."
         }
         foreach c_name [HTTP::cookie names] {
            HTTP::cookie remove $c_name
         }

##############################################################################
#
# Make sure that the following URI is to the startpage of the application
#
##############################################################################

         HTTP::uri /
      }

##############################################################################
#
# Clean up the request before it is forwarded to the server
#
##############################################################################

      HTTP::cookie remove $h_cookie
   }
   elseif { [HTTP::cookie count] }{

##############################################################################
#
# The hash cookie is not present but other cookies are. The most probable
# explanation is that the user deleted the hash cookie to circumvent the
# tampering prevention. To combat this all cookies will be removed an the
# request will be rewritten to the startpage, as with the tampered hash cookie
# above.
#
##############################################################################

      if {$debug}{
         log $log_host local0.info `
"Request with missing hash cookie sent from [IP::client_addr], dropping session."
      }
      foreach c_name [HTTP::cookie names] {
         HTTP::cookie remove $c_name
      }

##############################################################################
#
# Make sure that the following URI is to the startpage of the application
#
##############################################################################

      HTTP::uri /
   }
}

3rd Place Partner Winner

iRule Developer:
Levin Chen

Rule Name:
iRules_deny_repeat_login_ok 

iRule Description:
"When the usb key is pulled out, due to IE does not shut down an application exception. Users hope that the new usb key to prompt the user to switch off before use IE, so that access to the normal." 

Key Challenges:
"To prevent the same user login on the second." 

Alternatives:
"No solution." 

Reduced Costs:
"Reduce duplication Sign losses." 

How it works:
"When the user first login on, get the user serial number, will be posted mark set to 1, if the user login on again to stop, but if the new user can continue to login on." 

rule iRules_deny_repeat_login_ok {
   when RULE_INIT {
  set allzeros [string repeat "0" 64]
}

when CLIENTSSL_CLIENTCERT {
  set cert [SSL::cert 0]
  set sid [SSL::sessionid]
  if { $sid ne $::allzeros } {
    # If this SSL session will be cached, then it may be
    # resumed later on a new connection. Cache the cert
    # in the session table in case that happens. Because IDs
    # are not globally unique, the session id needs to be combined 
    # with something from client address to avoid mismatch.  
    set key [concat [IP::remote_addr]@$sid]
    session add ssl $key $cert 180
  }
}

when HTTP_REQUEST {
  if { [info exists cert] } {
    set sn [X509::serial_number $cert]
  } else {
    set sid [SSL::sessionid]
    # We dont have a cert, possibly because this is
    # a new connection that was a resumption of a
    # previous SSL session. If that is the reason,
    # the cert will be in the session table.
    if { $sid ne $::allzeros } {
      # This SSL session was resumed; retreive the cached cert
      set key [concat [IP::remote_addr]@$sid]
      set cert [session lookup ssl $key]
      if { $cert != "" } {
          set sn [X509::serial_number $cert]
      } else {
          # dunno how this happened
          # session overtime, redirect to login pages.
          #reject
          HTTP::respond 200 content {
          
           
          
          }

          return
      }
    }
  }
  if { [info exists sn] } {
    set client_sign [concat "[SSL::sessionid]RELOGON[IP::remote_addr]"]
    set login_sign [session lookup uie $client_sign]

    #user logout, login_sign change to 0
    if {[matchclass [HTTP::uri] equals $::signoff]} {
        #session add uie $client_sign 0 1800
    }
  
    #login_sign == "", user access first
    #for user login_sign change to 1
    if {$login_sign == ""} {
        if {[matchclass [HTTP::uri] equals $::login_uri]} {
            session add uie $client_sign 1 1800
        }
    }
    else {
      #login_sing != "", user access no first
      if {$login_sign == 1} {
        if {[matchclass [HTTP::uri] equals $::login_uri]} {
          HTTP::redirect "http://bbs.sinogrid.com/Error401.htm"
          return
          #User repeat login, deny
        }
      }
      else {
        HTTP::redirect "http://bbs.sinogrid.com/Error403-7.htm"
        return
        #User already logout, deny
      }
    }

    # Dont allow data to be chunked
    if { [HTTP::version] eq "1.1" } {
      if { [HTTP::header is_keepalive] } {
        HTTP::header replace "Connection" "Keep-Alive"
      }
      HTTP::version "1.0"
    }

    # Insert client cert to http header for app check user
    HTTP::header insert "SSLClientCert" [X509::whole $cert]
  }
}

when HTTP_RESPONSE {
  if { [HTTP::status] contains "302"} {
    if { [HTTP::header location] starts_with "http://" } {
      #Change [HTTP::header location] "http://" to "https://"
      set newLoc [string map {http https} [HTTP::header location] ]
      HTTP::header replace location "$newLoc"
    }
  }
}
}

iRule Developer:
Levin Chen

Rule Name:
iRules_deny_repeat_login_ok 

iRule Description:
"When the usb key is pulled out, due to IE does not shut down an application exception. Users hope that the new usb key to prompt the user to switch off before use IE, so that access to the normal." 

Key Challenges:
"To prevent the same user login on the second." 

Alternatives:
"No solution." 

Reduced Costs:
"Reduce duplication Sign losses." 

How it works:
"When the user first login on, get the user serial number, will be posted mark set to 1, if the user login on again to stop, but if the new user can continue to login on." 

rule iRules_deny_repeat_login_ok {
   when RULE_INIT {
  set allzeros [string repeat "0" 64]
}

when CLIENTSSL_CLIENTCERT {
  set cert [SSL::cert 0]
  set sid [SSL::sessionid]
  if { $sid ne $::allzeros } {
    # If this SSL session will be cached, then it may be
    # resumed later on a new connection. Cache the cert
    # in the session table in case that happens. Because IDs
    # are not globally unique, the session id needs to be combined 
    # with something from client address to avoid mismatch.  
    set key [concat [IP::remote_addr]@$sid]
    session add ssl $key $cert 180
  }
}

when HTTP_REQUEST {
  if { [info exists cert] } {
    set sn [X509::serial_number $cert]
  } else {
    set sid [SSL::sessionid]
    # We dont have a cert, possibly because this is
    # a new connection that was a resumption of a
    # previous SSL session. If that is the reason,
    # the cert will be in the session table.
    if { $sid ne $::allzeros } {
      # This SSL session was resumed; retreive the cached cert
      set key [concat [IP::remote_addr]@$sid]
      set cert [session lookup ssl $key]
      if { $cert != "" } {
          set sn [X509::serial_number $cert]
      } else {
          # dunno how this happened
          # session overtime, redirect to login pages.
          #reject
          HTTP::respond 200 content {
          
           
          
          }

          return
      }
    }
  }
  if { [info exists sn] } {
    set client_sign [concat "[SSL::sessionid]RELOGON[IP::remote_addr]"]
    set login_sign [session lookup uie $client_sign]

    #user logout, login_sign change to 0
    if {[matchclass [HTTP::uri] equals $::signoff]} {
        #session add uie $client_sign 0 1800
    }
  
    #login_sign == "", user access first
    #for user login_sign change to 1
    if {$login_sign == ""} {
        if {[matchclass [HTTP::uri] equals $::login_uri]} {
            session add uie $client_sign 1 1800
        }
    }
    else {
      #login_sing != "", user access no first
      if {$login_sign == 1} {
        if {[matchclass [HTTP::uri] equals $::login_uri]} {
          HTTP::redirect "http://bbs.sinogrid.com/Error401.htm"
          return
          #User repeat login, deny
        }
      }
      else {
        HTTP::redirect "http://bbs.sinogrid.com/Error403-7.htm"
        return
        #User already logout, deny
      }
    }

    # Dont allow data to be chunked
    if { [HTTP::version] eq "1.1" } {
      if { [HTTP::header is_keepalive] } {
        HTTP::header replace "Connection" "Keep-Alive"
      }
      HTTP::version "1.0"
    }

    # Insert client cert to http header for app check user
    HTTP::header insert "SSLClientCert" [X509::whole $cert]
  }
}

when HTTP_RESPONSE {
  if { [HTTP::status] contains "302"} {
    if { [HTTP::header location] starts_with "http://" } {
      #Change [HTTP::header location] "http://" to "https://"
      set newLoc [string map {http https} [HTTP::header location] ]
      HTTP::header replace location "$newLoc"
    }
  }
}
}