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.

Redirect Location header validator

Problem this snippet solves:

This iRule demonstrates how to validate the 30x redirects a web application sends back to clients. It intercepts any redirects which are to a domain that is not in a whitelist string data group. The goal is to protect clients from a web application which does not provide complete validation of user-input when generating HTTP redirects. See the OWASP Top Ten page for details on this class of vulnerability:

OWASP Top Ten Unvalidated Redirects and Forwards

Code :

# Validate the 30x redirects the web application sends to clients against a whitelist stored in a data group
# The goal is to prevent the client from being tricked into receiving an unvalidated redirect to a malicious third party site
# by an attacker.  See the OWASP Top Ten for details on the vulnerability: https://www.owasp.org/index.php/Top_10_2010-A10-Unvalidated_Redirects_and_Forwards 

# The data group format is string.  v11 example:
#
#ltm data-group internal my_domain_whitelist_dg {
#    records {
#        example.com { }
#        example.net { }
#        example.org { }
#        example.co.uk { }
#        partner.com { }
#    }
#    type string
#}

when RULE_INIT {
   # Name of the string data group which contains the whitelisted domains
   # (ex: legal.com, legal.net, okay.org, etc)
   set static::domain_whitelist_dg "my_domain_whitelist_dg"

   # Log debug to /var/log/ltm? 1=yes, 0=no.
   set static::redirect_debug 1
}
when HTTP_RESPONSE {

   # Check if domain is a redirect
   if {[HTTP::is_redirect]}{

      if {$static::redirect_debug}{
         log local0. "[IP::client_addr]:[TCP::client_port]: status=[HTTP::status], Location=[HTTP::header Location], Server=[LB::server]"
      }
      # Check if the redirect location is an absolute URL
      switch -glob [HTTP::header Location] {
         "/*" -
         "" {
            # No Location header value or a local reference so do not check against whitelist
            if {$static::redirect_debug}{log local0. "[IP::client_addr]:[TCP::client_port]: Location local or empty. Not validating"}
         }
         default {
            # Check Location value against the data group
            set hostname [string tolower [URI::host [HTTP::header Location]]]
            if {$static::redirect_debug}{log local0. "[IP::client_addr]:[TCP::client_port]: Checking $hostname against $static::domain_whitelist_dg"}

            # Check the hostname against the whitelist
            if {[class match $hostname ends_with $static::domain_whitelist_dg]}{
               if {$static::redirect_debug}{log local0. "[IP::client_addr]:[TCP::client_port]: Legal redirect to [HTTP::header location]"}
            } else {
               if {$static::redirect_debug}{log local0. "[IP::client_addr]:[TCP::client_port]: Illegal redirect to [HTTP::header location]"}
               HTTP::respond 302 Location "http://www.example.com/redirect_blocked.html"
            }
         }
      }
   }
}
Published Mar 18, 2015
Version 1.0
No CommentsBe the first to comment