Introduction
In this article we will try to see what is Cross Site Scripting(XSS).
We will try to see some samples
that are vulnerable to XSS and try to inject some scripts. We will then see how we can prevent XSS attacks
in an ASP.NET website.
Background
Cross Site scripting is one of the problem that has plagued a lot of websites. According to
WhiteHat Security Top Ten more than 50% of the websites are vulnerable to cross site scripting.
As a web developer, it is important to understand what is cross site scripting and how can we
safeguard our site from such attacks.
Cross site scripting is nothing but injection of client side scripts into a website. These scripts
can be HTML scripts or JavaScript scripts. Now the question would be how can a person inject scripts
on a running page. This can easily be done using all the various ways a website is collecting inputs. Cross site scripting can be performed by passing scripts in form of:
- TextBox (input controls)
- Query Strings
- Cookies
- Session variables
- Application variables
- Retrieved data from an external or shared source
Now let us see some very rudimentary example of cross site scripting and then we will try to
see what ASP.NET provides to prevent cross site scripting. We will also look at the best practices that
needs to be followed in order to make our website safe from cross site scripting attacks.
Using the code
Now before writing applications that are vulnerable to cross site scripting we should know that
ASP.NET provides some security out of the box against such attacks i.e. RequestValidations
. This is a good thing for an ASP.NET
developer. We will talk about it in the later part of the article but for now lets us see how can we disable
this prevention mechanism.
Getting the Test Project Ready
The first thing that we need to do to disable the request validations is to set the ValidateRequest
property of the
page directive to false
. If we need to do this for the whole website then we can do this from the web.config pages
element.
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" ValidateRequest="false" %>
Now in order for the above setting to work we also need to change the requestValidationMode
of the httpRuntime
to
2.0
. The request validation will only be turned off when this mode is set to 2.0
otherwise it will not work.
<httpRuntime requestValidationMode="2.0"/>
Note: We are disabling the request validation because we want to test the cross site scripting. without
disabling it wont be possible to see cross site scripting in action. It is not recommended to turn off
requestvalidation
in production environment because this will open the website for cross site scripting attacks.
Perform XSS using Query Strings
Now let us create a simple web form that will simply accept a query string from the user and display the query
string values on page.
The code behind for the page looks like:
protected void Page_Load(object sender, EventArgs e)
{
string id = Request.QueryString["id"] as string;
if (id == null)
{
lblId.Text = "NA";
}
else
{
lblId.Text = id;
}
}
Now under normal circumstances this will work just fine but if I try to pass some script in the
query string variable then we have a problem. Let me now pass the query string parameter as:
Default.aspx?id=<h3>Hello from XSS"</h3>
and now when we open the page
And now we have a problem. The user can pass any HTML from the query string and that HTML will be rendered
on the page. This was a very basic example but imagine an HTML with absolutely positioned tags and images could
possibly wipe out the original page and show something else entirely.
Same thing can happen with JavaScript too. I can inject any javascript into this page. Let us try this:
Default.aspx?id=<script>alert('you have been hacked');</script>
and the output will be
Now we can go crazy and try to write this javascript to manipulate DOM objects in any manner.
Perform XSS using Input fields
Let us now create a simple textbox
to accept the user name and then display the user's name on the page
with some welcome message.
The code behind for the button click looks like:
protected void Button1_Click(object sender, EventArgs e)
{
lblMessage.Text = "Hello " + TextBox1.Text;
}
Now everything will work fine under normal input scenarios but as soon as we try pausing some HTML and Javascript
in the textbox, the problem will come in front of us. Lets put an image on the page
on top of everything else on page by using the following input in the textbox:
<img src="dilbert-03.jpg" style="position:absolute;top:0;left:0;display:block"/>
So we saw how we can inject client side script easily in the pages using Cross site scripting attacks. let us see
what we need to do from an ASP.NET developer's perspective(or as a web developer) to curb these attacks.
Prevent Cross Site Scripting
ASP.NET websites developers have some advantages over other technologies because ASP.NET has
some cross site scripting prevention logic baked into the framework itself i.e. RequestValidations
. In our earlier
examples we disabled it to check the cross site scripting but it is not at all recommended and should
not be disabled unless it is a must.
If we enable the page with RequestValidation
as true then we will get an error rather than modified page.
But apart from this in built default prevention mechanism developer should always follow the
following guidelines to prevent XSS.
- Constrain the user input to the characters that are acceptable for that particular field.
- Never trust user input. Always encode all the user inputs before processing them.
- If data is coming from an external source or a shared source, never show raw data.
Always encode the data before displaying it to the user.
Now let us go back to our XSS prone page again. We will add one more textbox and button on the page to see how we
can constrain user input.
We can always use JavaScript filters to constrain the user input. Let us apply some javascript based filters on this new
text box so that we will only accept alpha numeric characters and noting else.
<asp:TextBox ID="TextBox2" runat="server" onkeypress="return AcceptAlphaNumericOnly(event, false, false);"></asp:TextBox>
Now this will prevent the user from typing any unwanted characters in the textbox. We should also check for and remove
the unwanted characters on server side too because client side scripts can be bypassed easily(even in the above text box
we can paste the copied scripts).
Note: This code is using a small s file meant to validate and filter the user input. This file and its details
can be found here: A Tiny Javascript Framework for Common Validation Scenarios.[^]
Now as for the encoding the user input part. Let us add a similar textbox again and put the the logic
for encoding the user input in for this.
protected void Button3_Click(object sender, EventArgs e)
{
string rawInput = TextBox3.Text;
string encodedinput = Server.HtmlEncode(rawInput);
lblMessage3.Text = "Hello " + encodedinput;
}
Now if we try to inject something in using this textbox, the output will be
Same should be done if the data is coming from an external or shared source. We should never trust the
data that is not created by us.
So now we know some basic prevention mechanism that could prevent our site from cross site scripting.
Along with these mechanism, use of some stable third party cross site scripting protection library
is also advisable. One such library is AntiXSS
(http://wpl.codeplex.com/[^]). Use of such libraries will provide the prevention
in conditions where the framework and framework functions are falling short.
Point of interest
In this article we saw what is Cross Site Scripting from an absolute beginner's perspective. We have seen
some samples prone to cross site scripting and we saw how ASP.NET RequestValidation
help prevent us from XSS
attacks and finally we saw what all needs to be done from a developer end to ensure XSS attacks will not result in
undesirable behavior. This article was written from the perspective of a beginner who knows nothing or very little
about cross site scripting and thus we didn't discuss about libraries like AntiXss
. I hope this has been
informative.
History
-
06 April 2013: First version.