Forum Discussion

Eric_Weiss_2486's avatar
Eric_Weiss_2486
Icon for Nimbostratus rankNimbostratus
Feb 24, 2016

Extra pair/s of eyes need to verify HTTP::cookie logic

Can anyone see glaring logic issues with the following?

when HTTP_REQUEST { set LogString "Client [IP::client_addr]:[TCP::client_port] -> [HTTP::host][HTTP::uri]" log local0. "=============================================" log local0. "$LogString (request)" foreach aHeader [HTTP::header names] { Print the header info log local0. "$aHeader: [HTTP::header value $aHeader]" } foreach aCookie [HTTP::cookie names] { Log the cookie name and value log local0. "Cookie Name: $aCookie, Cookie value: [HTTP::cookie value $aCookie]" } if { ([HTTP::header value "User-Agent"] contains "Mozilla") || ([HTTP::header value "User-Agent"] contains "Opera") || ([HTTP::header value "User-Agent"] contains "curl") && ([string tolower [HTTP::uri]] matches_regex {restservicesintstest}) && (not [HTTP::cookie names] contains ".fb") } then { reject log local0. "Client browser connection to REST Host:[HTTP::host]; URI=[HTTP::uri]. No SSO Cookie Detected in Header, Client IP:[IP::client_addr] has been blocked" log local0. "=============================================" } else { log local0. "Client browser connection to REST Host:[HTTP::host]; URI=[HTTP::uri] for Client IP:[IP::client_addr] allowed!" log local0. "=============================================" } }

Particularly this piece:

if {
            ([HTTP::header value "User-Agent"] contains "Mozilla")
            || ([HTTP::header value "User-Agent"] contains "Opera")
            || ([HTTP::header value "User-Agent"] contains "curl")
    && ([string tolower [HTTP::uri]] matches_regex {restservicesintstest})
    && (not [HTTP::cookie names] contains ".fb") 

We're logging cookies:

Feb 24 15:57:23 lb01 info tmm[15541]: Rule /Common/SecAuthREST-IntS-Test--DEBUG2 : Client 10.0.22.218:59677 -> restservicesintstestv7.fb/test/alertsrestserviceintA/rest/alert/isAlive (request) Feb 24 15:57:23 lb01 info tmm[15541]: Rule /Common/SecAuthREST-IntS-Test--DEBUG2 : Host: restservicesintstestv7.fb Feb 24 15:57:23 lb01 info tmm[15541]: Rule /Common/SecAuthREST-IntS-Test--DEBUG2 : User-Agent: curl/7.47.0 Feb 24 15:57:23 lb01 info tmm[15541]: Rule /Common/SecAuthREST-IntS-Test--DEBUG2 : Accept: / Feb 24 15:57:23 lb01 info tmm[15541]: Rule /Common/SecAuthREST-IntS-Test--DEBUG2 : Cookie: test2.fb=foobar Feb 24 15:57:23 lb01 info tmm[15541]: Rule /Common/SecAuthREST-IntS-Test--DEBUG2 : Cookie Name: test2.fb, Cookie value: foobar Feb 24 15:57:23 lb01 info tmm[15541]: Rule /Common/SecAuthREST-IntS-Test--DEBUG2 : Client browser connection to REST Host:restservicesintstestv7.fb; URI=/test/alertsrestserviceintA/rest/alert/isAlive for Client IP:10.0.22.218 allowed!

However when we don't provided the test2.fb cookie, not [HTTP::cookie names] contains ".fb" isn't triggering in order to reject the connection:

Feb 24 15:57:18 lb01 info tmm[15541]: Rule /Common/SecAuthREST-IntS-Test--DEBUG2 : Client 10.0.22.218:59675 -> restservicesintstestv7.fb/test/alertsrestserviceintA/rest/alert/isAlive (request) Feb 24 15:57:18 lb01 info tmm[15541]: Rule /Common/SecAuthREST-IntS-Test--DEBUG2 : Host: restservicesintstestv7.fb Feb 24 15:57:18 lb01 info tmm[15541]: Rule /Common/SecAuthREST-IntS-Test--DEBUG2 : User-Agent: curl/7.47.0 Feb 24 15:57:18 lb01 info tmm[15541]: Rule /Common/SecAuthREST-IntS-Test--DEBUG2 : Accept: / Feb 24 15:57:18 lb01 info tmm[15541]: Rule /Common/SecAuthREST-IntS-Test--DEBUG2 : Client browser connection to REST Host:restservicesintstestv7.fb; URI=/test/alertsrestserviceintA/rest/alert/isAlive for Client IP:10.0.22.218 allowed!

I'm thinking that the HTTP::cookie statement isn't quite right, or that there must be a better way to string all of those conditions together.

Any insight or suggestions would be appreciated. Thanks, Eric

3 Replies

  • Hi Eric, Any chance you could log the User-Agent as well? Why not check if HTTP::cookie exists?
  • Hi Eric,

    I can only repeat the answer I gave you in your last post...

    https://devcentral.f5.com/questions?pid=44725answer132972

    when HTTP_REQUEST { 
        set LogString "Client [IP::client_addr]:[TCP::client_port] -> [HTTP::host][HTTP::uri]" 
        log local0. "=============================================" 
        log local0. "$LogString (request)" 
        foreach aHeader [HTTP::header names] { 
             Print the header info 
            log local0. "$aHeader: [HTTP::header value $aHeader]" 
        } 
        foreach aCookie [HTTP::cookie names] { 
             Log the cookie name and value 
            log local0. "Cookie Name: $aCookie, Cookie value: [HTTP::cookie value $aCookie]" 
        } 
        if { (( [HTTP::header value "User-Agent"] contains "Mozilla" ) or 
              ( [HTTP::header value "User-Agent"] contains "Opera" ) or 
              ( [HTTP::header value "User-Agent"] contains "curl" )) and 
              ( [string tolower [HTTP::uri]] matches_regex {restservicestest} ) and 
              not ( [HTTP::cookie names] contains ".fb" )
        } then { 
            reject 
            log local0. "Client browser connection to REST Host:[HTTP::host]; URI=[HTTP::uri]. No SSO Cookie Detected in Header, Client IP:[IP::client_addr] has been blocked" 
            log local0. "=============================================" 
        } else { 
            log local0. "Client browser connection to REST Host:[HTTP::host]; URI=[HTTP::uri] for Client IP:[IP::client_addr] allowed!" 
            log local0. "=============================================" 
        } 
    }
    

    ... to show you that this syntax is working you may try this test snipped...

    set user_agent "Blah Mozilla Blah"
    set http_uri "/folder/restservicestest/folder/file.txt"
    set cookie_names "cookie1 cookie.fb cookie2"
    
    set LogString "Client [IP::client_addr]:[TCP::client_port] -> [HTTP::host][HTTP::uri]" 
    log local0. "=============================================" 
    log local0. "$LogString (request)"
    if { (( $user_agent contains "Mozilla" ) or
          ( $user_agent contains "Opera" ) or
          ( $user_agent contains "curl" )) and
          ( [string tolower $http_uri] matches_regex {restservicestest} ) and
          not ( $cookie_names contains ".fb" )
    } then {
         reject  
        log local0. "Client browser connection to REST Host:[HTTP::host]; URI=[HTTP::uri]. No SSO Cookie Detected in Header, Client IP:[IP::client_addr] has been blocked" 
        log local0. "=============================================" 
    } else { 
        log local0. "Client browser connection to REST Host:[HTTP::host]; URI=[HTTP::uri] for Client IP:[IP::client_addr] allowed!" 
        log local0. "=============================================" 
    } 
    

    As already Noted: The iRule implements is a typical Blacklist. So it wouldn't block unknown "User-Agents" and/or unknown URIs. If this is not desired for you, then change the iRule to become a Whitelist where you allow just certain User-Agents, certain URIs and then enforce the Cookie to be present. And then block everything else which is not explicitly whitelisted...

    White-List approach

    when HTTP_REQUEST { 
        set LogString "Client [IP::client_addr]:[TCP::client_port] -> [HTTP::host][HTTP::uri]" 
        log local0. "=============================================" 
        log local0. "$LogString (request)" 
        foreach aHeader [HTTP::header names] { 
             Print the header info 
            log local0. "$aHeader: [HTTP::header value $aHeader]" 
        } 
        foreach aCookie [HTTP::cookie names] { 
             Log the cookie name and value 
            log local0. "Cookie Name: $aCookie, Cookie value: [HTTP::cookie value $aCookie]" 
        } 
        if { (( [HTTP::header value "User-Agent"] contains "Mozilla" ) or 
              ( [HTTP::header value "User-Agent"] contains "Opera" ) or 
              ( [HTTP::header value "User-Agent"] contains "curl" )) and 
              ( [string tolower [HTTP::uri]] matches_regex {restservicestest} ) and 
              ( [HTTP::cookie names] contains ".fb" )
        } then {
            log local0. "Client browser connection to REST Host:[HTTP::host]; URI=[HTTP::uri] for Client IP:[IP::client_addr] allowed!" 
            log local0. "=============================================" 
        } else { 
            reject 
            log local0. "Client IP:[IP::client_addr], User-Agent:[HTTP::header value "User-Agent"] and Cookies:[HTTP::cookie names] connection to REST Host:[HTTP::host]; URI=[HTTP::uri] has been blocked" 
            log local0. "=============================================" 
        } 
    }
    

    Cheers, Kai

  • I figured it out and was able to come up with something a little more elegant. Also, added logging for cookie and user-agent. The rule broke when adding all of the || and && conditions, like above. Changed logic for HTTP::cookie so that it isn't using 'not' (since that expects a numeric value instead of alpha), and changed the HTTP::uri regex that wasn't working, to HTTP::host.