Handling Exceptions avoid Information leakage

Post date: Jul 25, 2011 2:54:34 AM

Before ASP.NET, error handling was never a strong suit of ASP. Despite taking great efforts to handle possible error conditions, it is not uncommon to see classic ASP applications crash and display cryptic error messages. For applications critical to a company’s success, this is might be a huge embarrassment and perhaps even a security risk. You may have seen something like this quite often with classic ASP:

Microsoft VBScript runtime error '800a0006' Overflow /asp/test.asp, line 25

To build a secure application, you must handle exceptions. The .NET Framework provides much improved error handling mechanisms to allow proper and consistent error handling across your application. The .NET Framework provides features to:

While every programmer hopes to write bug-free programs, this may not always be a realistic goal. Bugs in programs can be incredibly frustrating, usually disrupting the programs they infect. Such errors can be classified into these four categories, which we’ll discuss in the following sections:

A syntax error is one of the most common errors in programming. This is especially true if you are new to a particular language. Fortunately, syntax errors can be resolved quite easily. In Visual Studio .NET, syntax errors are underlined similar to that of misspellings typed into Microsoft Word. To know the cause of the error, simply position the mouse over the underlined word and the tool tip box will appear. You generally catch syntax errors while coding and they usually have little effect on the final security of the application.

Compilation errors occur when the compiler tries to compile the program and realizes that the program contains code that may potentially trip up a program. Since compiler errors prevent the compiling process from finishing, you usually catch these errors before your code goes into production.

Runtime errors occur during the time when the application is running and something unexpected occurs. It happens regularly in projects that have very tight deadlines. Programmers stretched to their limits are often satisfied that their program runs. They do not have the time to carefully consider all the different possible scenarios in which their programs may be used; hence the result is often a buggy and potentially vulnerable program. To ensure that an application is as robust and bug-free as possible, it is important to place emphasis on anticipating all the errors that can occur in your program. Runtime errors are a security risk because they might reveal sensitive information and facilitate attacks such as denial of service and SQL injection.

Finally, there are logic errors, which consist simply of code segments of that do not work as expected. The failure may result in the absence of certain features or providing extra unintended features. Logic errors might result in privilege escalation, account hopping, or other application attacks.

Using Structured Error Handling

Summary:

Threats:

Structured error handling promotes careful forethought to exception handling

Information leakage

Error handling got a big boost in the .NET Framework. With classic ASP, error handling was unstructured, done using the limited On Error statement. In VB.NET, error handling can both be structured and unstructured. Error handling allows you to catch, react to, and add relevancy to application errors.

Unstructured Error Handling

Unstructured error handling in VB.NET is similar to what was available in classic ASP. Consider the following code:

Dim shortNum As Int16 Dim intNum As Int32 intNum = 999999 shortNum = intNum ' narrowing will fail!

Figure 7.1: Runtime Error

An error message such as this might reveal sensitive information about your application but it might also tip off a hacker that you do not handle errors. To prevent the error from appearing, VB.NET supports the unstructured On Error statement:

Dim shortNum As Int16 Dim intNum As Int32 On Error Resume Next intNum = 999999 shortNum = intNum ' narrowing will fail! If Err.Number <> 0 Then   Response.Write(Err.Description) End If

The On Error Resume Next statement ignores any error that happens and continues as though no error has occurred. The error information is contained within the Err object. If an error has occurred, the property Number of the Err object would contain a nonzero value.

In the preceding example, we examine three errors. The first error will cause the execution to jump to the ErrorHandling block, and after the error description has been printed, it resumes execution at the point it was interrupted. The second error will be ignored while the third error will cause the program to fail.

As you can see, unstructured error handling makes your code messy and difficult to debug, and also affects future maintenance. Hence, the recommended way to handle errors is to use structured error handling.

Structured Error Handling

Rather than placing an On Error statement at the beginning of a block to handle potential errors, .NET supports structured error handling using the Try-Catch-Finally construct to handle exceptions. The Try-Catch-Finally construct then allows developers to actively catch different forms of errors and respond to them appropriately. It has the following syntax:

Try   ' Executable statements that may cause   ' an exception. Catch [optional filters]   ' Catches the error and responds to it Catch [optional filters]   ' Catches the error and responds to it [Additional Catch blocks] Finally ' Always executed, with or without error End Try

Using structured error handling, we get:

Dim shortNum As Int16 Dim intNum As Int32 intNum = 999999 Try   shortNum = intNum ' narrowing will fail! Catch anyException As Exception   Response.Write(anyException) End Try

When executed, the error message printed is:

System.OverflowException: Exception of type System.OverflowException was thrown. at WebApplication1.WebForm1.Page_Load(Object sender, EventArgs e) in C:\Documents and Settings\lwm\VSWebCache\LWM\WebApplication1\ WebForm1.aspx.vb:line 31

When the line in the Try block is executed, it generates an exception, which is then caught by the Catch block. The statement in the Catch block prints out the reason for causing that exception. The previous example doesn’t really do justice to the structured error-handling construct in VB.NET. Consider the following revised example:

Dim shortNum As Int16 Dim intNum As Int32 intNum = 999999 Try   shortNum = intNum ' narrowing will fail! Catch outofMemoryException As System.OutOfMemoryException   Response.Write("Out of memory!") Catch overflowException As System.OverflowException   Response.Write("Overflow!") Catch anyException As Exception   Response.Write("Some exception!") End Try

Here we have multiple Catch statements. Each Catch statement tries to catch the different kinds of exceptions. If discovered, the exception is evaluated from top to bottom. Once a match is found, the codes within the Catch block are executed. If no match is found, an error message is displayed. The three exceptions in the preceding list include:

When the statement within the Try block generates an exception, the few Catch statements are evaluated in order. First, it compares with the initial Catch block and checks to see if it matches the kind of exception specified in the Catch statement. If it doesn’t, it will compare it with the next, and so on. It stops only when a match is found. In our case, the exception is an overflow exception and hence the second Catch block is matched. If no match is found, an error message will be generated. Lastly, the Finally block allows you to perform whatever cleaning up operation codes need doing, regardless of whether the exception occurs.

... Catch anyException As Exception   'Response.Write(anyException)   Response.Write("Some exception!") Finally   '---code here always executes   '---regardless of the exception End Try

There are some key points to remember when writing structured error-handling routines. First, you must be sure to structure the error handler so that when the code fails, it fails securely. Also, carefully consider the effect of using exception filters and Finally blocks with multiple layers of error handling. Sometimes these blocks run in an unexpected order so you must use caution when making security decisions within these blocks of code.

Security Policy

Reporting and Logging Errors

Summary:

Threats:

Give users generic error details while gathering more comprehensive information for administrators and_developers

Information leakage

If your application encounters an exception, it must somehow handle this exception. Most often, this appears as a 500 error returned to the client along with a default error page like that shown in Figure 7.1. You will generally want to avoid the default error handler because it provides little useful information to the legitimate user, yet it might provide a wealth of information to an attacker.

If the user did something wrong, you should instruct them on how they can fix the error. For example, if they left a required form field blank, you should let them know that you require data in that field. Nonetheless, you should never reveal too much information in your error messages. If there is nothing the user can do to remedy the situation, for instance if the back-end database is down, then you should simply provide a generic message indicating that an error occurred on the server.

Generic Errors

Generic errors are the key to safe error reporting. You’ll usually want to hide detailed exception information from end users. Here are some example error messages you should avoid:

Instead, you should consider error messages such as these:

In ASP.NET you can provide generic HTML pages for handling various classes of errors. The following is an example of the exception settings in a web.config file:

<customErrors defaultredirect="/error/error.aspx" mode="on">      <error statuscode="404" redirect="/error/404Error.htm"/>   <error statuscode="500" redirect="/error/500error.aspx"/> </customErrors>

This configuration provides a generic page named error.aspx, but also provides custom redirect pages for 404 and 500 errors. Any unhandled error will cause a redirection to one of these three pages.

Note 

The default error handler settings in the web.config file apply only to files mapped to ASP.NET. If you want these settings to apply to other files, such as HTM or GIF files, you must either configure IIS to use these same pages or configure IIS script maps to allow ASP.NET to handle these other file extensions. See Chapter 2 for instructions on mapping non-ASP.NET resources.

ASP.NET also allows you to specify error handlers on the page or application levels. To specify a global error handler for a page, use the Page.Error event. For a global application error handler, use the Application.Error event in Global.asax.

Logging Errors

Although you do not want the end users to see detailed error messages, you certainly do need this information for correcting errors or to alert you of an attack. You can use several methods for logging errors in your ASP.NET application, examples of which are as follows:

The method you choose for logging errors depends greatly on the particular needs and size of your application. Here are some questions to ask yourself when evaluating a logging mechanism:

In some cases, it might be appropriate to provide multiple logging mechanisms. This helps ensure accuracy and reinforces the non-repudiation of log data. You might, for instance, use the IIS logs to track errors but save additional error details to a separate log file. In addition, you might want to use a sniffer or intrusion detection system to log suspicious network traffic between the client and the server.

When you log exception details, you should try to anticipate which information will be most useful to you. You might, for instance, log the following details:

Information that you might not want to log includes:

Security Policy