2

My goal is to create an IIS Managed Module that looks at the Request and filters out content from the POST (XSS attacks, SQL injection, etc).
I'm hung up right now, however, on the process of actually filtering the Request. Here's what I've got so far:

In the Module's Init, I set HttpApplication.BeginRequest to a local event handler. In that event handler, I have the following lines set up:

if (application.Context.Request.HttpMethod == "POST")
    {
        application.Context.Request.Filter = new HttpRequestFilter(application.Context.Request.Filter);
    }

I also set up an HttpResponseFilter on the application.Context.Response.Filter

HttpRequestFilter and HttpResponseFilter are implementations of Stream.

In the response filter, I have the following set up (an override of Stream.Write):

public override void Write(byte[] buffer, int offset, int count)
    {
        var Content = UTF8Encoding.UTF8.GetString(buffer);
        Content = ResponseFilter.Filter(Content);
        _responseStream.Write(UTF8Encoding.UTF8.GetBytes(Content), offset, UTF8Encoding.UTF8.GetByteCount(Content));
    }

ResponseFilter.Filter is a simple String.Replace, and it does, in fact, replace text correctly.

In the request filter, however, there are 2 issues. The code I have currently in the RequestFilter (an override of Stream.Read):

public override int Read(byte[] buffer, int offset, int count)
{
    var Content = UTF8Encoding.UTF8.GetString(buffer);
    Content = RequestFilter.Filter(Content);
    if (buffer[0]!= 0)
    {
        return _requestStream.Read(UTF8Encoding.UTF8.GetBytes(Content), offset, UTF8Encoding.UTF8.GetByteCount(Content));
    }
    return _requestStream.Read(buffer, offset, count);
}

There are 2 issues with this. First, the filter is called twice, not once, and one of the requests is just basically a stream of /0's. (the if check on buffer[0] filters this currently, but I think that I'm setting something up wrong)

Second, even though I am correctly grabbing content with the .GetString in the read, and then altering it in RequestFilter.Filter(a glorified string.replace()), when I return the byte encoded Content inside the if statement, the input is unmodified.

Here's what I'm trying to figure out:

1) Is there something I can check prior to the filter to ensure that what I'm checking is only the POST and not the other time it is being called? Am I not setting the Application.Context.Request.Filter up correctly?

2) I'm really confused as to why rewriting things to the _requestStream (the HttpApplication.Context.Request.Filter that I sent to the class) isn't showing up. Any input as to something I'm doing wrong would be really appreciated.

Also, is there any difference between HttpApplication.Request and HttpApplication.Context.Request?

edit: for more information, I'm testing this on a simple .aspx page that has a text box, a button and a label, and on button click assigns the text box text to the label's text. Ideally, if I put content in the textbox that should be filtered, it is my understanding that by intercepting and rewriting the post, I can cause the stuff to hit the server as modified. I've run test though with breakpoints in the module and in code, and the module completes before the code behind on the .aspx page is hit. The .aspx page gets the values as passed from the form, and ignores any filtering I attempted to do.

Pavel Strakhov
  • 39,123
  • 5
  • 88
  • 127
Drew McGhie
  • 1,086
  • 1
  • 12
  • 26
  • 2
    This is entirely the wrong place to perform such filtering (which, no doubt, is why an existing such module isn't readily available). In particular, XSS attacks arise from data that *you return to the user* being compromised; and SQL injection arises from data that *you send to the database* being compromised. To manipulate data that *users send to your web server* long before either of the above operations take place is flawed and could lead to all sorts of errors. For example, suppose "Mr O'Reilly" submits his name to a script: that script would then be processing an incorrect surname... – eggyal May 10 '12 at 14:57
  • When you're looking at the POST, you can look at the specific values of things being sent. By looking at those values and identifying patterns of attacks (XSS, SQL, etc) you can filter that content out. I could go into each page and sanitize each input that is incorrect, but there are hundreds of places I'd need to update, and I'm hoping that I can write some generic rules in a Managed Module to speed that up. That's all. I'm really thinking that this isn't possible though. – Drew McGhie May 10 '12 at 18:35
  • does this link help? http://stackoverflow.com/questions/3240170/how-can-i-modify-a-post-request-using-a-custom-ihttpmodule-and-an-httprequest-fi – pms1969 May 16 '12 at 05:54

1 Answers1

0

There's a few issues going on here, but for future reference, what explains the page receiving the unfiltered post, as well as the filter being evaluated twice is that you are likely accessing the request object in some way PRIOR to you setting the Request.Filter. This may cause it to evaluate the inputstream, running the currently set filter chain as is, and returning that stream.

For example, simply accessing Request.Form["something"] would cause it to evaluate the inputstream, running the entire filter chain, at that point in time. Any modification to the Request.Filters after this point in time would have no effect, and would appear that this filter is being ignored.

What you wanted to do is possible, but also ASP.NET provides Request Validation to address some of these issues (XSS). However, Sql Injection is usually averted by never constructing queries through string concatenation, not via input sanitizing, though defense-in-depth is usually a good idea.

Snives
  • 1,226
  • 11
  • 21