Cross-Site Scripting in ASP.NET
Cross-site scripting attacks exploit vulnerabilities in Web page validation by injecting client-side script code. The script code embeds itself in response data, which is sent back to an unsuspecting user. The user's browser then runs the script code. Because the browser downloads the script code from a trusted site, the browser has no way of recognizing that the code is not legitimate, and Microsoft Internet Explorer security zones provide no defense. Cross-site scripting attacks also work over HTTP and HTTPS (SSL) connections.
One of the most serious examples of a cross-site scripting attack occurs when an attacker writes script to retrieve the authentication cookie that provides access to a trusted site and then posts the cookie to a Web address known to the attacker. This enables the attacker to spoof the legitimate user's identity and gain illicit access to the Web site.
Common vulnerabilities that make your Web application susceptible to cross-site scripting attacks include:
- Failing to constrain and validate input.
- Failing to encode output.
- Trusting data retrieved from a shared database.
Guidelines
The two most important countermeasures to prevent cross-site scripting attacks are to:
- Constrain input.
- Encode output.
Constrain Input
Start by assuming that all input is malicious. Validate input type, length, format, and range.
- To constrain input supplied through server controls, use ASP.NET validator controls such as RegularExpressionValidator and RangeValidator.
- To constrain input supplied through client-side HTML input controls or input from other sources such as query strings or cookies, use the System.Text.RegularExpressions.Regex class in your server-side code to check for expected using regular expressions.
- To validate types such as integers, doubles, dates, and currency amounts, convert the input data to the equivalent .NET Framework data type and handle any resulting conversion errors.
For more information about and examples of how to constrain input, see .
Encode Output
Use the HttpUtility.HtmlEncode method to encode output if it contains input from the user or from other sources such as databases. HtmlEncode replaces characters that have special meaning in HTML-to-HTML variables that represent those characters. For example, < is replaced with < and " is replaced with ". Encoded data does not cause the browser to execute code. Instead, the data is rendered as harmless HTML.
Similarly, use HttpUtility.UrlEncode to encode output URLs if they are constructed from input.
Summary of Steps
To prevent cross-site scripting, perform the following steps:
<system.web>
<pages buffer="true" validateRequest="true" />
</system.web>
You can disable request validation on a page-by-page basis. Check that your pages do not disable this feature unless necessary. For example, you may need to disable this feature for a page if it contains a free-format, rich-text entry field designed to accept a range of HTML characters as input. For more information about how to safely handle this type of page.
To test that ASP.NET request validation is enabled
- Create an ASP.NET page that disables request validation. To do this, set ValidateRequest="false", as shown in the following code example.
<%@ Page Language="C#" ValidateRequest="false" %>
<html>
<script runat="server">
void btnSubmit_Click(Object sender, EventArgs e)
{
// If ValidateRequest is false, then 'hello' is displayed
// If ValidateRequest is true, then ASP.NET returns an exception
Response.Write(txtString.Text);
}
</script>
<body>
<form id="form1" runat="server">
<asp:TextBox id="txtString" runat="server"
Text="<script>alert('hello');</script>" />
<asp:Button id="btnSubmit" runat="server"
OnClick="btnSubmit_Click"
Text="Submit" />
</form>
</body>
</html>
- Run the page. It displays Hello in a message box because the script in txtString is passed through and rendered as client-side script in your browser.
- Set ValidateRequest="true" or remove the ValidateRequest page attribute and browse to the page again. Verify that the following error message is displayed.
A potentially dangerous Request.Form value was detected from the client (txtString="<script>alert('hello...").
This indicates that ASP.NET request validation is active and has rejected the input because it includes potentially dangerous HTML characters.
Response.Write
<% =
Search your pages to locate where HTML and URL output is returned to the client.
Step 3. Determine Whether HTML Output Includes Input Parameters
Analyze your design and your page code to determine whether the output includes any input parameters. These parameters can come from a variety of sources. The following list includes common input sources:
- Form fields, such as the following.
Response.Write(name.Text);
Response.Write(Request.Form["name"]);
Query Strings
Response.Write(Request.QueryString["name"]);
- Query strings, such as the following:
Response.Write(Request.QueryString["username"]);
- Databases and data access methods, such as the following:
SqlDataReader reader = cmd.ExecuteReader();
Response.Write(reader.GetString(1));
Be particularly careful with data read from a database if it is shared by other applications.
- Cookie collection, such as the following:
Response.Write(
Request.Cookies["name"].Values["name"]);
- Session and application variables, such as the following:
Response.Write(Session["name"]);
Response.Write(Application["name"]);
<%@ Page Language="C#" AutoEventWireup="true"%>
<html>
<form id="form1" runat="server">
<div>
Color: <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox><br />
<asp:Button ID="Button1" runat="server" Text="Show color"
OnClick="Button1_Click" /><br />
<asp:Literal ID="Literal1" runat="server"></asp:Literal>
</div>
</form>
</html>
<script runat="server">
private void Page_Load(Object Src, EventArgs e)
{
protected void Button1_Click(object sender, EventArgs e)
{
Literal1.Text = @"<span style=""color:"
+ Server.HtmlEncode(TextBox1.Text)
+ @""">Color example</span>";
}
}
</Script>
Potentially Dangerous HTML Tags
While not an exhaustive list, the following commonly used HTML tags could allow a malicious user to inject script code:
<img src="BLOCKED SCRIPTalert('hello');">
<img src="java
script:alert('hello');">
<img src="java
script:alert('hello');">
<style TYPE="text/javascript">
alert('hello');
</style>
When you find ASP.NET code that generates HTML using some input, you need to evaluate appropriate countermeasures for your specific application. Countermeasures include:
Response.Write(HttpUtility.HtmlEncode(Request.Form["name"]));
Response.Write(HttpUtility.UrlEncode(urlString));
<%@ Page Language="C#" ValidateRequest="false"%>
<script runat="server">
void submitBtn_Click(object sender, EventArgs e)
{
// Encode the string input
StringBuilder sb = new StringBuilder(
HttpUtility.HtmlEncode(htmlInputTxt.Text));
// Selectively allow <b> and <i>
sb.Replace("<b>", "<b>");
sb.Replace("</b>", "");
sb.Replace("<i>", "<i>");
sb.Replace("</i>", "");
Response.Write(sb.ToString());
}
</script>
<html>
<body>
<form id="form1" runat="server">
<div>
<asp:TextBox ID="htmlInputTxt" Runat="server"
TextMode="MultiLine" Width="318px"
Height="168px"></asp:TextBox>
<asp:Button ID="submitBtn" Runat="server"
Text="Submit" OnClick="submitBtn_Click" />
</div>
</form>
</body>
</html>
- Form fields, such as the following.