This article originally appeared at Microsoft Canadian Developer Connection.
What is cross-site scripting?
Cross-site scripting wasn’t viewed as a “real” attack until the famous “Samy Worm” that hit myspace.com in October 4, 2005. The worm carried a payload that would display the string “but most of all, Samy is my hero” on a victim’s profile. When a user viewed that profile, they would have the payload planted on their page. The worm infected over one million users within just 20 hours. Samy was sentenced to 3 years probation without computer user, 90 days community service, and an undisclosed amount of restitution.
Why Is it a big deal?
Cross-site scripting is an attack that targets the application users. The simplicity of cross-site scripting is also why it is so powerful. If the application is vulnerable to cross-site scripting, the developer is not in charge of what runs on the user’s browser anymore … the attacker is.
Cross-site scripting could be used in attacks like authentication hijacking and session hijacking. The power of cross-site scripting manifests itself even more when combined with cross-site request forgery, which is exactly what happened on April 14th, 2009 when a guy named Mickey hit Twitter with a worm that leveraged both cross-site scripting and cross-site request forgery and forced Twitter to lock some of their users out of their accounts in addition to going into the dark for a few hours.
Effective controls in .NET Framework
ASP.NET is one of the best frameworks that built-in cross-site scripting mitigations into the framework. Understanding these mitigations and their limits is key to properly finding cross-site scripting without falling into the false-positive trap. Here is a brief overview of what the framework offers:
- Request Validation: is a feature in ASP.NET that examines an HTTP request and determines whether it contains potentially dangerous content. When Request Validation is enabled, ASP.NET performs this check for URL query string, cookies, or posted form values. The following is an example of Request Validation in action.
The code behind uses values retrieved from the request to fill in the values for these two controls.
Now because the Label control is not doing any encoding on its own, it will be vulnerable to cross-site scripting attacks, while the TextBox control will not be vulnerable to cross-site scripting attacks.
Notice how a cross-site scripting payload was injected in both values but only the Label control executed. Looking at the HTML source code of the page confirms this. Notice how the Label’s payload was not encoded while the TextBox’s was indeed encoded.
Understanding the Different Cross-Site Scripting Contexts
Cross-site Scripting remains one of the most common vulnerabilities found during web application security assessments, I can safely say from my experience professionally performing security code review for tens of ASP.NET applications, the average for me has been at least 9 out 10 web applications had one or more cross-site scripting issues.
There are several reasons for the prevalence of this beast. While the lack of input validation and output encoding remain the top two reasons to blame for the dominance of cross-site scripting. The developers’ unfamiliarity with the differences between HTML contexts could definitely score the third place in the list of top reasons.
HTML has 5 contexts, and each one of them will need a slightly different encoding in order to mitigate malicious scripts in that particular context, so while performing security code reviews, it is very important to understand which context the unsafe data will run in, and depending on that you will be able to decide whether the encoding done (if any) is enough. The 5 HTML encoding contexts are as follows:
- HTML Context: data that is rendered inside HTM tags like div, p, td, etc
- HTML Attribute Context: data that is rendered inside simple attributes like width, name, value, etc
- CSS Context: data that is rendered inside a style tag or inline style attributes.
- URL Context: data that is rendered inside an href of anchor tags.
Understanding HTML contexts is key to beating cross-site scripting right on Zirakzigil , since one context’s encoding will not work for the others. When you understand this concept properly, you will be able to find cross-site scripting issues a whole lot easier. Usually, encoding controls will encode the most dangerous five characters: < > “ ‘ &, encoding these five is enough in the HTML context for example, but definitely not enough for the other 4 contexts.
Cross-Site Scripting Prevention Cheat Sheet from OWASP provides a thorough look into the differences between the different contexts and complete prevention techniques to mitigate cross-site scripting issues. Troy Hunt – MVP provides an excellent ASP.NET resource on how to mitigate this beast in your ASP.NET applications.
How to Review Your Code for Cross-Site Scripting
Understand the types of Cross-Site Scripting – There are three major types of cross-site scripting:
- Reflected Cross-site Scripting and this is the easiest to review, because you are basically looking for data retrieved from the request and used in a response directly.
- Persistent Cross-Site Scripting which happens when the application saves untrusted data retrieved from untrusted sources, usually in the database, and then this data is retrieved later and used to construct HTML back to the user. This type is harder to review because you will need to find out for each piece of data rendered to the user, whether it was originally retrieved from an untrusted source or not.
- DOM-Based Cross-Site Scripting the main difference between reflected and persistent cross-site scripting from one side and DOM-based on the other side, is that persistent and reflected cross-site scripting result from server-side code weaknesses while DOM-based is client-side code weaknesses.
Understand Your Configuration – While ASP.NET framework provides some mitigations against cross-site scripting vulnerabilities, it also gives you the luxury of changing these configurations on-demand. The goal of this step is to understand which settings the application is currently using.
- RequestValidationMode: There are two values for this: “2.0” and “4.0” (default). If “2.0” is specified then request validation options has to be reviewed on a page by page basis, since disabling it on one page will override the setting in web.config.
- RequestValidation: if request validation is disabled then the application is wide open to cross-site scripting.
- If this is turned on, you will have to make sure that none of the web form pages turned it off. The following example shows a page that turned request validation off.
Look for the Bacon – During this step, are we looking mostly for code in the application that uses untrusted data whether retrieved from the request, the database or any other untrusted source, and uses that to build HTML back to the user. This is definitely not an easy task, but the job could be easier if you know where to look. Once you get a hang of this, it becomes easier afterwards where you can automate your search using CAT.NET, FxCopor good old regular expression.
Data Binding: Data binding is used basically to establish a connection between the application UI and business logic. Data binding is usually a very fertile ground to look for cross-site scripting issues, these are three questions to help you figure out quickly whether there is a Cross-Site Scripting issue in data binding code:
- Where is the data coming from and whether it originated from an unsecure source?
- What is the HTML context that this data will run in?
For example, the code below binds untrusted data retrieved from the request
Here is how the data looked like in the database, notice the cross-site scripting payload in the first record.
And the result was a very bad cross-site scripting attack when this page was rendered.
Don’t forget databinding using data binding expressions with <%# %> using Eval() or Bind() methods. For example:
Embedded Code Blocks (<%= %> syntax): which is free form server code that executes during the page’s render phase. Consider the following example for instance:
Including a cross-site scripting payload in the query string indeed led to a cross-site scripting exploit.
Code Nuggets (<%: %>): embedded code blocks are the worst because they are almost a sneaky way to get out from ASP.NET protections and leave the door open for cross-site scripting, that’s why ASP.NET came up with “Code Nugget Blocks” syntax replacing the “<%= %>” with “<%: %>”, and this basically performs HTML encoding by default. However, you gotta be careful, because the code nugget blocks does encode the major five characters: <, >, “, ‘ and &. These five characters are enough to mitigate cross-site scripting in HTML context but not enough to mitigate it in any of the other contexts. So I did a quick test to understand which character exactly does code nugget blocks encode:
And sure enough, only the basic five characters are encoded as show in the following HTML source:
While this is awesome functionality in ASP.NET, you will have to understand what it protects from and what it does not protect from while reviewing code for security issues.
Now because the code is building the client script using unvalidated and unencoded data, this could become very dangerous, here is the result of this if a malicious script was provided.
Reviewing your code for cross-site scripting issues could get very challenging, but getting an understanding of why cross-site scripting happens, the different HTML contexts, as well as understanding the common places to find cross-site scripting make the task a whole lot easier.
Static code analysis tools are an essential part to code review for cross-site scripting issues, but learning the skills manually is essential prior to starting the process. Once you understand what you are looking for in the code, automating the process becomes easier.
Finally, getting better at security code review is not so much different than getting better at programming, the same techniques apply in both, by practice! So take the time to review your code, your peer’s code and have fun with it. In addition, there are applications to help you out learn more about application security,SuperSecureBank (the application I used for the examples in this article) is free and available for anyone who would like to enhance their application security skills, the main purpose of these apps is to teach you application security without getting into trouble breaking into real applications.