Forum Discussion

elandreth_29975's avatar
elandreth_29975
Icon for Nimbostratus rankNimbostratus
Apr 16, 2019

irule to mark cookies httponly/secure - selectively

Hello iRule Wizards,

I have an irule that I've grabbed off of devcentral to flag all cookies as secure/httponly. I want to continue flagging all cookies with secure/httponly but only if the cookie doesn't start with XYZ. Here's the rule from devcentral. Any suggestions?

 This irule is only necessary in version 12.x and lower to add secure and http flag to cookies. 
when CLIENT_ACCEPTED {
    set httpsVs [PROFILE::exists clientssl]
     to determine whether the connection is via an HTTP or HTTPS VS
     it can be done with [SSL::cert count] and catch in HTTP_RESPONSE
     event, but there would have been a bigger perfomance impact 
}
when HTTP_RESPONSE {
   set setckval [HTTP::header values "Set-Cookie"]
   HTTP::header remove "Set-Cookie"
    this command removes all cookies from the responce, so we have to remove and then 
    re-insert in any case (rather then do it selectively on an as-needed per-cookie basis)
   foreach cookie1 $setckval {
    set cookie1 [string trimright [string trimright $cookie1] ";"]
     to avoid obtaining multiple semicolons (e.g. ";;Secure" or "; ;Secure") in the output
     if the orginal cookie had a trailing semicolon, possibly, followed by spaces
     trailing semicolons, strictly saying, do not meet rules described in RFC 2965 
     but there are reports of applications using them (e.g. Cisco Bug: CSCso95114)
    set list1 [lrange [split $cookie1 ";"] 1 end]
     the first field (cookie name=value pair) is skipped to ensure that even cookies
     that happen to have names "httponly" or "secure" are processed properly
    set hasHttpOnly false
    if { $httpsVs } { set hasSecure false   }
    else { set hasSecure true }  
    i.e. insertion of "Secure" is disabled for non-HTTPS VSs
    foreach item1 $list1 {
       set titem1 [string tolower [string trim $item1]]
        accordring to RFC 2965 leading and trailing WSP characters in atrributes 
        should be ignored and attributes should be treated as case-insensitive;
       if { ($titem1 eq "httponly") or  ($titem1 starts_with "httponly=") } {
        set hasHttpOnly true
       }
       if { ($titem1 eq "secure") or ($titem1 starts_with "secure=")} {
        set hasSecure true
       }
    }
    if { not $hasHttpOnly } {
        set cookie1 "${cookie1}; Httponly"
        log local0. "Missing Httponly attribute is being added to cookie: $cookie1"
    }   
    if { not $hasSecure } {
        set cookie1 "${cookie1}; Secure"
        log local0. "Missing Secure attribute is being added to cookie: $cookie1"
    }
    log local0. "The following cookie is being rewritten: $cookie1"
    HTTP::header insert "Set-Cookie" $cookie1
   }
}

2 Replies

  • JG's avatar
    JG
    Icon for Cumulonimbus rankCumulonimbus

    Which version of BIG-IP are you running?

     

  • Hi Elandreth,

     

    the iRule is slightly complicated but it should work fine.

     

    To add the skip functionality to the iRule you will need to replace the part below...

     

        re-insert in any case (rather then do it selectively on an as-needed per-cookie basis)
       foreach cookie1 $setckval {
        set cookie1 [string trimright [string trimright $cookie1] ";"]

    ... with the code below ...

     

        re-insert in any case (rather then do it selectively on an as-needed per-cookie basis)
       foreach cookie1 $setckval {
        if { $cookie1 starts_with "XYZ" } then {
            HTTP::header insert "Set-Cookie" $cookie1
            break
        }
        set cookie1 [string trimright [string trimright $cookie1] ";"]

    You could also use the quickly written iRule below. Its does the same as the iRule above but using a less complicated syntax...

     

    when CLIENT_ACCEPTED {
        set is_ssl [PROFILE::exists clientssl]
    }
    when HTTP_RESPONSE {
        set cookie_list [HTTP::header values "Set-Cookie"]
        HTTP::header remove "Set-Cookie"
        if { $is_ssl } then {
            foreach cookie $cookie_list {
                switch -glob -- [string tolower $cookie] {
                    "xyz*" {
                         Skip cookie starting with XYZ
                    }
                    "*;*secure*httponly*" - "*;*httponly*secure*" {
                         The cookie has already a Secure and HttpOnly flag...
                    }
                    "*;*httponly*" {
                        set cookie "[string trimright $cookie "; "]; Secure"
                    }
                    "*;*secure*" {
                        set cookie "[string trimright $cookie "; "]; HttpOnly"
                    }
                    default {
                        set cookie "[string trimright $cookie "; "]; Secure; HttpOnly"
                    }
                }
                HTTP::header insert "Set-Cookie" $cookie
            }
        } else {
            foreach cookie $cookie_list {
                switch -glob -- [string tolower $cookie] {
                    "xyz*" {
                         Skip cookie starting with XYZ
                    }
                    "*;*httponly*" {
                         The cookie has already a Secure and HttpOnly flag...
                    }
                    default {
                        set cookie "[string trimright $cookie "; "]; HttpOnly"
                    }
                }
                HTTP::header insert "Set-Cookie" $cookie
            }
        }
    }

    Cheers, Kai