Forum Discussion

istockchris_390's avatar
istockchris_390
Icon for Nimbostratus rankNimbostratus
Dec 08, 2010

Masking cookie names from the server

I have fighting sessionID cookies from two different applications. One uses a subdomain, the other uses the root domain. My work around idea is to hide the cookie using the root domain from the application that sets the subdomain cookie. These two application have two different virtual servers.

In order to try to implement this, I've created:

 


when HTTP_REQUEST{
   if { [HTTP::cookie exists "sessionID"] and [HTTP::header "Cookie"] contains "sessionID" } {
       log local0. "Should be mangling streams"
      STREAM::disable
      STREAM::expression "@sessionID@HiddensessionID@"
      STREAM::enable
   }
}

 

This just simply does nothing. Watching packets hit the server, "sessionID" is never re-written. However, I do end up with the logged message "Should be mangling streams".

Anyone know why this isn't working for me? It's important that I not delete any cookies, I just want to hide one when using a specific virtual server.

  • Hi,

     

     

    A stream profile applied to a VS with an HTTP profile will only affect the HTTP request and response payloads. Cookies in the request are just name=value pairs. The client won't include cookie properties that the server set like the path or domain.

     

     

    So can you differentiate between the cookies just based on the value? If so, would you want to rename the "wrong" session cookie name? Or would you just want to remove it from requests that are proxied to the pool? You can remove a cookie using HTTP::cookie remove. But I'm not sure how HTTP::cookie remove will handle two cookies with the same name. It might remove the last cookie (or both!). You could save the cookie value that you want, remove all cookies with that name and then insert the correct value again. This assumes that you can determine the correct cookie value though.

     

     

    Aaron

     

     

  • Actually if one or both cookies are set in responses through LTM, you could try to rename the cookie in the response and then name it back on subsequent requests (or remove it or do whatever else you want with it). You could look for the cookie by name and path in the Set-Cookie headers, save the value, remove the "wrong" cookie and insert it with a new name and original value, path, etc.

     

     

    If this sounds like a workable solution for you, let me know and I'll test an example iRule.

     

     

    Aaron
  • Yes, it looks like you're ahead of us on working this out.

     

     

    We can diferrentiate based on cookie value. So, we implemented that, but then realized that it didn't matter. The browser was only allowing one sessionID cookie to exist and it seemed like the sub.domain.com cookie wasn't getting set if it existed in .domain.com. So we could mask this cookies existence from the server, but the browser still wouldn't set it.

     

     

    So what you described, a "cookie translation" if you will, seems like the only workable option.

     

     

    I'll see what I'm able to make work. Thanks for the help.

     

  • I thought browsers should support multiple cookies with the same name if the domain and/or path is different.

     

     

    Regardless, the response cookie rewriting should work as well. If you get stuck on how to do this in an iRule, can you post an anonymized copy of a response where both cookies are set?

     

     

    Thanks, Aaron
  • The following appears to work perfectly, if you just look at the logs. However, the application (obviously OWA in this case) isn't fooled. Because it's encrypted I can't use tcpdump to confirm the headers are correctly being set.

     

    
    when HTTP_REQUEST {
    if { [HTTP::header exists "Cookie"] and [HTTP::header "Cookie"] contains "OWAsessionid" } {
    log local0. "Trying to send cookie(s): [HTTP::header "Cookie"]"
    set new_cookies [string map {OWAsessionid= sessionid=} [HTTP::header value "Cookie"]]
    HTTP::header remove "Cookie"
    HTTP::header insert "Cookie" $new_cookies
    log local0. "Actually sent cookie(s): [HTTP::header "Cookie"]"
    }
    }
    
    when HTTP_RESPONSE {
    if { [HTTP::header exists "Set-Cookie"] and [HTTP::header "Set-Cookie"] contains "sessionid" } {
    log local0. "Trying to set cookie: [HTTP::header value "Set-Cookie"]"
    set new_cookies [string map {sessionid= OWAsessionid=} [HTTP::header value "Set-Cookie"]]
    HTTP::header remove "Set-Cookie"
    HTTP::header insert "Set-Cookie" $new_cookies
    log local0. "Actually set: [HTTP::header value "Set-Cookie"]"
    }
    
    }
    

     

    The logging output from this rule:

    Dec 9 15:53:23 tmm tmm[2524]: Rule CookieMask2 : Trying to set cookie: sessionid=78bb3b32-ec44-4d2f-a888-52bdd454c9f7; path=/; path=/

    Dec 9 15:53:23 tmm tmm[2524]: Rule CookieMask2 : Actually set: OWAsessionid=78bb3b32-ec44-4d2f-a888-52bdd454c9f7; path=/; path=/

    Dec 9 15:53:23 tmm tmm[2524]: Rule CookieMask2 : Trying to send cookie(s): BIGipServerPool_Exchange=2689860362.20480.0000; OutlookSession=aacc1677c2f84a18836f5eb3d560dcd1; PBack=0; OWAsessionid=78bb3b32-ec44-4d2f-a888-52bdd454c9f7

    Dec 9 15:53:23 tmm tmm[2524]: Rule CookieMask2 : Actually sent cookie(s): BIGipServerPool_Exchange=2689860362.20480.0000; OutlookSession=aacc1677c2f84a18836f5eb3d560dcd1; PBack=0; sessionid=78bb3b32-ec44-4d2f-a888-52bdd454c9f7

  • Can you log the value(s) of the Set-Cookie header(s) for each response and post back with the sanitized output from /var/log/ltm? You can use:

    log local0. "Set-Cookie headers: [HTTP::header values Set-Cookie]"

    Also, you could replace these checks:

     

        if { [HTTP::header exists "Cookie"] and [HTTP::header "Cookie"] contains "OWAsessionid" } {
    

     

    with:

     

    if { [HTTP::cookie value "OWAsessionid"] ne "" } {
    

     

    Aaron

  • The problem is that multiple "Set-Cookie"'s are in a single request, and when I do a [HTTP::cookie remove "Set-Cookie"], I'm clobbering a lot of other cookies. I imagine another potential problem is that I'm not always going to catch "sessionid" being set, because these functions operate only on the last "Set-Cookie" header.

    The following code:

    when HTTP_RESPONSE {

    if { [HTTP::header values "Set-Cookie"] contains "sessionid" } {

    log local0. "Set-Cookie count: [HTTP::header count "Set-Cookie"]"

    log local0. "Set-Cookie value: [HTTP::header values "Set-Cookie"]"

    }

    Produces the following output:

    Dec 10 00:05:08 tmm tmm[2524]: Rule CookieMask2 : Set-Cookie count: 3

    Dec 10 00:05:08 tmm tmm[2524]: Rule CookieMask2 : Set-Cookie value: {sessionid=; path=/; expires=Thu, 01-Jan-1970 00} 00 {00 GMT} {cadata=; path=/; expires=Thu, 01-Jan-1970 00} 00 {00 GMT} {BIGipServerPool_Exchange=2689860106.20480.0000; path=/}

    Dec 10 00:05:18 tmm tmm[2524]: Rule CookieMask2 : Set-Cookie count: 3

    Dec 10 00:05:18 tmm tmm[2524]: Rule CookieMask2 : Set-Cookie value: {sessionid=1b36c39b-2ae6-42cb-86b1-db030e2e65fe; path=/} {cadata="seeminglyrandomstringbutsanitizedjustincase="; HttpOnly; path=/} {sessionid=1b36c39b-2ae6-42cb-86b1-db030e2e65fe; path=/; path=/}

    Which I believe proves this to be true. Also note, that the first "sessionid" cookie is split up funny, which is preventing a pretty simple fix to this problem in my mind.

    So, I don't believe I have to tools necessary with HTTP::header and HTTP::cookie to fix this. I see no way to nicely "step through" headers with duplicate names. Hoping someone can chime in on that.

     

  • TCP::collect / TCP::payload doesn't look like an easy option either. I have an SSL client profile that is doing SSL offloading, however TCP::payload returns garbage (but works great on HTTP traffic).

     

     

    I found talk of a workaround being to make another virtual server, and redirect traffic to that. I'm not sure I completely understand how that may work for me at this point.

     

     

    I'm running 9.4+, so SSL::collect doesn't appear to be an option either.