iRule Security 101 - #02 - HTTP Methods and Cross Site Tracing

In this installment of iRule Security 101, I'll refer to OWASP's Data Validation Test "Testing for HTTP Methods and XST (Cross Site Tracing)" and illustrate how to use iRules to build a defense mechanism to block potentially dangerous HTTP commands (methods) and ensure that Cross Site Tracing is not possible. Other articles in the series:

GET and POST methods the most used methods to request information from a web server, but the HTTP protocol allows several others including HEAD, PUT, DELETE, TRACE, OPTIONS, and CONNECT. Some of these can cause potential security risks such as remote file access and un-intended retrieval of information. The TRACE in particular, was designed to allow echoing of strings sent to the server and is mainly used for debugging purposes. But, the use of this method has been shown to allow for an attach known as Cross Site Tracing, which was discovered by Jeremiah Grossman in his paper titled "Cross Site Tracing (XST)".

when RULE_INIT {
  set INFO 0
  set DEBUG 0
  #------------------------------------------------------------------------
  # HTTP Method
  #------------------------------------------------------------------------
  set sec_http_method_enabled 1
  set sec_http_method_block 1
  set sec_http_method_alert 1
  set sec_http_methods [list \
    "CONNECT" \
    "DELETE" \
    "HEAD" \
    "OPTIONS" \
    "PUT" \
    "TRACE" \
  ]
}

when HTTP_REQUEST {
  #============================================================================
  # HTTP Method
  #============================================================================
  if { $::INFO } { log local0. "ASSERTION: http_method" }
  if { $::sec_http_method_enabled } {
    if { $::DEBUG } { log local0. "  HTTP Method: [HTTP::method]" }
    if { [matchclass [HTTP::method] equals $::sec_http_methods] } {
      if { $::sec_http_method_alert } { log local0. "  SEC-ALERT: Invalid HTTP Version found: '[HTTP::method]'" }
      if { $::sec_http_method_block } { reject }
    } else {
      if { $::DEBUG } { log local0. "  PASSED" }
    }
  }
}

In the RULE_INIT method, I've created a few global variables enabling one to turn on or off the verification. This iRule will block all requests in the violation list so make sure before you deploy this iRule that you verify that your web applications don't make use of any of them.

Without all the extra conditionals, the iRule can be stripped down to the following couple of lines:

when RULE_INIT {
  set sec_http_methods [list "CONNECT" "DELETE" "HEAD" "OPTIONS" "PUT" "TRACE"]
}

when HTTP_REQUEST {
  if { [matchclass [HTTP::method] equals $::sec_http_methods] } {
    reject
  }
}

For 10.x and later, you should use the class command instead of matchclass. Also, global variables should not be used for CMP systems. The iRules below should work for later versions. Note however, that the logic is reversed in these versions, where you specify the versions you want to allow and block all others.

# Via list in RULE_INIT
when RULE_INIT {
  set static::sec_http_methods [list "DELETE" "GET" "PATCH" "POST" "PUT"]
}
when HTTP_REQUEST {
  if { [lsearch -exact $static::sec_http_methods [HTTP::method]] == -1 } { reject }
}

# Via data-group called sec_http_methods
when HTTP_REQUEST {
  if { not [class match [HTTP::method] equals sec_http_methods} { reject }
}

Also available in later versions, you can use an LTM Policy and forego the iRule altogether:

ltm policy sec_http_method {
    controls { forwarding }
    last-modified 2016-09-21:10:17:19
    requires { http }
    rules {
        allow_methods {
            actions {
                0 {
                    forward
                    reset
                }
            }
            conditions {
                0 {
                    http-method
                    not
                    values { GET POST PUT PATCH DELETE }
                }
            }
        }
    }
    status published
    strategy first-match
}

For more information on HTTP Method attacks and Cross Site Tracing, take a look at OWASP's documentation on the topic.

Get the Flash Player to see this player.
Published Aug 13, 2007
Version 1.0

Was this article helpful?

5 Comments

  • Hi, first let me say that I really enjoy these articles - please keep them coming.

     

     

    However, I did note that the if statement in the above rule seems to be inverted when assessing whether or not to reject the connection. Assuming that we don't want to accept those HTTP methods, you probably want to drop the ! in the evaluation. Looks like maybe you were thinking to define only acceptable HTTP methods and simply drop everything else (which would seem like the best way to go about this - whitelisting is usually easier than blacklisting anyway). :-)
  • Just checking to make sure anyone was paying attention... No really, this was a cut+paste from a previous iRule I was working on. You're right in that the ! should go. I've updated the article.

     

     

    Thanks!

     

     

    -Joe
  • Wondering if this has changed in recent versions at all?

     

     

    Also thinking the method is back to front entirely, but that is easily fixed.

     

     

    Since new methods may be added to HTTP, we should whitelist allowed methods not blacklist denied methods.

     

     

    We can do that here, last time I did it was with Squid proxy 2.mumble, and there you could only "deny" methods in the config file, so I wrote a script to extract methods known from where they were enumerated in the Squid proxy header file, and deny all those not on my whitelist. Since Squid proxy has the decency to reject http methods it doesn't recognise this was adequate - of course it wasn't choosy out of the box and TRACE and all of WebDAV methods were allowed by default.
  • Rule's current syntax on 11.5.1 throws: 01070151:3: Rule [/Common/irule-whitelist-httpverb] error: Unable to find value_list (sec_http_methods) referenced at line 27: [matchclass [HTTP::method] equals $::sec_http_methods]
  • For later versions, alternative iRules syntax is provided at the bottom of the article. You could also instead use an LTM policy for this.