Forum Discussion

jrhodes_77014's avatar
jrhodes_77014
Icon for Nimbostratus rankNimbostratus
Mar 10, 2014

Duplicate cookies due to iRule

Hi,

We are having an issue with duplicate cookies. We have an iRule to rewrite the cookies so they are marked as 'secure' and 'httponly'. I can see the cookies are replaced (according to the logs) however in the browser we see 2 cookies.

eg Response sent 96 bytes of Cookie data: Set-Cookie: ASP.NET_SessionId=35z1kaf1puyipd51xue5ibus; Secure; HttpOnly; Secure; HttpOnly; path=/; HttpOnly Response sent 60 bytes of Cookie data: Set-Cookie: ASP.NET_SessionId=35z1kaf1puyipd51xue5ibus; path=/; HttpOnly

=======================================================================================

iRule as follows

when HTTP_RESPONSE { foreach cookie [HTTP::cookie names] { Use a variable to store whether we remove the leading dash from the cookie value set rewrite 0 set value [HTTP::cookie value $cookie];

if { "" != $value }
{

          
          Check the first character "0" to see if it's a hash "-"
          if {[string range $value 0 0] eq "-"} {
                 Remove the leading hash from the string and reset the variable
                 set value [string trimleft $value "-"]
                 If we remove the hash, we need to add it later so make a note
                 set rewrite 1
          }
          

          set testvalue [string tolower $value]
          set valuelen [string length $value]

          log local0. "Cookie found: $cookie = $value";

          switch -glob $testvalue {
                 "*;secure*" -
                 "*; secure*" { }
                 default { set value "$value; Secure"; }
          }

          switch -glob $testvalue {
                 "*;httponly*" -
                 "*; httponly*" { }
                 default { set value "$value; HttpOnly"; }
          }

          
          if we removed the hash earlier on it may be needed so lets add it back
          if {$rewrite == 1} {
                 set value "-$value"
          }
          

          if { [string length $value] > $valuelen} {
                 log local0. "Replacing cookie $cookie with $value"
                 HTTP::cookie value $cookie "${value}"
          }

}

}

}

Is there anything wrong with this rule?

1 Reply

  • I don't think you're explicitly removing the existing cookie before adding a new one. One sort of quirky thing about HTTP cookies is that a unique instance is defined not just by the cookie name, but also a combination of its value, path, expires, and other attributes. So,

    Set-Cookie foo=test1;path=/;secure;httponly
    Set-Cookie foo=test2;path=/;secure;httponly
    Set-Cookie foo=test2;path=/;httponly
    

    Are all separate cookies as far as the browser is concerned. Inserting a cookie with the same name, by virtue of a different "signature", is actually creating a new cookie.

    I also typically don't like to set the HttpOnly flag using the HTTP::cookie command because it can behave badly. Instead here's what I would use to replace a given set of cookies and set the secure and HttpOnly flags:

    when HTTP_RESPONSE {
        foreach aCookie [HTTP::cookie names] {
             if the cookie does not already have an HttpOnly attribute
    
            if { ( [HTTP::cookie httponly $aCookie] equals "disable" ) or ( [HTTP::cookie secure $aCookie] equals "disable" ) } {
    
                 get cookie value and path
                set value [HTTP::cookie value $aCookie]
                set path [HTTP::cookie path $aCookie]
    
                 get and insert domain if it exists
                if { [HTTP::cookie domain $aCookie] ne "" } { set domain "domain=[HTTP::cookie domain $aCookie];" } else { set domain "" }
    
                 get and insert expires only if it exists
                if { [HTTP::cookie expires $aCookie] ne "" } {
                    set expires_local [clock format [expr [clock seconds] + [HTTP::cookie expires $aCookie]] -format "%a, %d-%b-%Y %H:%M:%S GMT" -gmt true]
                    set expires "expires=$expires_local;"
                } else {
                    set expires ""
                }
    
                 remove the original cookie
                HTTP::cookie remove $aCookie
    
                 insert a new cookie via HTTP header inject
                HTTP::header insert "Set-Cookie" "$aCookie=$value;path=$path;${domain}${expires}secure;HttpOnly;"
            }       
        }
    }