ASP.NET 4.0 + WCF Rest Services and the request validation problem

by Stefano Mostarda 19. March 2011 01:48

Some days ago I was working on ASP.NET 4.0 project with several WCF REST services invoked from javascript. Everything worked fine except for a nasty problem which affected our REST services: input was not validated. Let's lay the background.

Request validation is the ASP.NET feature which prevents the user from submitting malicious data. If the user enters in a text box something like "<javascript type="text/javascript">alert(1);</javascript> and submits the page, ASP.NET blocks the request because it detects that the input is malicious. Data Request validation is a feature that's always been in ASP.NET since 1.0 version. The main problem which affects request validation in version previous to ASP.NET 4.0 is that it is triggered only for aspx pages. It means that request validation isn't triggered for handlers and services. ASP.NET 4.0 has maintained compatibility with the past, but has also introduced a new request validation model. The request validation in ASP.NET 4.0 is triggered before the Begin Request which means that all request in the ASP.NET pipeline are examined including handlers and services. The validation is also extensible, we can create a new class which inherits from RequestValidator to inject our validation logic (it turns out to be particularly useful when using WIF). In such class we just have to override the IsValidRequestString method.

public class MyRequestValidator : RequestValidator
{
  protected override bool IsValidRequestString(HttpContext context, string value, RequestValidationSource requestValidationSource, string collectionKey, out int validationFailureIndex)
  {
    validationFailureIndex = 0;
    //my logic
    return base.IsValidRequestString(context, value, requestValidationSource, collectionKey, out validationFailureIndex);
  }
}

Finally we have to register such class in the httpRuntime node of the web.config file.

<httpRuntime requestValidationType="MyRequestValidator, MyAssembly"/>

The IsValidRequestString method doesn't receive all request values at once, but is invoked for each value in the request. For instance, if a request has 8 headers, 3 values in querystring and 20 values in post, the IsValidRequestString is invoked once for each of them which means 31 times.

Let's get back to the problem. What was happening in my case, is that validation was triggered (the IsValidRequestString from my custom validator class was hit), but POST data coming from the REST call weren't inspected. The IsValidRequestString method was invoked only for the request's headers. I investigated a bit and discovered that the problem was in the content-type header. I used the following jQuery code to issue the REST call:

$.ajax({
    dataType: "json",
    data: "{ \"key\":\"value\" }",
    contentType: "application/json; charset=utf-8",
    type: "POST",
    success: function (response) { ... }
  });

I just changed the content-type from "application/json; charset=utf-8" to "application/x-www-form-urlencoded" and everything were validated; even POST data. I don't know if it's the best solution, but it's a solution which passed all our security tests.

To ensure that everybody called the REST service using the right content-type, I created the AjaxSecure function in a jQuery plugin so that everyone in the team invokes that function instead of the Ajax function. The AjaxSecure function just set the correct content-type before invoking the Ajax function.

(function ($) {
    $.extend({
        ajaxSecure: function (obj) {
            $.extend(obj, { contentType: "application/x-www-form-urlencoded" });
            $.ajax(obj);
        },
    });
})(jQuery);

Stay tuned...

Comments are closed

Calendar

<<  August 2014  >>
MoTuWeThFrSaSu
28293031123
45678910
11121314151617
18192021222324
25262728293031
1234567

View posts in large calendar