Inside the new ValidateRequest feature
Note: this entry has moved.
I’m not going to repeat here what is already written in the docs or in additional articles. Also I believe that looking at this picture will help understand the following text.
This new feature is implemented by new methods added to the existing System.Web.HttpRequest type plus a new helper type named System.Web.CrossSiteScriptingValidation.
In HttpRequest, the get accesors for properties QueryString, Form and Cookies had been modified to check for dangerous content in the items of the collections they are wrapping before returning them. This new behaviour is only active if ValidateRequest is set to true (either at the Page or application-level; note that true is the default value). If you explicitly set ValidateRequest to false no validation will occur.
There are two new methods for validating the previously mentioned collections: ValidateNameValueCollection and ValidateCookieCollection. Why two different methods? Because the types of items to be validated are quite different and may require special handling. Let’s see this in detail:
ValidateNameValueCollection validates the items of a NameValueCollection, which is a collection that stores name/value string pairs, i.e.:
Name/Key |
Value |
FirstName |
Catalina |
CustCode |
532 |
__VIEWSTATE |
dDwtMTI3OTMzNDM4NDs7Pn2S7p |
This method will check the Value string for each item but __VIEWSTATE as there is no sense in checking it for dangerous content.
ValidateCookiesCollection validates the items of an HttpCookieCollection, which is a collection of HttpCookie objects. The HttpCookie type has quite a bit more information than the simple name/value pair that we previously saw; it has properties like: Expires, Domain, Path, Value, Secure, etc. Like the previous one, this method is only interested in the Value property of the stored items. In this method there is no special handling of items like the __VIEWSTATE case shown above, every item in the collection is checked.
Both Validate* methods don’t contain any validation logic coded into them; they just loop through the items in a collection calling the ValidateString method and passing to it each item’s value as an argument. ValidateString still doesn’t implement any validation logic by itself; it uses a new private helper type named System.Web.CrossSiteScriptingValidation (yes, I said private, so forget about extending the validation logic) that has a couple of methods who check for different kind of dangerous content. How this CrossSiteScriptingValidation type looks like? It has four private static methods with very self describing names (IsAtoZ, IsDangerousExpressionString, etc) that perform the actual validation work and it exposes an internal static method named IsDangerousString that is called by the HttpRequest.ValidateString method previously mentioned.
The forgotten collections
As far as I can tell there seems to be no checking against the Headers and ServerVariables collections. I agree these are not so ‘popular’ as the previous three, but if the attempt was to offer maximum security right out of the box I don’t know why they’ve been excluded. Anyway, it should be great to hear some ‘official’ comments on this J
Documentation and cosmetic VS.NET bugs
Lastly, there is one new public method HttpRequest.ValidateInput that the docs describe as: “Validates data submitted by a client browser and raises an exception if potentially dangerous data is present”. This phrasing has already caused some confusion on the public newsgroups. Most people expect this method to perform the validation logic and to raise an exception if dangerous data is encountered (well… they’re just expecting what the docs describe). Unfortunately this is not really what this method does which is to just set three flags (one per collection) that will cause validation to happen later when any of the collections are accessed. Because of this, people write code like:
[C#]
try
{
HttpRequest.ValidateInput();
}
catch(HttpRequestValidationException e)
{
// handle an HttpRequestValidationException
// that will never be thrown by the code in the try block
}
While still at the Bugs Dpt., it seems like VS.NET 2003 has not catch up with this new feature; when a page is selected the Properties window doesn’t shows a ValidateRequest property that would map to the ValidateRequest attribute of the @Page directive (as it actually does with other properties like Trace, Culture, etc.)