08 Aug, 2017

Dude, Where’s My Request Validation?

by Rich Grimes

While in the process of migrating our ASP.NET on-demand training course to ASP.NET Core, I noticed ASP.NET Core 1.0 did not include a similar feature to ASP.NET’s Request Validation.

Given that ASP.NET Core has some significant changes from ASP.NET, it doesn’t surprise me to find a feature missing. As ASP.NET Core is supposed to be the leaner cross-platform version, namespaces, classes, and features are going to change. However, what concerns me, is on a routine basis we perform security assessments on ASP.NET applications where the only protection against Cross-Site Scripting (XSS) is the Request Validation feature.

So, this got me thinking. Will developers know Request Validation is missing? How many ASP.NET projects will be migrated with the assumption that Request Validation is present? Why hasn’t Microsoft made this change more obvious? How do we get the word out?

What Is ASP.NET Request Validation?

If you are new to ASP.NET or not familiar with the Request Validation feature, let me give you a quick overview, then show examples of an XSS attack in ASP.NET and ASP.NET Core.

Request Validation has been a feature of ASP.NET since version 1.1. It examines HTTP requests for potentially dangerous content such as HTML markup and JavaScript. If dangerous content is discovered the request is terminated and an error message is returned to the browser. ASP.NET performs this check on the request body, headers, query string, and cookies. This examination is performed to help prevent a malicious user from exposing other users to arbitrary JavaScript in an attack referred to as a Cross-Site Scripting (XSS).

Keep in mind, even though the Request Validation feature is popular among ASP.NET developers, it has its limitations, and was never intended to be an end-to-end solution to protect against XSS attacks. As James Jardine mentioned in his blog article titled The end of Request Validation, Request Validation was designed to only support HTML context for XSS. It was not designed to protect attribute, URL, JavaScript, and CSS contexts.

Let’s first look at the following HTTP request from an ASP.NET MVC application. We can see the attacker embeds malicious JavaScript in the Message parameter.

alt text

As the server accepts the HTTP request we can see below that an application exception is thrown since Request Validation found the dangerous content. The malicious content never makes it into the application.

alt text

Now lets take a look at an ASP.NET Core HTTP request containing the same malicious JavaScript.

alt text

Below we can see that the results are different this time. ASP.NET Core did not examine the HTTP request for potentially dangerous content thus allowing the JavaScript to be reflected back to the client and executed in the user’s web browser.

alt text

Now that you have some familiarity of what the Request Validation does, you can probably see why I have some concerns about ASP.NET web projects being migrated to ASP.NET Core. As the above examples show, if the application only relies on Request Validation for XSS protection, there is a good possibility security vulnerabilities will be introduced into the application by migrating the application to ASP.NET Core.

Where Is The Communication?

So why the lack of documentation? From what I can tell there has been minimal, if any notification about Request Validation being excluded from ASP.NET Core to the development community. Request Validation has been a staple of ASP.NET for over a decade. The ASP.NET development community has relied heavily on the feature. So why haven’t we seen more communication?

When I first noticed that ASP.NET Core was not protecting the application from malicious content, I started searching for documentation on ASP.NET Core Request Validation. There were two resources I stumbled upon that helped me. The first being a Stack Overflow question where someone asked, how to enable Request Validation in ASP.NET Core. In the answer to the question the author explains that ASP.NET Core does not have a feature similar to Request Validation. Included in that explanation was a link to the second resource which was a discussion on the ASP.NET Core issue, “Default middleware for request validation, like IIS has”. In that discussion, it is explained that Request Validation will be excluded from ASP.NET Core and the focus for ASP.NET Core will be to encode output by default.

Where Do We Go From Here?

No more Request Validation, now what? Well first off let’s remember the function Request Validation performs in applications. It adds a layer of data validation, which checks for malicious content in the incoming request. So how do we replace the data validation, you ask? If you read the ASP.NET Core issue I referenced above you saw part of the discussion mentions data validation should be performed on the inbound model, not the request.

Not familiar with ASP.NET MVC and the term model? Let me give you a brief explanation of how models are used when data is stored in a database. The model is the class the represents data in the database. Each instance of the model can correspond to a row within a database table, and each property of the model can map to a column in the table. On HTTP Request, posted form values are mapped to the model properties and sent to the action method in the controller. This is where data validation comes into play.

When performing data validation on models I recommend adding Data Annotation attributes to your model classes. In ASP.NET Core the System.ComponentModel.DataAnnotations namespace provides a list of attributes that allows us to describe the rules we want applied to the model class and it’s properties. MVC will handle the enforcing of the rules and display the appropriate messages to the user.

Using the ASP.NET Core example from earlier, let’s explore what Data Annotations give us. First, let’s take a look at the data annotation as they are applied to the model properties. For this example, I used the Required, StringLength, and RegularExpression attributes to perform some basic data validation. The DisplayAttribute tells ASP.NET Core what name to display in the view.

alt text

ASP.NET Core will create the client-side jQuery validation during the creation of the view. Looking at the below image you will notice client-side validation being performed based on the attribute rules applied to the model properties.

alt text

Next, we can see the same level of data validation being performed on the server side as was done on the client side. Here we have the altered request that includes the JavaScript.

alt text

The action method in the controller will check to see if the model state is valid. In this case, the Message property does not pass the rules assigned to the property. The controller returns the model error message to the web browser where the message is displayed.

alt text

As we can see by adding a few attributes to the model properties, the application now has its own layer of validation. Another reason for using Data Annotations is its flexibility. Rules can be placed on the class or you can create your own custom annotations. Keep in mind, since the validation rules are assigned to the model you can validate the model data in any layer of the application.

Data Annotations are great for validating the incoming data, but what about the data that is reflected out to the user’s web browser? If you remember from earlier I mentioned that part of ASP.NET Core issue discussion was about the focus being on ensuring that all output is encoded to the proper context before being sent to the web browser. Let’s take a look at what encoding offers us.

Building on the XSS example from above I changed the rules for the Message property to allow the characters and symbols of the JavaScript used in the example. There are no rules preventing me from submitting the message with the JavaScript. The application accepts the request and model data. The application sends the Message data in the response. Looking at the image below we can see the web browser did not execute the JavaScript. Instead the JavaScript is displayed as text.

alt text

The reason the JavaScript was not executed in the web browser was because ASP.NET Core automatically encoded the content when rendering the view. If we take a look at the HTML that builds the page we can see the special characters in the message were HTML encoded.

alt text

When defending against XSS, the primary defense should always be output encoding. The Razor view engine makes this easy for developers by providing HTML encoding by default when using @. For example, the code @ViewBag.TheMessage was used to display the message in the above screen shot. By utilizing @ViewBag our content was automatically HTML encoded. However, there is one exception when using the @. The @HTML.Raw helper method will not provide encoding as it makes the content part of the HTML in the view. If you need to use @HTML.Raw to display HTML markup, make sure user controlled data is encoded in the proper context before adding it to the HTML helper. The encoding can be achieved by using the ASP.NET Core public static property System.Net.WebUtility.HtmlEncode.

Even though Request Validation is gone from ASP.NET Core, we can still protect the application data and our users by implementing data validation and contextual encoding. Now granted if you are using ASP.NET MVC and not ASP.NET Core, it is still good practice to implement data validation and encoding. Also, keep in mind that Data Annotations and encoding are not specific to ASP.NET Core, and are is also available in ASP.NET MVC.

In Conclusion

So yes, the beloved Request Validation feature was removed in ASP.NET Core 1.0. Now that we know this let’s get the word out. Development teams need to be aware that a major feature providing a layer of security has been stripped from ASP.NET Core. If you are on a development team making the switch over to ASP.NET Core, keep in mind that while data validation is still possible, the proper mitigation for XSS is contextual encoding. Adding a layer of data validation can add to the security posture of the application, but is designed to enhance user experience and efficiency.