Introduction
This is part 2 of my series Secure your ASP.NET Applications. In this article, I will describe what exactly Cross
Site Scripting (XSS) is and how a hacker exploits it and how we can prevent XSS attacks.
Background
Part 1 of this series is available here
which is about how to secure your ASP.NET applications from SQL injection
attacks.
Cross Site Scripting (XSS)
Cross-Site Scripting is a kind of security exploit in which the attacker inserts malicious code of his choice (mostly script) into
a web page or a database
without the user's knowledge. XSS in itself is a threat which is brought by the internet security weaknesses of client-side scripting languages,
with HTML and JavaScript (others being VBScript, ActiveX, HTML, or Flash) as the prime culprits for this exploit.
We can categorize XSS as follows:
- Reflected (when malicious code goes from the user's browser to the server and comes back from server)
- Persistent (when code remains stored somewhere,
example - code stored in a database and executed on the client browser over and over, which makes it more dangerous).
- DOM
based XSS attack (both reflected and persistent
can fall in this category, attacker can manipulate DOM elements and can use DOM data).
What can these attacks do:
- Create and access DOM elements
- Send information to attacker site
- Hijack
cookies, click events, credentials
How is it exploited
Following are the ways an attacker tries XSS on a web application:
- It can be done from server side code (example: ASP.NET code)
- It can be done from client side code (JavaScript/jQuery code)
- Attacker can inject script into user's experience
1. Reflected Cross Site Scripting Attack
In this kind of attack, the attacker generally tries to send script or HTML input to
the server and lets it come back to the browser and run.
They achieve it using a querystring. Although all latest browsers apply XSS filters, HTML elements can be inserted using this attack.
Also to test, you can enable XSS filters in browsers; for IE - Tools > Internet option > Security
tab > Custom level > Enable XSS filter. Let's see how to do it
so things will be more clear:
In the above example I simply pass the HTML in the query string which gets reflected in
the web page. This is just to show the attacker can use proper scripts with intention
to get your credentials.
In the above example we are passing an HTML element and script in our label which gets assigned as it is and becomes
a legal script, and the element for a page gets reflected
in our page and shows the effects. This is just a basic example of how an attacker tries Reflected XSS, scripts, and their use can be too harmful.
2. Persisted Cross Site Scripting Attack
In persisted attack, the user injects a script to the database and every time
the user visits that page he faces the consequences of that script. Example:
Script injected in the Comments section:
hiii this is text
<link rel="stylesheet"
href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" />
//these scripts are innocent (Just opening the pop up),
//that's the developer cause who developed vulnerable web applications .
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<script>
$(function() {
$( "#dialog" ).dialog();
});
</script>
<div id="dialog" title="Session Out please login again">
<input type="Text" placeholder="login"/><br/>
<input type="Text" placeholder="login"/><br/>
<button>
3. DOM based Cross Site Scripting
Both persistent and reflected can fall in this category, but some other variances of attacks make it different. Some developers do think JSON is safe and some use jQuery unsafe methods.
How they use it:
var json = jQuery.parseJSON('{"name":"sarvesh",
"girlfriendname":"\x3cscript\x3ealert\x28\x27hehaha\x27\x29\x3c\x2fscript\x3e"}');
var createelement = document.createElement('div');
document.body.appendChild(createelement);
$(createelement).html(json.girlfriendname);
As attacker is not inserting a direct script, he is inserting an encoded string which contains
a script. These are new ways an attacker finds to exploit XSS.
Or we can use a direct encoded string, I just use JSON to show this; this is also not
a safe way.
var jencoded = "\x3cscript\x3ealert\x28\x27hehaha\x27\x29\x3c\x2fscript\x3e";
Another way of attack comes under this category, i.e., using HTML elements and
JavaScript code without a script tag. The developer tries to find the script tag or <> these characters
and replace them to avoid XSS but that is not a full proof way. The following example shows that.
Sometimes we need to show a dynamic alert:
<img onmouseover=alert(user input) />
The user can give input in
a SQL Injection manner like this:
<img onmouseover=alert(1) onmouseout=alert(document.cookie) >
Now he can see the cookies you are saving, and that might be user credentials or any important data.
How to prevent XSS
- Your code output should be HTML encoded but make sure while storing data, it should not be
encoded. Encoding and storing can lead to double encoding.
< => < => &lt; => &&lt;
So for
encoding we can use AntiXss sanitizier's GetSafeHtml()
and GetSafeHtmlFragment()
. To download AntiXss, go to MS Visual Studio's Tools > Library Package
Manager > Package Manager Console > Install-Package AntiXss.
Sanitizer.GetSafeHtmlFragment(YourString)
It's better to use these methods if we really don't encode data.
- Specify page encoding in web.config because the attacker can change the encoding to UTF-7 which has
a different standard to write the lines and
can make it tough to filter out the script code in the page.
<configuration>
<system .web="">
<globalization culture="en-US" fileencoding="utf-8"
requestencoding="utf-8" responseencoding="utf-8" uiculture="de-DE">
</globalization></system>
</configuration>
- Apply content security policies to allow the script of your own host, or to allow the script of any host like Google and Microsoft.
We can add a header to stop scripting from the attacker site or any third party site.
Although it is not full proof because IE does not support this, but we can
still use this as an additional thing to stop XSS. Add the following code to allow scripts just from your host.
Response.AddHeader("X-WebKit-CSP", "default-src 'self'");
Response.AddHeader("X-Content-Security-Policy", "default-src 'self'");
- Do not use filter approach to find the script tag and replace that, there are many cheat-sheets available on the internet for XSS.
A simple example that an attacker can use:
onload=alert('anything')
. - Data validation: you can't trust the user input, just make sure the data is exactly what
your application expects.
- Don't set the
ValidateRequest
attribute to false. When it is true it might throw
an error;
to prevent this error make sure your data is properly encoded before sending it to the server. - Be concerned where DOM elements are being created and modified. Use functions such as
setAttribute
and document.createElement('div')
rather than document.writein
and $('div').html()
.
- Force the user to update IE 6 which is very much vulnerable to XSS.
IE6update.com is a better solution for that.
- Audit every place where data is assigned. Know your control behavior as
a label can't post the values and text-box can.
So better encode text-boxes first. You can use a third party control to check the vulnerability; for Firefox use
XSS-ME and for
Chrome can use
DOM-SNITCH.
- Update yourself on regular basis ,check new ways of the same attack. The
attacker invents new ways to do the same attack in their spare time.
OWASP
has a very good cheat sheet and defense for XSS.
OWASP
has regular updates about these attacks.
- Know ASP.NET encoding ways and use proper config statements to make changes.
All the above mentioned methods are useful to prevent XSS attacks.
References