Forum Discussion

Vadym_Chepkov's avatar
Vadym_Chepkov
Icon for Nimbostratus rankNimbostratus
Mar 05, 2021

How to preserve HTTP headers for HTTP::respond

I need to preserve HTTP headers for HTTP::respond, I tried the following approach

when HTTP_RESPONSE {
  if {[HTTP::has_responded]} {return}
  catch { unset hdrs }
  foreach header [HTTP::header names] {
    lappend hdrs $header "[HTTP::header $header]"
  }
  log local0. "Headers: $hdrs"
  HTTP::respond 301 -version auto $hdrs
}

Headers appear properly in the log, but I don't receive them in the response, only Connection Content-Length and Server are populated

Don't see errors either. What did I miss?

Thanks,

Vadym

  • Vadym,

    HTTP::respond does not allow variables to be expanded and evaluated in the context of the command execution.

    You will need to use eval. However, this introduces the risk of a TCL injection vulnerability.

    when HTTP_RESPONSE {
      if {[HTTP::has_responded]} {return}
      catch { unset hdrs }
      foreach header [HTTP::header names] {
        lappend hdrs $header "[HTTP::header $header]"
      }
      log local0. "Headers: $hdrs"
      eval HTTP::respond 301 -version auto $hdrs
    }

    You may also need to play with quoting the values.

    • Vladimir_Akhmarov's avatar
      Vladimir_Akhmarov
      Icon for Cirrus rankCirrus

      Hello Simon

       

      Tried this approach for modified Exchange iRule to logout user and sometimes I caught connection reset inside browser (but there is no TCL error inside LTM logs). So I cannot understand why "eval {}" with variable leads to connection errors compared with regular HTTP::respond header1 value1 header2 value2 ...

      My code

      when RULE_INIT priority 500 {
          set static::hdrs [list \
              "\"Location\" \"/vdesk/hangup.php3\"" \
              "\"Content-Type\" \"text/html\"" \
              "\"Cache-Control\" \"no-cache, must-revalidate\"" \
              "\"Set-Cookie\" \"MRHSession=deleted;expires=Thu, 01-Jan-1970 00:00:00 GMT;path=/;secure\"" \
              "\"Set-Cookie\" \"LastMRH_Session=deleted;expires=Thu, 01-Jan-1970 00:00:00 GMT;path=/;secure\"" \
              "\"Set-Cookie\" \"cadata=null;Expires=Thu, 01-Jan-1970 00:00:00 GMT;path=/;secure\"" \
              "\"Set-Cookie\" \"ClientId=null;Expires=Thu, 01-Jan-1970 00:00:00 GMT;path=/;secure\"" \
              "\"Set-Cookie\" \"UC=null;Expires=Thu, 01-Jan-1970 00:00:00 GMT;path=/;secure\"" \
              "\"Set-Cookie\" \"X-BackEndCookie=null;Expires=Thu, 01-Jan-1970 00:00:00 GMT;path=/;secure\"" \
              "\"Set-Cookie\" \"X-OWA-CANARY=null;Expires=Thu, 01-Jan-1970 00:00:00 GMT;path=/;secure\"" \
          ]
      }
      
      when HTTP_REQUEST priority 500 {
          ...
          eval {HTTP::respond 302 -version 1.1 noserver "[join $static::hdrs]"}
          ...
      }
      
      when ACCESS_SESSION_STARTED priority 500 {
          ...
          eval {ACCESS::respond 302 -version 1.1 noserver "[join $static::hdrs]"}
          ...
      }

       

      Do you know maybe there are some gotchas that should be included in the code?

  • Thank you,  , it helped. Is it enough to put $hdrs in curly braces to avoid TCL injection ?

    Or maybe append HTTP::respond statement with an additional header? Article doesn't provide detailed recommendation how to protect from malicious input.

    Also, I solved the problems of quoting by converting $hdrs to a list, i.e.

        set headers {}
     
        foreach header [HTTP::header names] {
            lappend headers $header [HTTP::header value $header]
        }
        

    Thanks,

    Vadym

    • Simon_Blakely's avatar
      Simon_Blakely
      Icon for Employee rankEmployee

      >Is it enough to put $hdrs in curly braces to avoid TCL injection ?

      No - that just makes {$hrds} a single parameter with spaces in it.

      I suspect you need to individually wrap each element (the headers and the values) in curly braces prior to the eval

      So you end up doing an eval on

      HTTP::respond 301 -version auto {header1} {header1_value} {header2} {header2_value} ...

      That prevents eval from further expanding the strings in the curly braces.

      But I don't really get TCL injection either - I know it is possible via unsanitized input, and eval is a common problem, and curly braces help, but I still struggle with it.