Forum Discussion

Zuke_254875's avatar
Zuke_254875
Icon for Altostratus rankAltostratus
Dec 14, 2016

Insert X-Frame-Options header when specific URI is not used

I am having a tricky time getting an iRule to match criteria. I am trying to get the X-Frame-Options SAMEORIGIN header inserted whenever a URI does NOT match a specific string.

Here is the rule I have so far:

when HTTP_RESPONSE {
  if { ($hostLowered eq "domain.example.edu") and !($uriLowered contains "/sites/prod") } {
    HTTP::header insert "X-Frame-Options" "SAMEORIGIN"
    log local0. "Success: $hostLowered $uriLowered [IP::client_addr]"
  }
  else [ log local0. "Failure: $hostLowered $uriLowered" ]

When I use cURL to test, all of the responses I'm getting back include the X-Frame-Options SAMEORIGIN header. The second log statement is even showing the exact URI that matches the second argument on line 2.

2 Replies

  • Hi Zuke,

    you may try the iRule below to conditional inject the X-Frame-Option header...

    when HTTP_REQUEST {
        if {     ( [string tolower [HTTP::host]] eq "domain.example.edu" )
         and not ( [string tolower [HTTP::uri]] starts_with "/sites/prod" ) } then {
            set insert_x_frame_options 1
            log local0.debug "[HTTP::host][HTTP::uri] requires x_frame_options"
        } else {
            set insert_x_frame_options 0
            log local0.debug "[HTTP::host][HTTP::uri] does not require x_frame_options"
        }
    }
    when HTTP_RESPONSE {
        if { $insert_x_frame_options } then {
            HTTP::header insert "X-Frame-Options" "SAMEORIGIN"
            log local0.debug "Injected x_frame_options"
        }
    }
    

    Cheers, Kai

  • Used Kai's irule as a basis for one we needed. The conditions were a bit different where our determination of if/what value to return was based on the presence and contents of a query string value. In short, the query string value for 'CID' identifies a client for which we needed to respond with different X-Frame-Options header values based on whether they were framing us.

     Configure a custom response for the X-Frame-Options header based on the CID in the URI query string.
     Custom cid-specific settings are pulled from the 'xfo_client_overrides' list where the client cid
     is the 'string' and the desired X-Frame-Options value the 'value'.  Example:  12345678 := DENY
    
    when HTTP_REQUEST {
      set uri [string tolower [HTTP::uri]]
      set qcid [URI::query $uri cid]
      set ccid ([HTTP::cookie value "xcid"]) 
    
      if {[info exists qcid] and $qcid ne ""} {
        set cid [string trim $qcid "()"]
        set setcookie 1
      } elseif {[info exists ccid] and $ccid ne ""} {
        set cid [string trim $ccid ")("]
      } else {
        set cid 0
      }
    
    }
    
    when HTTP_RESPONSE {
      if { [ class search xfo_client_overrides equals $cid ] } {
        HTTP::header replace "X-Frame-Options" [class lookup $cid xfo_client_overrides]
      }
      if { [info exist setcookie] } {
        HTTP::cookie insert name "xcid" value $cid path "/" version 1
        HTTP::cookie secure "xcid" enable
        HTTP::cookie httponly "xcid" enable
      }
    }
    

    The value that is returned in the header is looked up from a 'xfo_client_overrides' string-based Data Group List. So basically there's a lookup table that matches the CID value (or subsequent xcid cookie value) to the value returned in the X-Frame-Options header.

    So for example:

    999991 := DENY
    999992 := SAMEORIGIN
    999993 := ALLOW-FROM https://www.somedomain.com
    

    Since in our situation the CID query value goes away after the initial request, I set that value into a 'xcid' cookie so the information persists for the duration of the session. Should a new CID query value come in on the URI, that value would be used and the xcid cookie value updated.

    This script does not permit for a default response were the CID not listed in 'xfo_client_overrides' or if the CID were absent altogether. This could be added relatively easily with an

    else
    on the first
    if
    condition in HTTP_RESPONSE (either be hard-coding in the script or by doing a lookup for a default value configured in 'xfo_client_overrides' as '0' or 'default' as in
    default := SAMEORIGIN
    ). Haven't thought through the logic on this entirely but the answer is close if not quite right. The advantage to the default value in 'xfo_client_overrides' solution should be that one could choose to have a default or not based on whether one exists in the lookup table (though this would necessitate an
    elseif
    rather than an
    else
    I suppose).