howtoprotectfrominjectionattacksinaspnet

Cancel Edit [WikiEntry.PreviewButtonText] Save
Return to HomePage



Note: This document is live on MSDN! See http://msdn.microsoft.com/library/en-us/dnpag2/html/PAGHT000003.asp


How To: Protect from Injection Attacks in ASP.NET



J.D. Meier, Alex Mackman, Blaine Wastell, Prashant Bansode, Andy Wigley
Microsoft Corporation
May 2005

Applies To:

* ASP.NET 1.1
* ASP.NET 2.0

Summary

This How To explains how you can validate input to protect your application from injection attacks. Performing input validation is essential because almost all application-level attacks contain malicious input.
You should validate all input, including form fields, query string parameters, and cookies to protect your application against malicious command injection. Assume all input to your Web application is malicious, and make sure that you use server validation for all sources of input. Use client-side validation to reduce round trips to the server and to improve the user experience, but do not rely on it because it is easily bypassed.
To validate input, define acceptable input for each application input field. A proven practice is to constrain input for length, range, format, and type. Use an "allow" approach to define valid input, instead of a "deny" approach. A "deny" approach is impractical because it is very difficult to anticipate all possible variations of bad input.
When you need to accept a range of HTML characters, make sure that you HTML-encode the data to make it safe prior to displaying it as output.

Contents

* Overview
* Summary of Steps
* Step 1: Use ASP.NET Request Validation
* Step 2: Constrain Input
* Step 3: Encode Unsafe Output
* Step 4: Use Command Parameters for SQL Queries
* Step 5: Verify that ASP.NET Errors Are Not Returned to the Client
* Summary
* Additional Resources

Overview

You need to validate all untrusted input to your application. You should assume that any input from users is malicious. User input to your Web application includes form fields, query strings, client-side cookies, and browser environment values such as user agent strings and IP addresses.

Weak input validation is a common vulnerability that could allow your application to be exploited by a number of injection attacks. The following are common types of attacks that exploit weak or missing input validation:

* SQL Injection. If you generate dynamic SQL queries based on user input, a SQL injection attack can inject malicious SQL commands that can be executed by the database.
* Cross-Site Scripting. Cross-site scripting (XSS) attacks exploit vulnerabilities in Web page validation by injecting client-side script code. This code is subsequently sent back to an unsuspecting user and executed by their browser. Because the browser downloads the script code from a trusted site, the browser has no way of identifying that the code is not legitimate.
* Arbitrary file access. If your code accepts file input or path input from the caller, your code could be coerced into accessing arbitrary files and is vulnerable to canonicalization bugs.

Note: Injection attacks work over HTTP and HTTPS (SSL) connections. Encryption provides no defense.

The general approach for input validation is summarized here. You should apply this approach to any input that comes from the network, such as text boxes and other forms field input, query string parameters, cookies, server variables, and Web method parameters. Note that the strategy is to first allow only good input and then deny bad input. This is because you can easily define good input for your application, but you cannot realistically anticipate the format for all malicious input.

Check for valid input as follows:
* Constrain: Check for known good data by validating the type, length, format, and range. To constrain input from server controls, use the ASP.NET validator controls. To constrain input from other sources, use regular expressions and custom validation.
* Reject: Then check for any known bad data and reject bad input.
* Sanitize: Sometimes you also need to sanitize input and make potentially malicious input safe. For example, if your application supports free-format input fields, such as comment fields, you might want to permit certain "safe" HTML elements, such as <b> and <i>, and strip out any other HTML elements.

Summary of Steps

To protect your ASP.NET application from injection attacks, perform the following steps:
* Step 1: Use ASP.NET Request Validation
* Step 2: Constrain Input
* Step 3: Encode unsafe output
* Step 4 Use Command Parameters for SQL Queries
* Step 5: Verify that ASP.NET errors are not returned to the client

Step 1: Use ASP.NET Request Validation

By default, ASP.NET 1.1 and 2.0 request validation detects any HTML elements and reserved characters in data posted to the server. This helps prevent users from embedding script into your application. Request validation checks all input data against a hard-coded list of potentially dangerous values. If a match occurs, an exception of type HttpRequestValidationException is thrown.

You can disable request validation in your Web.config application configuration file by adding a <pages> element with validateRequest="false" or on an individual page by setting ValidateRequest="false" on the @ Pages element.

If you do need to disable request validation, for example because you have a page with a free format text field that accepts HTML formatted input, then you should disable it only on specific pages where necessary.

Check that ASP.NET Request Validation is Enabled in Machine.config

Request validation is enabled by the platform by default. You can see the following default setting in Machine.config.comments.

		 <pages validateRequest="true" ... />
	

Ensure that you have not disabled request validation by overriding the default settings in your server's Machine.config or your application's Web.config.

Test ASP.NET Request Validation

You can test the effects of request validation. To do so, create an ASP.NET page that disables request validation by setting ValidateRequest="false", as follows:

		 <%@ 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>
	

When you run the page, "Hello" is displayed in a message box because the script in txtString is passed through and rendered as client-side script in your browser.

If you set ValidateRequest="true" or remove the ValidateRequest page attribute, then ASP.NET request validation rejects the script input and produces an error similar to the following.

		 A potentially dangerous Request.Form value was detected from the client (txtString="<script>alert('hello...").
	

Note: Do not rely on ASP.NET request validation. Treat it as an extra precautionary measure in addition to your own input validation.

Step 2: Constrain Input

To constrain input, follow these guidelines:
* Use server-side input validation. Do not rely on client-side validation because it is easily bypassed. Use client-side validation in addition to server-side validation to reduce round trips to the server and to improve the user experience.
* Validate length, range, format and type. Make sure that any input meets your guidelines for known good input.
* Use strong data typing. Assign numeric values to numeric data types such as Integer or Double. Assign string values to string data types. Assign dates to the DateTime data type.

For Web form applications that obtain input through server controls, use the ASP.NET validator controls to constrain the input. For other sources of input data, such as query strings, cookies, and HTTP headers, constrain input by using the Regex class from the System.Text.RegularExpressions namespace.

Explicitly Check Input from Form Fields

To constrain form field input received through server controls, you can use the following ASP.NET validator controls.

* RegularExpressionValidator. Use this control to constrain text input.
* RangeValidator. Use this control to range check numeric, currency, date and string input.
* CustomValidator. Use this control for custom validation such as ensuring that a date is in the future or in the past.

To validate form field input received through HTML input controls, perform validation in server-side code and use the Regex class to help constrain text input. The following sections describe how to constrain a variety of common input types.

Validating Text Fields
To validate text fields, such as names, addresses, and tax identification numbers, use regular expressions to do the following:
* Constrain the acceptable range of input characters.
* Apply formatting rules. For example, pattern-based fields, such as tax identification numbers, ZIP Codes, or postal codes, require specific patterns of input characters.
* Check lengths.

Using a ""RegularExpressionValidator""
To use a RegularExpressionValidator, set the ControlToValidate, ValidationExpression, and ErrorMessage properties to appropriate values as shown in the following example.

		 <form id="WebForm" method="post" runat="server">
		   [<asp:TextBox] id="txtName" runat="server"></asp:TextBox>
		   [<asp:RegularExpressionValidator] id="nameRegex" runat="server" 
		         ControlToValidate="txtName" 
		         ValidationExpression="^[a-zA-Z'.\s]{1,40}$" 
		         ErrorMessage="Invalid name">
		   </asp:regularexpressionvalidator>
		 </form>
	

The regular expression used in the preceding code example limits an input name field to alphabetic characters (lowercase and uppercase), space characters, the single apostrophe for names such as O'Dell, and the period. In addition, the field length is constrained to 40 characters.

Note: The RegularExpressionValidator control automatically adds a caret ""(^)"" and dollar sign ($) as delimiters to the beginning and end of expressions if you have not added them yourself. You should add them to all of your regular expressions as good practice. Enclosing the expression in the delimiters ensures that the expression consists of the desired content and nothing else.

Using the Regex Class
If you are not using server controls (which means you cannot use the validator controls), or you need to validate input from sources other than form fields (such as from query string parameters or cookies) you can use a Regex class.
To use the Regex class
  1. Add a using statement to reference the System.Text.RegularExpressions namespace.
  2. Ensure that the regular expression is contained in the ^ and $ anchor characters (beginning of string, end of string).
  3. Call the IsMatch method of the Regex class, as shown in the following code example.

		 // Instance method:
		 Regex reg = new Regex(@"^[a-zA-Z'.\s]{1,40}$");
		 [Response.Write(reg.IsMatch(txtName.Text));]
	

		 // Static method:
		 if (!Regex.IsMatch(txtName.Text,@"^[a-zA-Z'.\s]{1,40}$")) 
		 {
		   // Name does not match expression
		 }
	

If you cannot cache your regular expression for frequent use, you should use the static IsMatch method where possible for performance reasons, to avoid unnecessary object creation.

Validating Numeric Fields
In most cases, numeric fields should be checked for type and range. To validate the type and range of a numeric input field that uses a server control, you can use a RangeValidator control. The RangeValidator supports currency, date, integer, double, and string data types.
To use a RangeValidator, set the ControlToValidate, Type, MinimumValue, MaximumValue, and ErrorMessage properties to appropriate values as shown in the following example.

		 [<asp:RangeValidator] 
		        ID="RangeValidator1" 
		        Runat="server" 
		        ErrorMessage="Invalid range. Number must be between 0 and 255."
		        ControlToValidate="rangeInput" 
		        MaximumValue="255" 
		        MinimumValue="0" Type="Integer" />
	

If you are not using a server control, you can validate a numeric range by converting the input value to an integer and then performing a range check. For example, to validate that an integer is valid, convert the input value to a variable of type System.Int32 by using the new Int32.TryParse method (introduced in the .NET Framework version 2.0). This method returns false if the type conversion fails.

		 Int32 i;
		 if [(Int32.TryParse(txtInput.Text,] out i) == false)
		 {
		   // Conversion failed
		 }
	

If you are using an earlier version of the .NET Framework, you can use Int32.Parse inside a try/catch block and handle any exceptions of type FormatException that are thrown if the input value is not the correct type.
The following code shows how to perform a type and range check for an integer entered through an HTML text input control.

		 <%@ Page Language="C#" %>
	

		 <script runat="server">
	

		   void Page_Load(object sender, [EventArgs] e)
		   {
		     if [(Request.RequestType] == "POST")
		      {
		       int i;
		       if (Int32.TryParse(Request.Form["integerTxt"], out i) == true)
		       {
		         // [TryParse] returns true if the conversion succeeds
		         if ((0 <= i && i <= 255) == true)
		         {
		           Response.Write("Input data is valid.");
		         }
		         else
		           Response.Write("Input data is out of range");
		       }
		       else
		         Response.Write("Input data is not an integer");
		     }
		   }
	

		 </script>
	

		 <html>
		   <body>
		     <form id="form1" action="NumericInput.aspx" method="post">
		       <div>
		         Enter an integer between 0 and 255:
		         <input name="integerTxt" type="text" />
		         <input name="Submit" type="submit" value="submit" />
		       </div>
		     </form>
		   </body>
		 </html>
	

Validating Date Fields
You need to validate that date fields are of the correct type. In most cases, you also need to check them for range, for example to validate that they are in the future or past. If you use a server control to capture an input date, and if you also need to validate that a date falls within a specific range, you can use a RangeValidator control with its Type field set to Date. This control lets you specify a range by using constant date values. If you need to validate a date range based on today's date, for example to validate that a date is in the future or the past, you can use a CustomValidator control.
To use a CustomValidator control to validate a date, set the ControlToValidate and ErrorMessage properties and set the OnServerValidate event to point to a custom method containing your validation logic. The following sample .aspx page code shows this approach.

		 <%@ Page Language="C#" %>
	

		 <script runat="server">
	

		  void [ValidateDateInFuture(object] source, [ServerValidateEventArgs] args)
		  {
		    [DateTime] dt;
	

		    // Check for valid date and that the date is in the future
		    if [((DateTime.TryParse(args.Value,] out dt) == false) || 
		        (dt <= [DateTime.Today))]
		    {
		      [args.IsValid] = false;
		    }
		  }
	

		 </script>
	

		 <html>
		   <body>
		     <form id="form1" runat="server">
		       <div>
		         <asp:Label ID="Label1" Runat="server" 
		                    Text="Future Date:"></asp:Label>
		         [<asp:TextBox] ID="futureDatetxt" Runat="server"></asp:TextBox>
		         [<asp:CustomValidator] 
		               ID="CustomValidator1" Runat="server" 
		               ErrorMessage="Invalid date. Enter a date in the future."
		               ControlToValidate="futureDatetxt"  
		               OnServerValidate="ValidateDateInFuture">
		         [</asp:CustomValidator>]
		         <br />
		         <asp:Button ID="submitBtn" Runat="server" Text="Submit"  />
		       </div>
		     </form>
		   </body>
		 </html>
	

Note: The preceding code uses DateTime.TryParse, which is new to .NET Framework version 2.0.

Sanitizing Free-Text Fields
To sanitize input, you make untrusted input safe by preventing it from being treated as code. For example, if your application handles user input that it cannot constrain or reads data from a shared database, you might need to sanitize the data or make the output safe when you write it on your page. Sanitize data prior to output by using HttpUtility.HtmlEncode.

Allowing Restricted HTML Input

If your application needs to accept a range of HTML elements — for example through a rich text input field such as a comments field — turn off ASP.NET request validation and create a filter that allows only the HTML elements that you want your application to accept. A common practice is to restrict formatting to safe HTML elements such as <b> (bold) and <i> (italic). Before writing the data, HTML-encode it. This makes any malicious script safe by causing it to be handled as text, not as executable code.
To allow restricted HTML input
  1. Disable ASP.NET request validation by the adding the ValidateRequest="false" attribute to the @ Page directive.
  2. Encode the string input with the HtmlEncode method.
  3. Use a StringBuilder and call its Replace method to selectively remove the encoding on the HTML elements that you want to permit.

The following .aspx page code shows this approach. The page disables ASP.NET request validation by setting ValidateRequest="false". It HTML-encodes the input and selectively allows the <b> and <i> HTML elements to support simple text formatting.

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

Validate Query String Values
Validate query string values for length, range, format, and type. You usually do this by using a combination of regular expressions to:
* Constrain the input values.
* Set explicit range checks.
* Specify the explicit type checks performed by converting the input value to its equivalent .NET Framework type and handling any ensuing conversion errors.

The following code example shows how to use the RegEx class to validate a name string passed on a query string.

		 void Page_Load(object sender, [EventArgs] e)
		 {
		   if (!System.Text.RegularExpressions.Regex.IsMatch(
		        Request.QueryString["Name"], @"^[a-zA-Z'.\s]{1,40}$"))
		     Response.Write("Invalid name parameter");
		   else
		     Response.Write("Name is " + Request.QueryString["Name"]);
		 }
	

Validate Cookie Values
Values maintained in cookies, such as query string parameters, can easily be manipulated by a client. Validate cookie values in the same way as you would for query string parameters. Validate them for length, range, format, and type.

Validate File and URL Paths

If your application has to accept input file names, file paths, or URL paths, you need to validate that the path is in the correct format and that it points to a valid location within the context of your application. Failure to do this can result in attackers persuading your application into accessing arbitrary files and resources.

Validating File Paths
To avoid possible canonicalization bugs and the potential for your application to be coerced to access arbitrary files, avoid writing code that accepts user supplied file or path input.

* If you must accept file names as input, canonicalize the file name by using System.IO.Path.GetFullName.
* If you must accept file paths as input, canonicalize the file path by using System.IO.Path.GetFullPath.

Using ""MapPath"" to Prevent Cross Application Mapping
If you use MapPath to map a supplied virtual path to a physical path on the server, use the overload of Request.MapPath that accepts a bool parameter so that you can prevent cross-application mapping. The following code example shows this technique.

		 try
		 {
		   string mappedPath = [Request.MapPath(] inputPath.Text, 
		                                        [Request.ApplicationPath,] false);
		 }
		 catch [(HttpException)]
		 {
		   // Cross-application mapping attempted
		 }
	

The final false parameter prevents cross-application mapping. This means that a user cannot successfully supply a path that contains ".." to traverse outside of your application's virtual directory hierarchy. Any attempt to do this results in an exception of type HttpException.
If you use server controls, you can use the Control.MapPathSecure method to retrieve the physical path to which the virtual path is mapped. Control.MapPathSecure uses code access security and throws an HttpException if the server control does not have permissions to read the resulting mapped file. For more information, see Control.MapPathSecure in the .NET Framework SDK documentation.

Using Code Access Security to Restrict File IO
An administrator can restrict an application's file I/O to its own virtual directory hierarchy by configuring the application to run with Medium trust. In this event .NET code access security ensures that no file access is permitted outside of the application's virtual directory hierarchy.
You configure an application to run with Medium trust, by setting the <trust> element in Web.config or Machine.config.

		 <trust level="Medium" />
	

More Information
Running applications successfully in Medium trust requires appropriate design and development techniques. For more information about using CAS with ASP.NET, see How To: Use Code Access Security In ASP.NET 2.0

Validating ""URLs""
You can filter for a valid URL format using a regular expression, such as the following.

		 ^(?:http|https|ftp)://[a-zA-Z0-9\.\-]+(?:\:\d{1,5})?(?:[A-Za-z0-9\.\;\:\@\&\=\+\$\,\?/]|%u[0-9A-Fa-f]{4}|%[0-9A-Fa-f]{2})*$
	

This constrains the input, but it does not validate whether the URL is valid in terms of the application boundaries. You should check whether the target is valid in the context of your application. For example, does it point to an authorized server that you expect your application to communicate with?

Step 3: Encode Unsafe Output

If you write text output to a Web page and you do not know with absolute certainty that the text does not contain HTML special characters (such as <, >, and ""&)"", encode it using HttpUtility.HtmlEncode. Do this if the text came from user input, a database, or a local file.
Similarly, if you write ""URLs"" that might contain unsafe characters because they have been constructed from input data or data from a shared database, use HttpUtilty.UrlEncode to make them safe.
Avoid the mistake of encoding the data early. Make sure you encode at the last possible opportunity before the data is displayed to the client.

Use ""HtmlEncode"" to Encode Unsafe Output

The HtmlEncode method 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 text, and the tags are not interpreted as HTML.
To illustrate the use of HtmlEncode, the following page accepts input from the user and allows potentially unsafe HTML characters by setting ValidateRequest="false". Before writing the input back to the user, the code calls HttpUtility.HtmlEncode on the supplied input text. This renders any potentially unsafe HTML as harmless text.

		 <%@ Page Language="C#" ValidateRequest="false" %>
	

		 <script runat="server">
		   void submitBtn_Click(object sender, [EventArgs] e)
		   {
		       [Response.Write(HttpUtility.HtmlEncode(inputTxt.Text));]
		   }
		 </script>
	

		 <html xmlns="http://www.w3.org/1999/xhtml" >
		   <body>
		     <form id="form1" runat="server">
		       <div>
		         [<asp:TextBox] ID="inputTxt" Runat="server" 
		              TextMode="MultiLine" Width="382px" Height="152px">
		         [</asp:TextBox>]
		         <asp:Button ID="submitBtn" Runat="server" Text="Submit" 
		                     OnClick="submitBtn_Click" />
		       </div>
		     </form>
		   </body>
		 </html>
	

To see the effect of the HTML encoding, place the preceding page in a virtual directory, browse to it, enter some HTML code in the input text box, and click Submit. For example, the following input is rendered as text.

		 Run script and say hello <script>alert('hello');</script>
	

It produces the following safe output.

		 Run script and say hello <script>alert('hello');</script>
	

If you remove the call to HtmlEncode and simply write back the input, the browser executes the script and displays a message box. Malicious script could pose a significant threat.

""Use UrlEncode to Encode Unsafe URLs""

If you need to write out ""URLs"" that are based on input that you do not fully trust, then use HttpUtility.UrlEncode to encode the URL string.

		 [HttpUtility.UrlEncode(] urlString );
	

Step 4: Use Command Parameters for SQL Queries

To help prevent SQL injection, use command parameters for SQL queries. The Parameters collection provides type checking and length validation. If you use the Parameters collection, input is treated as a literal value and SQL does not treat it as executable code. An additional benefit of using the Parameters collection is that you can enforce type and length checks. Values outside of the range trigger an exception.

Use the Parameters Collection When You Call a Stored Procedure

The following code fragment illustrates the use of the Parameters collection when calling a stored procedure:

		 [SqlDataAdapter] myCommand = new SqlDataAdapter("AuthorLogin", 
		                                      myConnection);
		 [myCommand.SelectCommand.CommandType] = [CommandType.StoredProcedure;]
		 [SqlParameter] parm = [myCommand.SelectCommand.Parameters.Add(]
		                                     "@LoginId", [SqlDbType.VarChar,] 11);
		 parm.Value = Login.Text;
	

Use the Parameters Collection When Building Your SQL Statements

If you cannot use stored procedures, you can still use parameters, as shown in the following code fragment.

		 [SqlDataAdapter] myCommand = new [SqlDataAdapter(]
		   "SELECT au_lname, au_fname FROM Authors WHERE au_id = @au_id", myConnection);
		 [SQLParameter] parm = [myCommand.SelectCommand.Parameters.Add(]
		                            "@au_id" [,SqlDbType.VarChar,] 11);
		 Parm.Value = Login.Text;
	

More Information
For more information about how to prevent SQL injection, see How To: Protect From SQL Injection in ASP.NET

Step 5: Verify that ASP.NET Errors Are Not Returned to the Client

You can use the <customErrors> element to configure custom, generic error messages that should be returned to the client in the event of an application exception condition.
Make sure that the mode attribute is set to "remoteOnly" as shown in the following example.

		 <customErrors mode="remoteOnly" />
	

After installing an ASP.NET application, you can configure the setting to point to your custom error page as shown in the following example.

		 <customErrors mode="On" defaultRedirect="YourErrorPage.htm" />
	

Summary

You should validate all input including form fields, query string parameters, and cookies to protect your application against malicious command injection. Assume all input to your Web application is malicious and make sure that you use server validation for all sources of input. Use client-side validation to reduce round trips to the server and to improve the user experience but do not rely on it because it is easily bypassed.

Constrain input for length, range, format and type. Use an "allow" approach up front and define what constitutes valid input, rather than using a "deny" approach. When you need to accept a range of HTML characters make sure you HTML encode the data to make it safe prior to outputting it.

Additional Resources

How To: Use Regular Expressions to Constrain Input in ASP.NET 2.0.
How To: Protect From SQL Injection in ASP.NET 2.0.
How To: Prevent Cross Site Scripting in ASP.NET 2.0
How To: Use Code Access Security with ASP.NET 2.0



Return to HomePage
Microsoft Communities