For more information regarding the security incident at F5, the actions we are taking to address it, and our ongoing efforts to protect our customers, click here.

Forum Discussion

fayar_128903's avatar
fayar_128903
Icon for Nimbostratus rankNimbostratus
Jul 09, 2013

Http cookies insertion in LTM

Hello !

 

I am currently learning how to write iRules. In order to implement a logging script on a LTM device (BigIp V11), I would like to insert a cookie containing a number in my http request.

 

My architecture is quite simple: I have an apache webserver, and the client-side of my architecture go threw my LTM device to reach it.

 

What I want to do is to add a cookie for all http exchanges between LTM and my apache webserver.

 

My code looks like this:

 

 

when RULE_INIT {

 

set ::cn "uniqueid"

 

}

 

 

 

when HTTP_REQUEST {

 

set http_request_time [clock clicks -milliseconds]

 

set http_request_ipsource [IP::client_addr]

 

set http_request_method [HTTP::method]

 

set unique_id [format %09d [expr {int(rand() * 1e9)}]]

 

HTTP::cookie insert name $::cn value "$unique_id"

 

}

 

when HTTP_REQUEST_SEND {

 

set http_request_send_time [clock clicks -milliseconds]

 

set http_request_ipdest [IP::server_addr]

 

log local0. "unique_id=$unique_id;request_time=$http_request_time;send_request_time=$http_request_send_time;ip_source=$http_request_ipsource;ip_dest=$http_request_ipdest;method=$http_request_method;"

 

}

 

 

 

when HTTP_RESPONSE {

 

set http_server_response_time [clock clicks -milliseconds]

 

 

}

 

 

when HTTP_RESPONSE_RELEASE {

 

set http_response_release_time [clock clicks -milliseconds]

 

if { [HTTP::cookie exists $::cn] } {

 

set unique_id_out [HTTP::cookie value $::cn]

 

HTTP::cookie remove $::cn

 

log local0. "unique_id=$unique_id_out;server_response_time=$http_server_response_time;response_release_time=$http_response_release_time;"

 

}

 

 

}

 

 

 

 

What I think the code above will do:

 

 

Client LTM WebServer

 

| | ------------no cookie--------------> | | ---------cookie----------->| |

 

| | | | | |

 

|___|<-----------no cookie-----------------|___| <---------cookie-----------|___|

 

 

 

 

 

My problem is, this is what I get:

 

 

Client LTM WebServer

 

| | ------------no cookie---------------->| | ---------cookie--------------->| |

 

| | | | | |

 

|___|<-----------no cookie----------------- |___| <---------no cookie-----------|___|

 

 

 

 

 

 

The funny part is, I have the same behaviour when I change the webserver (instead of a basic http server, I tried an https on a different machine, even the interface of another LTM machine...)

 

Do you have any ideas/suggestion about why this doesn't work as I expect it ?

 

Thank you ! :)

 

7 Replies

  • If I understand you correctly, you want to set a cookie in the ingress flow to the server for each request, containing some random unique identifier, and then strip it off of the response before sending data to the client so that the client is never involved in the cookie process.

     

     

    The first thing I'd ask, just out of curiosity, is why? What does this do to/for the web server - considering that the cookie value is NOT user-specific.

     

     

    The second thing I'd point out is that a web server doesn't natively relay cookies the way a browser would. The presence of a cookie in the output stream will always be a "Set-Cookie" header intended for the browser. The presence of a cookie in the input stream will always be a "Cookie" header from the browser, relaying a previously set cookie. A web server would neither expect a "Set-Cookie" header, nor generally know what to do with it, so you'd need to build in some capability into the application to relay a cookie value back in the response. But while you're at it, and since the client isn't involved in the process anyway, an HTTP header would be generally easier to work with.

     

     

    An example:

     

    
    when RULE_INIT {
          using the static namespace in v10/11 allows for CMP-compliance
         set static::cn "uniqueid"
    }
    when HTTP_REQUEST {
         set unique_id [format %09d [expr {int(rand() * 1e9)}]]
         HTTP::header insert $static::cn $unique_id
    }
    when HTTP_RESPONSE {
         if { [HTTP::header exists $static::cn] } {
              HTTP::header remove $static::cn
         }
    }
    

     

     

    Then simply code your application to both receive and send HTTP headers instead of cookies.

     

     

  • Thank you for your quick answer ! :)

     

     

    If I understand you correctly, you want to set a cookie in the ingress flow to the server for each request, containing some random unique identifier, and then strip it off of the response before sending data to the client so that the client is never involved in the cookie process.

     

     

    Exactly, this was what I wanted to do in the first place.

     

     

    The first thing I'd ask, just out of curiosity, is why? What does this do to/for the web server - considering that the cookie value is NOT user-specific.

     

     

    Actually, I want to be able to log the following for each http packet:

     

     

    1) The time spent by the packet inside LTM.

     

    2) The time spent on the server-side (wich will include the duration of the request's processing time by the server)

     

     

    In addition, I don't want this solution to be specific to my current application. In other words, I want to achieve this objective without modifying my application.

     

     

    Considering that, I don't think the header based solution is a good choice for me, because as you say, I will have to modify my application in this case.

     

     

    However, you made me understand why cookies wouldn't work in this case... thank you. ^^

     

     

    Do you know something else I could try in order to solve my problem ?

     

     

    Thank you !

     

  • Generally speaking, a response is ~usually tied to a request in a single TCP session. So you could very simply:

     

     

    1. Create a unique ID variable in the request (HTTP_REQUEST)

     

    2. Mark the time of exit to the server (HTTP_REQUEST_RELEASE)

     

    3. Mark the time of re-entry (HTTP_RESPONSE) - unique ID variable should still be available inside the TCP session

     

     

    No modifications to the server required, nor need to mess with headers or cookies.
  • I will try to use this solution. :)

     

     

    One more question though, would this still work when OneConnect is enable ?
  • Yes. OneConnect will aggregate multiple requests into a single TCP stream, but the individual requests and corresponding responses are still unique.
  • Okay, I see :).

     

    It seems to have solved my problem ! Thank you so much !

     

     

  • Just create an arbitrary variable in the HTTP_REQUEST event and look for it in the HTTP_RESPONSE event. Example:

    
    when HTTP_REQUEST {
         set GUID [format %09d [expr {int(rand() * 1e9)}]]
          send something to logs...
    }
    when HTTP_RESPONSE {
         if { [info exists GUID] } {
               send something to logs...
              unset GUID
               optionally unset the variable
         }
    }
    

    The most important thing is that you test for the existence of the variable in the response before trying to use it.