Input Validation


If you make unfounded assumptions about the type, length, format, or range of input, your application is unlikely to be robust. Input validation can become a security issue if an attacker discovers that you have made unfounded assumptions. The attacker can then supply carefully crafted input that compromises your application. The misplaced trust of user input is one of the most common and devastating vulnerabilities in Web applications.

Constrain, Then Sanitize

Start by constraining input and check for known good data by validating for type, length, format, and range. 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. The following table summarizes the options that are available for constraining and sanitizing data:

Table 10.1: Options for Constraining and Sanitizing Data

Requirement

Options

Type checks

.NET Framework type system. Parse string data, convert to a strong type, and then handle FormatExceptions.

Regular expressions. Use ASP.NET RegularExpressionValidator control or Regex class.

Length checks

Regular expressions

String.Length property

Format checks

Regular expressions for pattern matching

.NET Framework type system

Range checks

ASP.NET RangeValidator control (supports currency, date, integer, double, and string data)

Typed data comparisons

Regular Expressions

You can use regular expressions to restrict the range of valid characters, to strip unwanted characters , and to perform length and format checks. You can constrain input format by defining patterns that the input must match. ASP.NET provides the RegularExpressionValidator control and the Regex class is available from the System.Text.RegularExpressions namespace.

If you use the validator controls, validation succeeds if the control is empty. For mandatory fields, use a RequiredFieldValidator . Also, the regular expression validation implementation is slightly different on the client and server. On the client, the regular expression syntax of Microsoft JScript development software is used. On the server, System.Text.RegularExpressions.Regex syntax is used. Since JScript regular expression syntax is a subset of System.Text.RegularExpressions.Regex syntax, it is recommended that JScript regular expression syntax be used to yield the same results on both the client and the server.

For more information about the full range of ASP.NET validator controls, refer to the .NET Framework documentation.

RegularExpressionValidator Control

To validate Web form field input, you can use the RegularExpressionValidator control. Drag the control onto a Web form and set its ValidationExpression , ControlToValidate , and ErrorMessage properties.

You can set the validation expression using the properties window in Microsoft Visual Studio .NET or you can set the property dynamically in the Page_Load event handler. The latter approach allows you to group together all of the regular expressions for all controls on the page.

Regex Class

If you use regular HTML controls with no runat ="server" property (which rules out using the RegularExpressionValidator control), or you need to validate input from other sources such as query strings or cookies, you can use the Regex class either in your page class or in a validation helper method, possibly in a separate assembly. Some examples are shown later in this section.

Regular Expression Comments

Regular expressions are much easier to understand if you use the following syntax and comment each component of the expression using # . To enable comments, you must also specify RegexOptions.IgnorePatternWhitespace , which means that non-escaped white space is ignored.

 Regex regex = new Regex(@"                         ^           # anchor at the start                        (?=.*\d)     # must contain at least one digit                        (?=.*[a-z])  # must contain one lowercase                        (?=.*[A-Z])  # must contain one uppercase                        .{8,10}      # From 8 to 10 characters in length                        $            # anchor at the end",                         RegexOptions.IgnorePatternWhitespace); 

String Fields

To validate string fields, such as names , addresses, tax identification numbers , and so on, 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.

Names

The following example shows a RegularExpressionValidator control that has been used to validate a name field.

 <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 preceding validation expression constrains the input name field to alphabetic characters (lowercase and uppercase), the single apostrophe for names such as O'Dell, and the dot character. In addition, the field length is constrained to 40 characters.

Social Security Numbers

The following example shows the HTML code that is generated for a RegularExpressionValidator control that has been used to validate a U.S. social security number form field:

 <form id="WebForm" method="post" runat="server">   <asp:TextBox id="txtSSN" runat="server"></asp:TextBox>   <asp:RegularExpressionValidator id="ssnRegex" runat="server"         ErrorMessage="Invalid social security number"         ValidationExpression="\d{3}-\d{2}-\d{4}"         ControlToValidate="txtSSN">   </asp:RegularExpressionValidator> </form> 

The preceding validation expression is one of the standard expressions that Visual Studio .NET provides. It validates the format of the supplied input field as well as its type and length. The input must consist of three numeric digits followed by a dash, then two digits followed by a dash, and then four digits.

If you are not using server controls (which rule out the validator controls), or you need to validate input from sources other than form fields, you can use the System.Text.RegularExpression.Regex class in your method code. The following example shows how to validate the same field by using the static Regex.IsMatch method directly in the page class rather than using a validator control:

 if (!Regex.IsMatch(txtSSN.Text, @"^\d{3}-\d{2}-\d{4}$")) {   // Invalid Social Security Number } 

Date Fields

Input fields that have an equivalent .NET Framework type can be type checked by the.NET Framework type system. For example, to validate a date, you can convert the input value to a variable of type System.DateTime and handle any resulting format exceptions if the input data is not compatible, as follows .

 try {   DateTime dt = DateTime.Parse(txtDate.Text).Date; } // If the type conversion fails, a FormatException is thrown catch(FormatException ex) {   // Return invalid date message to caller } 

In addition to format and type checks, you might need to perform a range check on a date field. This is easily performed using the DateTime variable, as follows.

 // Exception handling is omitted for brevity   DateTime dt = DateTime.Parse(txtDate.Text).Date;   // The date must be today or earlier   if (dt > DateTime.Now.Date)     throw new ArgumentException("Date must be in the past"); 

Numeric Fields

If you need to validate numeric data, for example, an age, perform type checks using the int type. To convert string input to integer form you can use Int32.Parse or Convert.ToIn32 , and then handle any FormatException that occurs with an invalid data type, as follows:

 try {   int i = Int32.Parse(txtAge.Text);   . . . } catch(FormatException) {  . . . } 

Range Checks

Sometimes you need to validate that input data falls within a predetermined range. The following code uses an ASP.NET RangeValidator control to constrain input to whole numbers between 0 and 255. This example also uses the RequiredFieldValidator . Without the RequiredFieldValidator , the other validator controls accept blank input.

 <form id="WebForm3" method="post" runat="server">   <asp:TextBox id="txtNumber" runat="server"></asp:TextBox>   <asp:RequiredFieldValidator         id="rangeRegex"         runat="server"         ErrorMessage="Please enter a number between 0 and 255"         ControlToValidate="txtNumber"        style="LEFT: 10px; POSITION: absolute; TOP: 47px" >   </asp:RequiredFieldValidator>   <asp:RangeValidator         id="RangeValidator1"         runat="server"         ErrorMessage="Please enter a number between 0 and 255"         ControlToValidate="TextBox1"         Type="Integer"         MinimumValue="0"        MaximumValue="255"         style="LEFT: 10px; POSITION: absolute; TOP: 47px" >   </asp:RangeValidator>   <asp:Button id="Button1" style="LEFT: 10px; POSITION: absolute; TOP: 100px"                runat="server" Text="Button"></asp:Button> </form> 

The following example shows how to validate range using the Regex class:

 try {   // The conversion will raise an exception if not valid.   int i = Convert.ToInt32(sInput);   if ((0 <= i && i <= 255) == true)   {     // data is valid, use the number   } } catch(FormatException) {   . . . } 

Sanitizing Input

Sanitizing is about making potentially malicious data safe. It can be helpful when the range of allowable input cannot guarantee that the input is safe. This might include stripping a null from the end of a user-supplied string or escaping values so they are treated as literals. If you need to sanitize input and convert or strip specific input characters, use Regex.Replace .

Note  

Use this approach for defense in depth. Always start by constraining input to the set of known "good" values.

The following code strips out a range of potentially unsafe characters, including < > \ " ' % ; () &.

 private string SanitizeInput(string input) {   Regex badCharReplace = new Regex(@"^([<>""'%;()&])$");   string goodChars = badCharReplace.Replace(input, "");   return goodChars; } 

For more information about sanitizing free format input fields, such as comment fields, see "Sanitizing Free Format Input" under "Cross-Site Scripting," later in this chapter.

Validating HTML Controls

If you do not use server controls ” that is, controls with the runat="server" attribute ” and instead use regular HTML controls, you cannot use the ASP.NET validator controls. Instead, you can validate your Web pages' content by using regular expressions in the Page_Load event handler, as follows.

 using System.Text.RegularExpressions; . . . private void Page_Load(object sender, System.EventArgs e) {   // Note that IsPostBack applies only for    // server forms (with runat="server")   if (Request.RequestType == "POST") // non-server forms   {     // Validate the supplied email address     if(!Regex.Match(Request.Form["email"],           @"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$",          RegexOptions.None).Success)      {       // Invalid email address     }     // Validate the supplied name     if (!RegEx.Match(Request.Form["name"],          @"^[A-Za-z'\- ]$",          RegexOptions.None).Success)      {       // Invalid name     }   } } 

Validating Input Used for Data Access

If you are generating dynamic SQL queries based on user input, a SQL injection attack can inject malicious SQL commands that can be executed by the database. In a typical Web-based data access scenario, the following defense in depth strategy can be used:

  • Use regular expressions to constrain input within your page class.

  • Sanitize or reject input. For defense in depth, you can choose to use a helper method to strip null characters or other known bad characters.

  • Use parameterized stored procedures for data access to ensure that type and length checks are performed on the data used in SQL queries.

For more information about using parameters for data access and about writing secure data access code, see Chapter 14, "Building Secure Data Access."

Validating Input Used For File I/O

In general, you should avoid writing code that accepts file input or path input from the caller. Instead, use fixed file names and locations when reading and writing data. This ensures that your code cannot be coerced into accessing arbitrary files. It also ensures that your code is not vulnerable to canonicalization bugs .

If you do need to accept input file names, there are two main challenges. First, is the resulting file path and name a valid file system name? Second, is the path valid in the context of your application? For example, is it beneath the application's virtual directory root?

To canonicalize the file name, use System.IO.Path.GetFullPath . To check that the file path is valid in the context of your application, you can use .NET code access security to grant the precise FileIOPermission to your code so that is able to access only files from specific directories. For more information, see the "File I/O" sections in Chapter 7, "Building Secure Assemblies" and Chapter 8, "Code Access Security in Practice."

Using MapPath

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, as follows:

 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 so results in an exception of type HttpException .

Note  

Server controls can use the Control.MapPathSecure method to read files. This method requires that the calling code is granted full trust by code access security policy; otherwise an HttpException is thrown. For more information, see Control.MapPathSecure in the .NET Framework SDK documentation.

Common Regular Expressions

Visual Studio .NET provides a set of useful regular expressions. To access them, add a RegularExpresssionValidator control to a Web form and click the ellipsis button in the control's Expression property field. The following table shows several additional useful expressions for commonly used Web page fields.

Table 10.2: Useful Regular Expression Fields

Field

Expression

Format Samples

Description

Name

^[a-zA-Z'`- \s]{1,40}$

John Doe

O'Dell

Validates a name. Allows up to 40 uppercase and lowercase characters and a few special characters that are common to some names. This list can be tailored.

Numbers

^\D?(\d{3})\D?\D?(\d{3})\D?(\d{4})$

(425)-555-0123

425-555-0123

425 555 0123

Validates a U.S. phone number.

E-mail

^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$

someone@example.com

Validates an e-mail address.

URL

^(http https ftp)\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(:[a-zA-Z0-9]*)?/?([a-zA-Z0-9\-\._\?\,\'/\\\+&%\$#\=~])*$

 

Validates a URL.

Zip Code

^(\d{5}-\d{4}\d{5}\d{9})$^([a-zA-Z]\d[a-zA-Z] \d[a-zA-Z]\d)$

 

Validates a U.S. ZIP code allowing 5 or 9 digits.

Password

^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$

 

Validates a strong password. Must be between 8 and 10 characters. Must contain a combination of uppercase, lowercase, and numeric digits, with no special characters.

Non- negative integers

\d+

986

Validates for integers greater than zero.

Currency (non- negative)

"\d+(\.\d\d)?"

 

Validates for a positive currency amount. Requires two digits after the decimal point.

Currency (positive or negative)

"(-)?\d+(\.\d\d)?"

 

Validates for a positive or negative currency amount. Requires two digits after the decimal point.




Improving Web Application Security. Threats and Countermeasures
Improving Web Application Security: Threats and Countermeasures
ISBN: 0735618429
EAN: 2147483647
Year: 2003
Pages: 613

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net