Forum Discussion

Carl_Gottlieb_1's avatar
Carl_Gottlieb_1
Icon for Nimbostratus rankNimbostratus
Nov 09, 2010

Replay Attack prevention for HTTP Post of Auth details

Hi,

I have an application (let's call it website 1) which users log into using a username and password. Once logged in the app sends back a simple landing page with some links, and in hidden fields it inserts a clear text username and password for website 2. This second set of credentials is not seen or known by the user. When the user clicks to access their account details this performs a POST of their secondary auth details to website 2, it responds with their account details in another webpage and the user is now happily using website 2 without knowing what went on. All of this happens through one BigIP with website 1 and website 2 sitting on the same domain name.

 

 

 

We now want to secure this whole process by preventing the username and password being in cleartext and ideally prevent a replay attack where a host based packet sniffer/malware could capture the POST data and simply replay to log into website 2 in the future.

 

 

 

I'm thinking of the following plan:

 

 

 

To prevent clear text auth details:-

 

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

 

1) Scrub the username/password hidden field values on the way back to the customer and place their values in encrypted session cookies. When the POST is sent back, decryot the cookies and insert the values back into the POST payload and it all works fine.

 

 

 

To prevent replay attacks:-

 

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

 

2) Somehow validate the POST containing the encrypted auth cookies to ensure that the submission is only valid for that session/period of time.

 

 

 

 

 

For 1) I have worries about performance of regexing the payload and the complexity of the irule required.

 

 

 

For 2) I don't know how I can do this. Is there a way to use a variable that is session based or time based that could either be used as an encryption key or as something else to check, so that replaying the same POST another day would not be valid.

 

 

 

Appreciate any thoughts,

 

 

 

thanks

 

 

 

Carl

 

9 Replies

  • quick question...how deep into the payload is the username/password, and is its location consistent? Also, does the POST need to occur more than once?
  • Hi,

     

    Best assume the username and password are buried in the middle of the payload (and this location will probably change over time if app developers mess around with the page) but they will be in hidden fields so they should be adjacent to specified field names, as opposed to being randomly scattered in the page.

     

     

    The POST should be one time, so an iRule for one time token submission would be ideal but i couldn't find one.

     

     

    thanks

     

    Carl
  • This is totally doable. You'd need to have an iRule on each virtual. First virtual iRule would collect payload and search/replace the user/password. Take the username/password, hash it, send the hash to the user in an encrypted cookie and store the credentials in the session table locally. The second virtual's iRule would then lookup the hash in the session table, format the request with the username/password in appropriate fields for the request, then delete the session table entry. No entry, no replay. Obviously, there is work to do on your part, but there is a solution, and if you get stuck, post back.
  • Thanks! In this case both apps actually would sit on the same domain name and behind the same virtual server so this could be done in one iRule I suppose.

     

     

    Any good session table examples you'd recommend in the samples section?

     

     

    thanks again, Carl
  • take a look at the persistence section here: http://devcentral.f5.com/wiki/default.aspx/iRules/CodeShare.html Click Here

     

     

     

    The weblogic persistence shows the usage of the session command: http://devcentral.f5.com/wiki/default.aspx/iRules/Weblogic_JSessionID_Persistence.html Click Here

     

     

    Also, there are several examples (and syntax of course) of the session command itself: http://devcentral.f5.com/wiki/default.aspx/iRules/session.html Click Here
  • Here's the working iRule.

     

     

    Amongst the things it's missing are precedence and event disables so it doesn't clash with other redirect iRules:

     

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

     

     

     

     

    Name : Secure Credentials Handover Rule

     

     

    Description :

     

     

    This iRule is used to secure the handover of credentials between two apps when passed using HTTP redirects.

     

     

    Special Notes :

     

     

    Note this iRule applies to the following scenario, which can be secured by this iRule:

     

     

    App1 and App2 sit on the same https://www.domain.com website behind the same BigIP on the same virtual server

     

    User clicks on resource within App1, App1 sends back a 302 containing link to App2 along with the user's credentials in the URI

     

    User responds to 302 submitting request to App2 with credentials in URI. App2 receives request and uses the URI auth details to authenticate the user.

     

     

     

    Current Version : 1.1 - 18 Nov 2010

     

     

    version control

     

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

     

     

    1.1 - Anonymised for DevCentral - tested on 9.4.8

     

     

    Author (Version, Date, Name, Company)

     

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

     

     

    1.1, 18 Nov 2010, Carl Gottlieb

     

     

     

     

    when RULE_INIT {

     

    Specify the URL to redirect to when the the process fails

     

    set ::error_redirect_url "https://www.domain.com/login"

     

     

    Specify the unique string that the 302 Location Header contains that signifies this as an authentication redirect

     

    set ::auth_identifier_string "authattempt"

     

     

    Specify the temporary URI used to replace the original uri with

     

    set ::uri_string_unique_auth_text "/secured_auth_request"

     

     

    Specify the name of the authentication cookie

     

    set ::auth_cookie_name "hasheduricookie"

     

     

    Specify the session table entry timeout value in seconds

     

    set ::cookie_session_timeout "5"

     

     

    Specify the path of the cookie

     

    set ::auth_cookie_path "/"

     

     

    Specify the domain of the cookie

     

    set ::auth_cookie_domain "www.domain.com"

     

     

    Specify the domain of the website

     

    set ::website_domain "https://www.domain.com"

     

    }

     

     

     

    when HTTP_RESPONSE {

     

     

    Check if the HTTP response is a redirect to the authentication page

     

    if {[HTTP::is_redirect] and ([HTTP::header Location] contains $::auth_identifier_string)}{

     

     

    Use scan to check for https://$host/$cleartexturi, saving the matches

     

    the leading / of the URI will be trimmed, so we need to append it in the Location rewrite

     

    if {[scan [HTTP::header Location] {https://%[^/]/%s} host cleartexturi] == 2}{

     

     

    Strip the uri off the Location header and replace with $::uri_string_unique_auth_text to identify this process

     

    HTTP::header replace Location $::website_domain$::uri_string_unique_auth_text

     

     

    Create a numeric md5 hashed version of the clear text uri

     

    set hasheduri [b64encode [md5 $cleartexturi]]

     

     

    Insert the new cookie containing the hashed uri

     

    HTTP::cookie insert name $::auth_cookie_name value $hasheduri path $::auth_cookie_path domain $::auth_cookie_domain

     

     

    Insert a session table entry for the hashed uri against the real clear text uri with a timeout of $::cookie_session_timeout seconds

     

    session add uie $hasheduri $cleartexturi $::cookie_session_timeout

     

     

    } else {

     

    log local0. "[IP::client_addr]:[TCP::client_port]: Couldn't parse auth redirect: [HTTP::header Location]"

     

    }

     

    }

     

    elseif { [info exists wipe_cookie_flag] } {

     

    if { $wipe_cookie_flag == 1 } {

     

    The HTTP Response is not a redirect but since the successful auth response variable is set this must be the response after successful auth

     

    Set the auth session cookie to be expired in the response so the user's browser deletes the cookie

     

    HTTP::header insert Set-Cookie "$::auth_cookie_name=null;path=$::auth_cookie_path;domain=$::auth_cookie_domain;Expires=Thurs, 01-Jan-1970 00:00:00 GMT"

     

    log local0. "The hashed auth cookie has been set to expire due to successful authentication"

     

     

    Now the flag has been observed and the cookie set to expire itself we don't need the flag anymore, thus unset the cookie flag.

     

    unset wipe_cookie_flag

     

    log local0. "Wipe_cookie_flag has been reset after this successful authentication."

     

    }

     

    }

     

    }

     

     

    when HTTP_REQUEST {

     

     

    Only match traffic which is for this new app2 service that is a new auth attempt

     

    if {[HTTP::uri] starts_with $::uri_string_unique_auth_text}{

     

     

    Check that the request contains the auth cookie and it has a value

     

    if {[HTTP::cookie exists $::auth_cookie_name] and [HTTP::cookie $::auth_cookie_name] ne ""}{

     

     

    Check that session table isn't empty for this proposed cookie value

     

    if {[session lookup uie [HTTP::cookie value $::auth_cookie_name]] ne ""}{

     

     

    Set a variable to be the value of the incoming cookie

     

    set session_table_cookie [HTTP::cookie value $::auth_cookie_name]

     

     

    Replace the uri of the request with the original un-hashed uri from the session table with a slash

     

    HTTP::uri "/[session lookup uie $session_table_cookie]"

     

     

    Delete the uri from the session table now that it has been used

     

    session delete uie $session_table_cookie

     

     

    Delete the cookie containing the hashed uri from the HTTP request so that it is not submitted to the webserver

     

    HTTP::cookie remove $::auth_cookie_name

     

     

    set wipe_cookie_flag "1"

     

    log local0. "Wipe_cookie_flag has been set in a request to 1 during this successful authentication."

     

     

     

    } else {

     

    Request was to $::uri_string_unique_auth_text and the cookie was present but the cookie didn't match a session table entry (most likely a cookie recreation attack)

     

    HTTP::redirect $::error_redirect_url

     

    log local0. "Request was to ::uri_string_unique_auth_text but the cookie didn't match a session table entry (most likely a cookie recreation attack)" }

     

     

    } else {

     

    Request was to ::uri_string_unique_auth_text but no cookie was present in the request

     

    HTTP::redirect $::error_redirect_url

     

    log local0. "User tried to access authentication site by going to uri of [HTTP::uri] , but authentication cookie wasn't present so redirected user to error page of $::error_redirect_url"

     

    }

     

    }

     

    }