This post was most recently updated on March 15th, 2016
This post demonstrates how we can handle gracefully the HTTP request validation which exists in ASP.NET, when using ASP.NET MVC. Request validation is a feature in ASP.NET that examines an HTTP request and determines whether it contains potentially dangerous content. For example, if a user tries to input some malicious code in a field using the script element, the ASP.NET throws a “potentially dangerous value was detected” error and stops page processing. Without this validation, the site is vulnerable to this exploit typically referred as a cross-site scripting (XSS) attack.
Consider this form
Here is the error when the user tries to submit a field with HTML elements, pressing the Save button
We can disable this validation at a field, action, controller, or application level. But we have to think about the consequences of disabling it and being vulnerable to an XSS attack. Instead of disabling it, I want to continue validating the potential dangerous requests, but rather than throw the error and stop processing, I want to add a validation message for the field that is violating the validation.
In ASP.NET MVC, we can do this using a custom default model binder. The model binding is the mechanism that automatically populates the controller action parameters, taking care of the details of property mappings and type conversions. The default model binder in ASP.NET MVC is the class DefaultModelBinder . The good news is that we can have a custom default model binder. In our case, we want to inherit the DefaultModelBinder, overriding the main method BindModel, and handle the exception HttpRequestValidationException which is thrown when a potential dangerous request is detected
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
public class DefaultModelBinderWithHtmlValidation : DefaultModelBinder { public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { try { return base.BindModel(controllerContext, bindingContext); } catch (HttpRequestValidationException) { Trace.TraceWarning("Ilegal characters were found in field {0}", bindingContext.ModelMetadata.DisplayName ?? bindingContext.ModelName); bindingContext.ModelState.AddModelError(bindingContext.ModelName, string.Format("Ilegal characters were found in field {0}", bindingContext.ModelMetadata.DisplayName ?? bindingContext.ModelName)); } //Cast the value provider to an IUnvalidatedValueProvider, which allows to skip validation IUnvalidatedValueProvider provider = bindingContext.ValueProvider as IUnvalidatedValueProvider; if (provider == null) return null; //Get the attempted value, skiping the validation var result = provider.GetValue(bindingContext.ModelName, skipValidation: true); Debug.Assert(result != null, "result is null"); return result.AttemptedValue; } } |
So, what we do is quite simple: we catch the HttpRequestValidationException exception and add a validation error message to the ModelState specifying the field name that is violating the request. Next we read the attempted value, skipping the validation and return. In our action controller we can’t forget to check if the ModelState is valid.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
[HttpPost] public ActionResult Create(MyModel model, string fieldArgument) { if (ModelState.IsValid) { //The model is OK. We can do whatever we want to do with the model model.MyMessage = "Model Ok Updated @ " + DateTime.Now; } ViewBag.FieldArgument = fieldArgument; return View(model); } |
Next we have to register our binder as the default binder. We do this in the application start
1 2 |
//Register our binder as the default model binder ModelBinders.Binders.DefaultBinder = new DefaultModelBinderWithHtmlValidation(); |
Fantastic. Thanks for sharing this valuable information on the HTTP request validation which exists in ASP.NET, when using ASP.NET MVC . this one way of Action binding to the interface is clear.
I hope you will keep sharing more such informative articles.