Tuesday, December 23, 2008

Cross-Site Scripting in ASP.NET








Overview

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 &lt; and " is replaced with &quot;. 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

  1. 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>

  2. 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.
  3. 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:&nbsp;<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="javascript:alert('hello');">
      

      <img src="java&#010;script:alert('hello');">
      <img src="java&#X0A;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("&lt;b&gt;", "<b>");

      sb.Replace("&lt;/b&gt;", "");
      sb.Replace("&lt;i&gt;", "<i>");
      sb.Replace("&lt;/i&gt;", "");
      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>


23 comments:

  1. <img src="java
    script:alert('hello');">

    ReplyDelete
  2. Good article


    Pawan Kumar
    http://dev.codeplatter.com

    ReplyDelete
  3. alert('very good article, Thanks');

    ReplyDelete
  4. Hi.
    Nicely done.
    [off topic]
    There is a problem in viewing (some of) sample HTML codes in the article. Its slightly trimmed to the end.
    You can use Live Writer for writing such programming codes. Live Writer has a plug-in for highlighting program-codes.
    Once again.
    Nice one.

    ReplyDelete
  5. alert('Just testing');

    ReplyDelete
  6. alert('Just testing');

    ReplyDelete
  7. You could have mentioned the HttpOnly cookie attribute that has been introduced by Microsoft to mitigate session hijacking.

    ReplyDelete
  8. luckily I was able to spread window across two monitors.

    ReplyDelete
  9. You should use the Microsoft Anti Cross-site scripting library rather than the HttpUtility.HtmlEncode. It uses a white-list appraoch which is better practice

    ReplyDelete
  10. Thanks for the very informative article.

    ReplyDelete
  11. alert('Just testing');

    ReplyDelete
  12. There's a library for Anti-Cross Site Scripting from Microsoft. Further reading at: http://msdn.microsoft.com/en-us/library/aa973813.aspx

    ReplyDelete
  13. Thanx for the valuable information. I was looking for something like this from a long time. keep posting.

    ReplyDelete
  14. Wouldn't it have been easier to post a link to the MSDN page instead if copying it and posting it as your own?

    http://msdn.microsoft.com/en-us/library/ff649310.aspx

    ReplyDelete