In code behind, we handle the OnClick event of the button. In the handler, we get a UserInfo object from the database. Finally, we render the first name entered into the text box via the label.
Now there is a possibility of XSS attack. The attacker can simply create a user with a first name "<script>alert(1)</alert>". Anyone who sends a request to a page where the attacker's first name would normally be displayed, gets the HTML code injected and executed on their machine (the user gets an alert showing "1").
Now we have another standard .aspx page with a label:
In code behind, we have this code:
What can XSS attack do
In cross site scripting, the attacker can insert any kind of code into a page which is interpreted by the client browser. So, the attacker can, for example:
- change the look of your site,
- change the content of the site,
- redirect the page to an evil one,
- force the users to download malicious code (typically a virus).
You may think that any at least a little advanced user wouldn't click a link like:
Yeah, but what about a link like:
Can you read that string? It is the same string as the first one, only in hexadecimal encoding, so the browser receives the same text.
Finding XSS vulnerabilities
The first way to find XSS vulnerabilities is based on trying. Simply insert a test string into all inputs and URL parameters. Use strings like:
You can also try to change the HTTP request (for example, if you are using the Firefox browser, you can use add-ons to change the user agent, referrer, etc.).
Another way is to find vulnerabilities in code. You can search for all spots where properties (of Kentico CMS's objects) are used and check whether they are HTML encoded when they get rendered on the page. This is the best technique of searching for persistent XSS.
You can also search for spots where context variables (HTTPContext.XXX, HTTPContext, Server, Request, request.querystring - this one is the most important) or URL parameters (QueryHelper.GetString()) are used. This way, you can find non-persistent XSS.
- document.location (and many of its properties)
The last way is to use automatic tools for vulnerability searching. These tools are based on similar techniques as manual searching, while they work automatically. However, they often find far too many false positive vulnerabilities and using them is much less effective. The reason for that is simple – these tools (at least those that aren't based on formal verification – about 99% of them) use brute force, while you can use your brain.
Avoiding XSS in Kentico CMS
Why would the attacker be able to perform all types of XSS attacks in the previously specified code examples?
- HTMLHelper.HTMLEncode() – encodes HTML tags, replaces the < and > chars with their HTML entities.
- QueryHelper.GetText() – gets a HTML encoded string from the query string.
- ScriptHelper.GetString() – replaces special chars like an apostrophe (alt+39).
- Correctly keep the type, using for example QueryHelper.GetInteger().
- Use transformation functions: HTMLEncode(), StripTags().
Where should you protect your code?
Always on the output before rendering. The reason is that you should secure your web, but you do not want to change the users' input data. You also should not exclusively rely on input validation.
It is also a good practice not to let anyone read cookies, as cookies are usually the main target of XSS attackers. You should make it impossible to access cookies on clients by configuring cookies to be http only – see Web.config file settings.
Examples of server-side protection from XSS vulnerabilities
If you have a string value which is taken from the database, you must encode it with HTMLHelper.HTMLEncode() before you set it to a control's property (e.g., label text). For example:
If you have a string value taken from query string (even if it's called id) and you plan to render it to output (i.e. some information message), use QueryHelper.GetText() instead of QueryHelper.GetString(). For example:
Always encode your dynamic parts with ScriptHelper.GetString(), even if you have already HTML encoded them. In this case, the attacker does not have to insert any HTML tags (e.g., <script>) because you have already inserted them. The protected code should look like this:
Protect your code against XSS when writing transformations. You can use the HTMLEncode method and validation methods. For example, you can encode the manufacturer name in product listings:
You can find other transformation examples in T topic.
- Encode strings before they are rendered.
- Encode all strings from any external source (user input, database, context/environment, URL parameters, method parameters).
- Use HTMLHelper.HTMLEncode() to encode strings from any external source.
- For URL parameters, you can use QueryHelper.GetText() if that value goes directly to output (i.e. the value is not saved to the database, filesystem, etc.).
- Configure cookies as http-only.