Forum Discussion

Dan_103700's avatar
Dan_103700
Icon for Nimbostratus rankNimbostratus
May 25, 2011

IRule for Context-Specific ASM Error Page

I wrote a couple iRules to help provide some context to our users when they get dinged by the ASM. Basically, I wanted to pass in the URL of the page that generated the block, in addition to the "support ID", so I could provide a more meaningful error message to customers, rather than using a single generic error message for all page requests that get blocked. This way I can provide some helpful suggestions to address any false positives a customer may be seeing.

 

 

Here's what I have so far:

 

 

when ASM_REQUEST_VIOLATION {

 

set x [ASM::violation_data]

 

set filterId [lindex $x 1]

 

set uri [HTTP::uri]

 

Build our query string for appending to not_found.htm

 

set asm_query_string "filterId=$filterId&uri=$uri"

 

}

 

 

when ASM_REQUEST_BLOCKING {

 

set redirectTo "http://www.domain.com/not_found.htm?$asm_query_string"

 

HTTP::header insert Location $redirectTo

 

}

 

 

Within the ASM, I have the response page set as:

 

Redirect URL: http://www.domain.com/not_found.htm?filterId=<%TS.request.ID()%>

 

 

So... what happens is that when someone is blocked, the iRule overwrites the response page 301 with the version that has URI in it. I can then use PHP in the not_found.htm page to give them a meaningful, context-specific error message.

 

 

The problem is that while this works in Firefox and Safari, Chrome and Internet Explorer receive both sets of Location headers and honor the one without URI in it.

 

 

Does anyone have any suggestions on how I can make this iRule work cross-browser? Ideally, there would be a variable like <%TS.request.URI()%> I could put right in the response page in the ASM, but I couldn't find any such variable. I also tried setting an error page instead of a response page in the security policy, hoping the irule redirect would override the error page, but it didn't.

 

 

Any help would be appreciated.

 

 

-Dan

 

 

 

4 Replies

  • Hi Dan,

    I haven't tested this, but could you use HTTP::respond from ASM_REQUEST_BLOCKING to replace the redirect?

    when ASM_REQUEST_BLOCKING {
        set redirectTo "http://www.domain.com/not_found.htm?$asm_query_string"  
        HTTP::respond 302 Location $redirectTo
    }
    

    Also make sure to validate the query string on your PHP app which displays the error text. At a minimum you could HTML encode any text you display back to the user to avoid a XSS vulnerability.

    Aaron
  • Aaron,

     

     

    Thanks for the response. The change you submitted doesn't work unfortunately -- it results in connection resets for some reason. As for the PHP code, I'm not showing any of the parameters on the page, except for support ID which I am sanitizing.

     

     

    I just tried changing the Redirect URL loaded in the ASM to an empty value, which actually fixed Chrome. This took some doing, since the javascript validation in the F5 wouldn't let me submit it at first. So I used the tamper data firefox extension to change the data after it passed validation, the ASM never bothers to validate it server-side, so I was able to get it to save.

     

     

    This fixed Chrome, but for some weird reason, IE now redirects to:

     

     

    http://www.domain.com/not_found.htm?filterId=259203436710356052&uri=/

     

     

    It looks like IE follows the first redirect and then follows the empty one, which it interprets as a request for the document root on the current domain. So close...

     

     

    Any other suggestions? Can I try disabling the ASM's rejection of the request somehow and rely on my own redirect to handle the request?

     

  • Got it!

     

     

    I needed to set the following as a Custom Response Header:

     

     

    HTTP/1.1 301 Moved Permanently

     

    Connection: close

     

     

    That way, it gets the 301 from the ASM but the actual Location from the iRule.
  • That's novel. I'd be careful about using a 301 as that tells any intermediate proxies to cache the response. Generally, the last thing you want is a proxy caching the blocking response. If you change it to a 302, it should be handled the same in terms of the Location, but you're telling the clientside not to cache the response.

     

     

    Aaron