When Should I Encode?
A common question I hear from developers is when should they encode their data. Protecting against cross-site scripting can actually be difficult, and it is good to hear the enthusiasm to properly encode. I have seen developers HTML encode their data before storing it in the database, right as they pull it from the database, in a business layer and many other places. So is there anything wrong with these techniques? Maybe not, depending on the context that data is going to be used in.
The first question a developer needs to know when deciding to encode their data for output is what context will that data be used in. As I mentioned before, cross-site scripting can be challenging to fix. Will the data be output in an HTML Element context? What about as an attribute? Maybe as a URL, or javascript? Maybe it is not going to the browser, but to LDAP. I think you get the point. All of these really have different encoding techniques due to the characters that need to be encoded.
Lets think about HTML encoding our data before storing it in the database. At that point in the application, do we know with 100% certainty that the data is only used in a HTML Element context when it is output? And not at just this point in time, but going forward after updates to the application. With time to market requirements, applications are changing rapidly.
Lets just assume we are talking about a Company Name data input. Maybe when I first build the application it is only output to the browser as a label so it is in a HTML element context. So HTML Encoding this before it goes to the database would work right now. What happens if down the road in the next release, we include the company name in a attribute as the alt text of an image for our company logo? Now the data is in an HTML Attribute context. In .Net 4.0, this would be a bad example since HTMLEncode and HTMLAttributeEncode encode the same characters, but what about if you are using an earlier framework like 2.0? You would now still be vulnerable to cross-site scripting. What if this data was used in JavaScript or in a URL? Maybe a report service has been set up and now we are including this data in a Crystal Report, or some other report. Do we have to decode the data before sending it to the selected report? Things really start getting interesting.
As you can see, it is difficult to really grasp all the places our data will be used throughout the lifetime of our applications. I always recommend to developers that they encode at the very last moment before they send the data to the external system. I know I am using cross-site scripting as the example, but this goes for all injection mitigations.
So why the very last moment? There are a few reasons for why I recommend this.
- This is really the only time you know the exact context the data is going to be used in. Even if this is a class level variable in a code behind file, only at the exact point of output do you know what the context is.
- It makes code review much easier because the reviewer can see the explicit encode at the point where it needs to be done. This saves a lot of time because the reviewer does not need to do a lot of tracing through the application to see if it got encoded previously. It also reduces using the wrong encoding context when it is explicit on the output.
- It is easy to check if a developer missed an encoding. No one is assuming the data is already encoded some where up the line.
If you are using the same data element many times in a single response and are concerned with the performance of encoding this data at every output there is a possible alternative. You could create a variable and store the encoded version of the data in there. This would allow only encoding once, but using the same data many times. It is IMPORTANT that if you are going to use this method, the name of the variable should indicate what type of encoding the data is. This allows you to know what context it will work for, as well as let other developers know the data is not in its raw form.
If you just use a variable like “ var companyName “ then there is no indication that this is encoded. But if you use “ var companyNameHTMLEnc “ then it is more obvious that the data is not in raw form. In most cases I would not recommend doing it this way as it could get confusing, but if you are gong to use a variable to hold your data, this would make things more simple.
This is not the only way to handle when to encode, just my preferred way.