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
- Add a using statement to reference the System.Text.RegularExpressions namespace.
- Ensure that the regular expression is contained in the ^ and $ anchor characters (beginning of string, end of string).
- 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
- Disable ASP.NET request validation by the adding the ValidateRequest="false" attribute to the @ Page directive.
- Encode the string input with the HtmlEncode method.
- 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("&lt;b&gt;", "<b>");
sb.Replace("&lt;/b&gt;", "</b>");
sb.Replace("&lt;i&gt;", "<i>");
sb.Replace("&lt;/i&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
< and
" is replaced with
". 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.0How To: Use Code Access Security with ASP.NET 2.0
Return to
HomePage