Hacking the Code ASP.NET Web Application Security [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Hacking the Code ASP.NET Web Application Security [Electronic resources] - نسخه متنی

James C. Foster, Mark M. Burnett

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید






Constraining Input

The key to protecting your application from malicious data is to validate all user input. There are numerous actions in your code that user input may affect, and therefore many different techniques for validating this input. Examples of actions that user input might have an effect on are:



Accessing a database



Reading the file system



Allowing users to upload or save files



Running a shell command



Sending an e-mail



Sending HTML output to the client



Setting an object property



Processing a shopping cart purchase



Each of these actions is vulnerable to one or more of the threats mentioned at the beginning of this chapter. To counter these threats, I have established the following techniques, which I will describe in more detail throughout this section:



Bounds checking Checking input values for appropriate data type, string length, format, characters, and range



Pattern matching Using regular expressions to match and allow known good input or match and block known bad characters or strings



Data reflecting Passing data to the system, reading back the system’s interpretation of the data, and then comparing it to the original data



Encoding Transforming string characters to a specific format for safe handling



Encapsulating Deriving a digest from user input that contains a known set of characters, making it safe to use.



Parameterizing Taking user input as a parameter to fix its scope, for example, appending a file extension or prefixing a directory path



Double decoding Decoding data twice to ensure that both instances match



Escaping Quoting or escaping special characters so the target treats them as literal characters



Syntax checking Checking a finished string to make sure the syntax is appropriate for the target



Exception handling Checking for errors and performing sanity checks to ensure that results are returned as expected



Honey drops Small pieces of data that work as a honey pot to help detect intrusions.



The following are examples of how to use these techniques with various programming tasks.


Bounds Checking












Summary:


Check input data to make sure it is appropriate for its purpose.


Threats:


Malicious input


Bounds checking is a quick and easy way to prevent many application-level attacks. Check input values to be sure they comply with the expected data type, string length, string format, set of characters, and range of values. ASP.NET provides several easy methods to check input data:



Validator Controls



Type Conversion



SqlParameters



Validator Controls


ASP.NET provides a set of controls to validate all form data entered by a user. By attaching a validator control to a form control and setting a few properties, you can have ASP.NET automatically check user input values. Table 5.2 summarizes the validator controls available with ASP.NET.






























Table 5.2: ASP.NET Validator Controls

Control


Description


CompareValidator


Compares a control’s value to a fixed value or to the value of another control. Also performs data-type checks.


CustomValidator


Runs a user-defined validation function


RangeValidator


Checks to make sure numeric values fall between minimum and maximum values


RegularExpressionValidator


Matches a control’s value against a regular expression pattern


RequiredFieldValidator


Ensures that a control is not left empty


ValidationSummary


Summarizes all validation errors on a page


To use a validator control, set the ControlToValidate property and then set any other properties to define the validation to perform. Figure 5.9 (C#) demonstrate how to use a validator control to check a numeric input field.







<html>
<body>
<form runat="server">
Enter you age:
<br />
<asp:TextBox id="tbox1" runat="server"/>
<br /><br />
<asp:Button Text="Submit" runat="server" />
<br /><br />
<asp:RangeValidator
ControlToValidate="tbox1"
MinimumValue="13"
MaximumValue="120"
Type="Integer "
EnableClientScript="false"
Text="Invalid age."
runat="server"/>
</form>
</body>
</html>






Figure 5.9: Validating Numeric Input (C#)

The most powerful of these validators is the RegularExpressionValidator, which allows complex pattern matching to ensure that input falls within very specific parameters.

But it is important to note that although validator controls are powerful, they do have some limitations:



You can use them only to validate form controls.



You can validate form controls only when the page posts back to itself, not to another page.



They work only with server-side controls.



ASP.NET does not perform any validation with validator controls before it fires the Page_Load event.



They tend to decentralize validation code, moving it to individual pages rather than having a centralized mechanism for input filtering.



Because validator controls focus exclusively on form input, it is easy to neglect filtering other forms of user input. To deal with these limitations, you will need to develop custom functions for validating other input. Nevertheless, because of their automated error messages and the addition of client-side code, you should still always use validator controls for form input.





Warning

The client-side validation features of validation controls speed up validation for the client and prevent extra load on your server from continual post backs, but they are not reliable as a security measure. An attacker can easily disable client-side scripting, or use a custom tool to post forms that bypass client-side validation.


Security Policy




Use validator controls to validate form input if a page posts back to itself.



Never rely on client-side validation for security.




Pattern Matching












Summary:


Pattern matching is an effective technique for filtering malicious input.


Threats:


Malicious input


The most common and effective method for addressing malicious input is to apply pattern matching through regular expressions. With pattern matching you block input that contains specific malicious characters or permit only input that contains a set of known safe characters. Under most circumstances, the latter is the preferred method for checking input.







   // Pattern match for known good characters and check length
// Only allow 1-260 letters, numbers, spaces,
// periods, and/or back slashes
Regex knownGood = new Regex(@"^[a-z0-9\s\.\\]{1,260}$",
RegexOptions.IgnoreCase);
if (!knownGood.IsMatch(decodedPath1))
TextBoxResults.Text += "Step 2: Pattern match for " +
"known good failed\n";
else
TextBoxResults.Text += "Step 2: Pattern match for " +
"known good passed\n";






Figure 5.10: Allowing Known Good Characters (C#)

Because it is difficult to anticipate the numerous ways one could exploit your application, it is usually best to establish which characters you will allow and then block everything else. Figures 5.10 (C#) and 5.11 (VB.NET) show how to use regular expressions to allow only specific characters. Using this method, however, does require some forethought. Users will quickly get frustrated if you do not allow certain characters, such as an apostrophes or hyphens, in a last name field.







  'Pattern match for known good characters and check length
'Only allow 1-260 letters, numbers, spaces, periods, and/or back slashes
Dim knownGood As Regex = New Regex("^[a-z0-9\s\.\\]{1,260}$", _
RegexOptions.IgnoreCase)
If Not knownGood.IsMatch(decodedPath1) Then
TextBoxResults.Text += "Step 2: Pattern match for " & _
"known good failed" & vbCrLf
Else
TextBoxResults.Text += "Step 2: Pattern match for " & _
"know good passed" & vbCrLf
End If






Figure 5.11: Allowing Known Good Characters (VB.NET)

But pattern matching is more than blocking and allowing individual characters. Some attacks might use no invalid characters but still be malicious. For example, consider a Web application that saves data to a file, and selects the filename based on user input. To prevent directory traversal or file access attacks, you might allow users to input only alphanumeric data, which you can enforce with a regular expression. But what happens if the user selects a filename using a reserved DOS device name such as COM1, PRN, or NUL? Although these device names do not contain anything other than alphabetic characters, accessing these devices might cause a denial of service or facilitate some other kind of attack. For some types of input you should allow only known good data and then perform a follow-up check to make sure that input does not contain known bad data. Figures 5.12 (C#) and 5.13 (VB.NET) show how to use a regular expression to check for these patterns.







   // Pattern match for known bad characters and strings
Regex knownBad = new Regex(@"(?:AUX|CO(?:M\d|N\.\.)" +
@"|LPT\d|NUL|PRN|\n|\r|progra(?:\~1|m\sfiles)|system32" +
@"|winnt|[\?\*\<\>\|\"\:\%\&])", RegexOptions.IgnoreCase);
if (knownBad.IsMatch(decodedPath1))
TextBoxResults.Text += "Step 3: Pattern match for " +
"known bad failed\n";
else
TextBoxResults.Text += "Step 3: Pattern match for " +
"know bad passed\n";






Figure 5.12: Matching Known Bad Input (C#)

Table 5.3 shows some common input scenarios and examples of regular expression patterns you might use to identify malicious input. Sometimes you will allow only known good data and other times you might filter out known bad data, but usually you should perform both checks. Note that the patterns in this table do not address every possible exploit, and you should customize them for your particular application.







  'Pattern match for known bad characters and strings
Dim knownBad As Regex = New Regex("(?:AUX|CO(?:M\d|N\.\.)" & _
"|LPT\d|NUL|PRN|\n|\r|progra(?:\~1|m\sfiles)|system32" & _
"|winnt|[\?\*\<\>\|\"\:\%\&])", RegexOptions.IgnoreCase)
If knownBad.IsMatch(decodedPath1) Then
TextBoxResults.Text += "Step 3: Pattern match for " & _
"known bad failed" & vbCrLf
Else
TextBoxResults.Text += "Step 3: Pattern match for " & _
"know bad passed" & vbCrLf
End If






Figure 5.13: Matching Known Bad Input (VB.NET)
























Table 5.3: Regular Expression Patterns for Filtering Input

Action


Regex for matching known bad input


File system access


(?:AUX|CO(?:M\d|N\.\.)|LPT\d|NUL|PRN|\n|\r|_progra(?:\~1|m\sfiles)|system32|winnt|[\?\*\<\>\|\”\:\%\&])


Database access


(?:\;\-\-|d(?:elete\sfrom|rop\stable)|insert\sinto_|s(?:elect\s\*|p_)|union\sselect|xp_)


Sending e-mail


(?:rcpt\sto|[\,\<\>\;])


Formatting HTML


(?:\<(?:applet|img\ssrc|object|s(?:cript|tyle)| a)|javascript|onmouseover|vbscript)






Tip

Matching with regular expressions can be complex, and the examples in Table 5.14 may or may not be sufficient for your needs. See www.ex-parrot.com/~pdw/Mail-RFC822-Addressl for an example of the complexity of validating something as simple as an e-mail address.


Escaping Data


Sometimes you want users to be able to enter special characters without restrictions. But allowing these characters might expose your application to attacks such as SQL injection. You might, for example, want to allow users to enter an apostrophe in their last name to allow for names such as O’Brien, but this character has special meaning in an SQL statement. Allowing this character might make the application vulnerable to SQL injection. But the fix is easy: replace every single quote with two single quotes. This allows you to build SQL statements without having to worry about users passing in single quotes. By escaping (or quoting) the single quote character, it no longer has any special meaning to the SQL interpreter.

Here are some common types of data that would require escaping:



Shell commands



SQL statements



Regular expression patterns



HTML



Security Policy




Use regular expressions to either block known bad data or allow only known good data.



Use regular expressions to identify malicious keywords or other patterns.



Escape all special characters from user input.




Data Reflecting












Summary:


Data reflection verifies path or other information using trusted system functions.


Threats:


Directory traversal


When Microsoft first released Windows 2000, security was a long-neglected issue that rapidly gained attention. Security researchers found numerous holes in the operating system, particularly in Microsoft’s Internet Information Services (IIS). Some of the most serious flaws allowed the viewing of protected files and traversing the file system to access files outside the Web content directories. Security researchers found ways to fool IIS into thinking it was retrieving a file with a different extension or a file in the same directory when it was in fact pulling a file from a parent directory. While these techniques fooled IIS, the operating system itself used a different mechanism to access files and therefore accessed them correctly. By discovering subtle differences between how IIS interpreted file paths and how the OS interpreted file paths, researchers exposed some serious vulnerabilities.

Unauthorized File Access


One of the early vulnerabilities discovered in IIS 5 was the ability to view portions of server-side source code by simply appending the string “+.htr” to any URL. Instead of processing the server-side script normally, IIS would return the source code of the file itself, often revealing sensitive information such as database connection strings and passwords. To exploit this vulnerability, an attacker could enter a URL such as this:

www.example.com/global.asa+.htr

Normally IIS does not allow requests for files with .ASP or .ASA extensions, but adding the extra characters fooled IIS into thinking it was accessing a file with the .HTR extension. However, the ISAPI filter that handled .HTR extensions discarded the extra data and returned the contents of the file itself.

Microsoft quickly released a hotfix to address this vulnerability but another researcher found that you could still fool IIS by simply adjusting the string to “%3F+.htr” like this:

www.example.com/global.asa%3F+.htr

Once again, the server returned the source code for global.asa rather than blocking the request. Although Microsoft fixed the specific known vulnerability the first time around, they failed to address the underlying weakness that made it possible to fool IIS in the first place.

IIS was also vulnerable to various directory traversal vulnerabilities. In these, an attacker requests files outside the bounds of the Web application. Normally, IIS will not allow requests outside the Web root, but by disguising the double dots (“..”) through encoding and other techniques, researchers found ways to trick IIS into thinking it was accessing a file within the Web root when it was in fact accessing a file in a parent directory. These turned out to be very serious vulnerabilities because they usually allowed attackers to execute commands and quickly gain control of the server. Furthermore, many internet worms such as Code Red and Nimda exploited these vulnerabilities to propagate themselves from server to server.

Reflecting the Data


To prevent Directory Traversal and Server-Side Code Access, developers usually check file extensions and watch for paths that contain double dots. However, this is not always effective because there are techniques, such as encoding, that attackers use to disguise these characters. Rather than attempting to anticipate every way an attacker can fool your code, a more effective technique is data reflection. With this technique, you take the user input and pass it to a trusted system function. You then read back the system interpretation of that data and compare it to the user input. The steps you would take to reflect a file path are:



Decode the path and expand any environment variables.



Use the System.IO.Path.GetFullPath() method to reflect back a normalized path.



Compare the directory of user input to the directory of the reflected path.



Make sure this path falls within the constraints of the application.



Use only the reflected path from that point on in your code.



The code in Figures 5.14 (C#) and 5.15 (VB.NET) demonstrate these steps.









   // Parameterizing and Data Reflecting
string rootPath = @"e:\inetpub\wwwroot\files\";
string fileExt = ".txt";
string expandedPath =
System.Environment.ExpandEnvironmentVariables(decodedPath1);
string scopedPath =
string.Concat(rootPath, expandedPath, fileExt);
string absolutePath = ";
try
{
absolutePath = Path.GetFullPath(scopedPath);
// Double-check to see if still within parameters
if (!absolutePath.StartsWith(rootPath) ||
!absolutePath.EndsWith(fileExt))
TextBoxResults.Text += "Step 4: Data reflection failed\n";
else
TextBoxResults.Text += "Step 4: Data reflection passed\n";
}
catch (Exception ex)
{
TextBoxResults.Text += "Step 4: Reflection failed " +
"with an Exception: " + ex.ToString() + "\n";
}






Figure 5.14: Reflecting Data (C#)








'Parameterizing and Data Reflecting
Dim rootPath As String = "e:\inetpub\wwwroot\files\"
Dim fileExt As String = ".txt"
Dim expandedPath = System.Environment. _
ExpandEnvironmentVariables(decodedPath1)
Dim scopedPath = String.Concat(rootPath, _
expandedPath, fileExt)
Dim absolutePath
Try
absolutePath = Path.GetFullPath(scopedPath)

   'Double-check to see if still within parameters
If Not absolutePath.StartsWith(rootPath) Or _
Not absolutePath.EndsWith(fileExt) Then
TextBoxResults.Text += "Step 4: Data reflection failed" & vbCrLf
Else
TextBoxResults.Text += "Step 4: Data reflection passed" & vbCrLf
End If
Catch ex As Exception
TextBoxResults.Text += "Step 4: Parameterizing failed " & _
"with an Exception: " & ex.ToString() & vbCrLf
End Try






Figure 5.15: Reflecting Data (VB.NET)

The advantage of this technique is that because the operating system will ultimately decide which file to access, you have the system tell you which file it intends to access based on the given user input. You validate the path and use that same path when actually accessing the file.

Security Policy




Reflect data using trusted system functions to prevent attacks such as directory traversal.



Always work with the reflected path in subsequent operations.




Encoding Data












Summary:


Data encoding neutralizes malicious HTML content.


Threats:


Cross-site scripting


Sometimes hackers are not trying to break into your Web site but instead want to exploit your Web application to target other users or glean user data. For example, an attacker may want to gain access to another user’s online bank account or personal e-mail. Using a technique called cross-site scripting (sometimes referred to as XSS), an attacker injects active HTML content into a Web page to exploit other users. This content may contain malicious HTML markup, including:



Deceptive links



HTML form tags



Client-side script



ActiveX components



At the heart of this attack is the abuse of trust that results from the malicious content running on a trusted Web site. Attackers can exploit cross-site scripting vulnerabilities to carry out a large number of attacks, such as:



Stealing client cookies



Bypassing policy restrictions



Accessing restricted Web content



Gathering Web-user IP addresses



Modifying the behavior of links or forms



Redirecting users to an untrusted Web site



Indeed, many developers underestimate the seriousness of cross-site scripting attacks.

Cross-Site Scripting vulnerabilities occur when a Web application dynamically displays HTML output to one user based on input from another user, such as displaying the unfiltered results of a guestbook or feedback system. Attackers can exploit this by injecting HTML tags that modify the behavior of the Web page. For example, an attacker might inject JavaScript code that redirects a user to another site or steals a cookie that contains authentication information. Web-based e-mail services such as Hotmail have long been a target of cross-site scripting attacks because they display HTML content in e-mail messages. An attacker simply has to send the target a specially crafted e-mail to execute the attack.

For cross-site scripting to work, the attacker must send HTML markup through some form of input. This might include an HTML form, a cookie, a QueryString parameter, or even an HTTP header. For example, there are many login pages that pass error messages back to the user like this:

www.example.com/login.aspx?err=Invalid+username+or+password

The page checks the Err parameter and if it exists, displays the contents back to the user as an error message. If the page does not filter this input, an attacker might be able to inject malicious code.

Fortunately, ASP.NET will automatically block any user input that appears to contain HTML code. Figure 5.16 shows how ASP.NET blocks a request for the URL:

http://localhost/input.aspx?text=<a href="></a>.


Figure 5.16: Built-In ASP.NET HTML Blocking

This method is limited, because it is easy to overlook all the different character sets and encoding methods that ASP.NET or the client browser supports. Some character sets allow for multi-byte or other encoded representations of special characters. Character sequences that may seem benign in one character set could in fact represent malicious code in another. While you can often filter out special characters, you cannot completely rely upon this method for total security.

Encoding is a technique that neutralizes special characters by modifying the representation of those characters. HTML encoding in particular is a technique that replaces special characters with character-entity equivalents that prevent the browser from interpreting the characters as active HTML. Table 5.5 shows the HTML-encoded representations of some common characters. If a browser encounters any of these HTML-encoded characters, it displays the character itself rather than treating it as a special character.
























Table 5.5: Example HTML Character Entity Encoding

Name


Character


Decimal Code


Entity


Quotation Mark



&#34;


&quot;


Ampersand


&


&#38;


&amp;


Less Than


<


&#60;


&lt;


Greater Than


>


&#62;


&gt;


Using the Table 5.5, if we had this HTML markup:

<a href=">ASP.NET</a>

We would encode it as follows:

&lt;a href=&quot;&quot;&gt;ASP.NET&lt;/a&gt;

The first example would show up as an active link, whereas the second example would display the HTML markup itself.

The .NET Framework provides methods in the Server object, an HttpServerUtility class, to encode strings that could potentially be dangerous if left unencoded. These methods are:



HtmlEncode Encodes an HTML string to safely output to a client browser



UrlEncode Encodes a string to safely pass it as a URL



UrlPathEncode Encodes a string to safely pass it as the path portion of a URL



Figures 5.17 (C#) and 5.18 (VB.NET) demonstrate how to use the HtmlEncode method







private void Button1_Click(object sender, System.EventArgs e)
{
Label1.Text = Server.HtmlEncode(TextBox1.Text);
Label2.Text =
Server.HtmlEncode(Orders.Customers[0].Name);
}






Figure 5.17: Using HtmlEncode (C#)







Private Sub Button1_Click(ByVal sender As System.Object, ByVal e _
As System.EventArgs) Handles Button1.Click
Label1.Text = Server.HtmlEncode(TextBox1.Text)
Label2.Text = _
Server.HtmlEncode(Orders.Customers[0].Name)
End Sub






Figure 5.18: Using HtmlEncode (VB.NET)

Another type of encoding is URL encoding for URLs and query strings embedded in HTML. You should use UrlEncode and UrlPathEncode anywhere you reference a URL or query string in an HTML document. This includes the A, APPLET, AREA, BASE, BGSOUND, BODY, EMBED, FORM, FRAME, IFRAME, ILAYER, IMG, ISINDEX, INPUT, LAYER, LINK, OBJECT, SCRIPT, SOUND, TABLE, TD, TH, and TR HTML elements. Use UrlEncode on full URLs and UrlPathEncode to encode a path only. The difference is that UrlPathEncode encodes spaces as %20, rather than the plus sign (“+”) that UrlEncode uses. Furthermore, UrlPathEncode does not encode all punctuation characters as UrlEncode does.

Security Policy




Use HtmlEncode to encode a string for browser output.



Use UrlEncode to encode a URL string for output.



Use UrlPathEncode to encode the path portion of a URL for output.




Encapsulating












Summary:


Hashing encapsulates data for safe handling.


Threats:


Malicious input


Sometimes you need to act on user input but you may not care about the actual value of the input. For example, you might want a unique identifier based on user input or want to store a value such as a password for later comparison. You can use a hash to encapsulate the data in a safe string format while still maintaining a link to the original data.

Good hashing functions have some properties that make them useful for encapsulating data:



They produce long, random digests that make use of the entire key space.



They produce few collisions; it would be extremely rare for two input strings to generate the same hash.



They always produce digest strings of the same length.



Given a hash you cannot derive the original data.



With a hash you can neutralize any malicious content because the hash mangles the string into a safe format. You can then format the hash as a hex string for safe handling.

If you hash a password before saving it, you never need to bother with checking it for invalid characters because the hash will not contain malicious content. This allows users to enter characters they want in a password without you having to worry about the impact of special characters in the string.

Another example is when you must create a file based on user input. Because any file operation based on user input could be dangerous, you might want to first convert the input to a safe hash string. This specific technique is described in more detail in Chapter 6.

Hashes are also effective at disguising data to make it less vulnerable to guessing attacks. One e-commerce application used temporary XML files for its shopping cart. The filenames were based on the user ID and the current date. However, a flaw in the application often left the files orphaned so they were not deleted at the end of the session, leaving a directory full of temporary files containing private user information that included customer credit card details. An attacker needed simply to employ smart guessing tactics to gain access to this information. Instead, using a filename based on a hash would make it unpredictable and would use a large enough key space to prevent guessing.

Security Policy




Use hashes to encapsulate data for safe handling.



Convert hashes to hex values to create safe alphanumeric strings.




Parameterizing












Summary:


Parameterizing allows you to fix the context of user input.


Threats:


Directory traversal, file system access, SQL injection, command injection



Parameterizing is a technique in which you take user input and place it within a fixed context so that you can control the scope of access. Consider a Web application in which you access files based on a selected link. A link may take you to a URL such as this:

www.example.org/articles.aspx?xml=/articles/a0318.xml

This first problem with this URL is that it is immediately apparent to attackers that you are accessing the file system, perhaps prompting them to experiment to find ways to break the application: what happens if you pass a filename with a different extension? Or what if you add additional path information?

To prevent abuse of your Web application, accept only the minimal amount of information required and insert this as a parameter to a full path. If the path and filename are fixed, a better version of the URL may be this:

www.example.org/articles.aspx?article=a0318

Now take the /articles path and append the article parameter, followed by the .xml extension. Now, no matter what the user enters, it will start in the /articles path and have an .xml extension.





Warning

Be careful not to rely on parameterizing alone to guarantee scope. Microsoft made this mistake with the showcode.asp sample included with early versions of IIS (see www.securityfocus.com/bid/167). The programmer checked to see if the final path string contained a specific directory, but did not check for double-dots (“..”) that allowed attackers to request files from a parent directory. The best way to handle this is to combine parameterizing with data reflecting, pattern matching, and other techniques described in this chapter.


Parameterizing is not just for file access; it is an effective technique for limiting many types of attacks. Chapter 6 shows how to use parameters to prevent SQL injection.

Security Policy




Use parameterizing to fix the context and scope of user data.



Combine parameterization with other techniques to prevent directory traversal.




Double Decoding












Summary:


Double decoding helps detect multiple layers of encoding.


Threats:


Directory traversal, file system access, server-side code access


Double decoding is a technique specifically designed to counter a type of encoding attack called double encoding. Vulnerability to this type of attack occurs because your application may decode an encoded string more than once from different areas of the application. Attackers can take advantage of this by creating multiple layers of encoded strings, usually in a path or query string. In other words, you encode a string, and then encode that string again. This might allow an attacker to bypass pattern matching or other security checks in your application code.

IIS 5 was vulnerable to this type of attack. In May of 2001, Microsoft issued a cumulative security patch for IIS (see www.microsoft.com/technet/security/bulletin/MS01-026.aspx) that included a fix for a double decoding vulnerability. IIS decodes incoming requests to render the path in a canonical form. It then performs the necessary security checks on this path to be sure that the user is requesting a file within a web content directory. After this check, IIS performed a second superfluous decoding pass. An attacker could take advantage of this by encoding the path twice. The first decoding pass will remove the first layer of encoding but because the path still has another layer of encoding it got past the IIS security checks. In the second decoding pass, IIS decoded the second layer of encoding and produced the final path. The end result is that an attacker could bypass IIS security checks to access files outside of the web root.

Because it is difficult to anticipate a string being decoded twice in your application, a more effective strategy is to initially check user input for multiple layers of encoding. By decoding a string twice, you can detect multiple layers of encoding, but what happens if someone uses more than two levels of decoding? How do you know how many times to decode to get to the final layer? Could someone cause a denial of service by encoding a string a hundred times? The solution is that you only decode the string twice, comparing the first result with the second result. If these do not match, then you know that the string contains two or more levels of encoding and is likely not a valid request. If you encounter this, simply reject the request and return an error to the client. Figures 5.19 (C#) and 5.20 (VB.NET) demonstrate the double decoding technique.







    // Double decode
string decodedPath1 = Server.HtmlDecode(inputFilePath);
string decodedPath2 = Server.HtmlDecode(decodedPath1);
if (!decodedPath1.Equals(decodedPath2))
TextBoxResults.Text += "Step 1: Double decode failed\n";
Else
TextBoxResults.Text += "Step 1: Double decode passed\n";






Figure 5.19: Double Decoding (C#)







  'Double decode
Dim decodedPath1 As String = Server.HtmlDecode(inputFilePath)
Dim decodedPath2 As String = Server.HtmlDecode(decodedPath1)
If Not decodedPath1.Equals(decodedPath2) Then
TextBoxResults.Text += "Step 1: Double decode failed" & vbCrLf
Else
TextBoxResults.Text += "Step 1: Double decode passed" & vbCrLf
End If






Figure 5.20: Double Decoding (VB.NET)


Security Policy




Use double decoding to detect multiple layers of encoding.



Reject all requests that contain more than one layer of encoding.




Syntax Checking












Summary:


Syntax checking is a last line of defense against those attacks that get past other filters.


Threats:


Malicious input


After accepting user input and applying one or more of the techniques described in this chapter, you will eventually need to do something with the data. You may, for instance, build an SQL statement to look up account information based on a given username. You might use one or more techniques in this chapter to check user input, but before executing that SQL statement on the server, you might want to perform a final check to be sure that the SQL syntax follows the format you expect. For example, you don’t want to send an SQL statement with multiple verbs such as two SELECT statements or a SELECT and a DELETE. Passing the final string through a pattern-matching function can be extremely effective in stopping attacks, albeit at the cost of some additional processing overhead.

Syntax checking serves as a last line of defense against those attacks that get past all your other filters. Examples of syntax checking are:



Ensuring that a shelled command does not contain piping, redirection, command-concatenation characters, or carriage returns



Ensuring that e-mail address strings contain only a single address



Ensuring that file paths are relative to a Web content directory and do not contain drive designators, UNC paths, directory traversal characters, or reserved DOS device names



Security Policy




When appropriate, check the final syntax of any string that is based on user input.




Exception Handling












Summary:


Exception handling can catch errors before hackers exploit them.


Threats:


Malicious input


Hackers don’t exploit normal operations of your Web application; they usually go after the exceptions that you failed to anticipate. Properly handling exceptions is a powerful defense in stopping a large percentage of Web application vulnerabilities. Although your code might fail to catch malicious user input, an exception handler might catch an error before an attacker can exploit it.

Exception handling is a long-standing best practice, but limited error handling capabilities in classic ASP has resulted in many programmers failing to properly deal with exceptions. ASP.NET provides a much more robust error handling system that you should take advantage of.

Exception handling is much more than handling errors. Some components do not raise an error but provide error information through events or properties. Furthermore, sometimes an error never occurs, but the results are not what you would expect. For example, if you perform a database query to look up a particular user’s record, you would expect only that record to be returned. If it returns more than one record, you have reason to be suspicious. You should always check results to be sure they are as you would expect them to be.

Other exceptions to consider are:



Return codes from shelled DOS commands



Return codes from mail servers



The size, length, or data type of returned data



Operation timeouts





Tip

Sometimes the nature of the error is not as important as its frequency. For higher security you might want to consider adding code to check for multiple errors from the same client within a given period of time. Because many attacks depend on exploiting errors, encountering too many errors from one user might be a strong indicator of an attack.




Security Policy




Take advantage of the robust error handling features in ASP.NET.



Check return results to be sure they are consistent with what you expected.




Honey Drops












Summary:


Honey drops work as mini intrusion detectors.


Threats:


Server-side code access, file system access, command execution, SQL injection


Many people are familiar with the concept of a honey pot, which is a system designed to lure and ensnare hackers, giving an administrator time to gather evidence and track down the intruder. Sometimes you can’t anticipate all possible attacks, but you’ll at least want to detect and log intrusions. Honey pots, if carefully managed, can prove to be effective intrusion detection systems. You can integrate this same concept into your Web application by using small honey pots, or honey drops. This is how it works:



Place unique strings throughout your application or data that you can use as honey drops. For example, create fake database records, fields, tables, or even complete databases, depending on the type of intrusion you want to monitor.



Configure your application so that it will never normally access this data. For example, if you created a fake database field, never use a wildcard select statement (such as “SELECT * FROM”), but instead list the specific fields you require.



Configure your application or an external packet sniffer (or both) to watch for these strings leaving your database or Web server.



Suppose that you have an e-commerce Web site that accepts credit card transactions and want to use honey drops to detect any unauthorized access to your data. To do this, create a single fake record in your database using a unique credit card number that you would not otherwise encounter, perhaps one containing all zeros. Make sure that you structure any SQL queries so that this record would not appear under normal circumstances so that if it ever does appear in a query, there is a good chance it is an intrusion, such as a hacker using SQL injection to access your database.

There are several ways for you to watch for this string. One method is to write code to check every query result to see if it contains that record, although this might add a considerable amount of processing overhead. Another method is to use an intrusion detection system (IDS), such as Snort (www. snort.org), to sniff the network link between the Web server and the database, and also between the Web server and the Internet. Finally, configure the sniffer to look for the fake record you created and alert you anytime this value travels from the database to the Web server or from your Web server to the Internet. Note that encrypted network connections prevent sniffing, so you might need to adjust your strategy based on your particular configuration.

Honey drops are not just for databases. You can also use them to detect access to files, directories, or even commands. Here are some more ideas:



Place a conspicuous, blank text file with a unique filename within your Web content directories. Then, configure your IDS to watch for this filename string leaving the network.



Place server-side comments with a unique string in your source code to detect access to server-side scripts.



Change the prompt variable in your command prompt to a unique string to detect remote command access.



Honey drops are not appropriate for all applications, but they can provide an extra layer of protection by allowing early detection of application attacks.

Security Policy




Use honey drops in your database to detect SQL injection attacks.



Use honey drops in your file system to detect file system access.



Use honey drops in your source code to detect server-side code access.



/ 96