This article will describe how to protect your J2EE application from Information Leakage and Improper Error Handling attacks using ESAPI and other techniques. As with all of the detail articles in this series, if you need a refresher on OWASP or ESAPI, please see the intro article The OWASP Top Ten and ESAPI.
What’s the problem?
As usual, let’s check in with what OWASP says it is:
“Applications frequently generate error messages and display them to users. Many times these error messages are quite useful to attackers, as they reveal implementation details or information that is useful in exploiting a vulnerability.” [from here]
This can be broken down further into two basic categories from the web end user perspective.
- An error message with too much detail (eg. stack trace, sql statement, etc) is splashed onto the screen.
- An error message for a specific function varies depending on minor changes to the input enabling the user to determine exactly what error occurred (eg. a different error message for a bad username and a good username/bad password – this tells the attacker the username is valid.)
The two categories above really differ at the level of concern. The issue of too much detail often stems from sending information to the screen that is internal to the application – information that has more to do with the code and/or configuration of the application. Often times these messages are NEVER intended to be shown to the end user. This is a technical issue. The issue of specificity in error messages has to do with user messages that ARE intended to be seen by users. However, the wording for them is poorly chosen. This is a business issue of coming up with appropriate messages.
One sidebar note here is that of exception handling. Appropriate exception handling in Java is often a topic of debate. One of the main issues stems from that of the difference between 2 core classes: Exception and RuntimeException.
1. The former (Exception and any subclass) is referred to as a checked exception, meaning that any code that calls any other piece of code that may throw one of these exceptions HAS to handle it in some way, either by wrapping the code in a try/catch block, or by explicitly throwing the same exception (or a superclass) in the method signature. Proponents argue that this forces developers to be aware of the types of exceptions that code may throw, and deal with them appropriately. Opponents argue that this can complicate code and cause many developers to trap exceptions and not deal with them properly or at all, which is worse than bubbling them up in the first place.
2. The latter (RuntimeException and any subclass) is referred to as an unchecked exception, meaning code may or may not deal with these exceptions, it is their choice. Proponents argue that this allows flexibility in handling exceptions and provides for cleaner code. Opponents argue that exceptions of this variety essentially don’t “notify” their callers of the types of exceptions they may throw, and therefore the calling code is less reliable.
Honestly, no matter where you land in this debate, the issue of information leakage still exists for J2EE web applications today. At the very least, NullPointerExceptions exist in every J2EE app known to man, so it’s still possible to bubble up an exception even if your entire application exception heirarchy is checked, so the information presented here is still very relevant.
So far, we’ve noted the types of application error messages that can be leaked to the end user, as well as a brief discussion about the internal exception management of an application.
Where do we go from here? ….
There are various specific techniques for dealing with information leakage and improper error handling. Several of these techniques are valid. The point of this article is not to try and enumerate all of them, but to create a working safe solution that can be implemented. Your solution may vary in style, but the underlying principles should be the same: preventing (as much as is reasonable) the attacker from gaining information from your system that can be used in an attack.
Again as above, we’ll break the discussion into 2 parts: missing exceptions altogether, and handling error messages improperly (often by giving too detailed of an error message).
1. First we’ll discuss how to resolve presenting the user with unhandled exceptions. These fall into the category of “should NEVER be presented to the user”. First, these occur because all possible exceptions are not handled in every piece of code. The first thing to note here is that your application should have a standard for how it handles exceptions. Ignored exceptions are an epidemic in Java (and other languages), but that is too large a topic to tackle here. No matter your standard for handling exceptions, inevitably there are going to be some places where you might miss them. Even if you handle everything you think you ought, there may be a JSP issue that would present an exception to the user.
My suggestion for how to handle this is a J2EE standard technique and quite simple to implement: configure an exception handler in the web.xml configuration file. An example of how to do this is below.
<error-page> <exception-type>java.lang.Throwable</exception-type> <location>/error.jsp</location> </error-page>
This is a very simple solution to handle any subclass of java.lang.Throwable (which covers all types of exceptions) that gets bubbled up through the application, whether by a servlet, jsp, or some framework specific code and preventing the user from seeing it. What it will do then is redirect the user for any previously unhandled exception it catches to /error.jsp. This page should have some generic text on it stating that an error occurred, and should not give specifics as to what that error is.
Note: MVC frameworks often offer an exception handling mechanism that is intended to do this same thing. However, be aware that many of these do not work if the exception occurs in the JSP page since that is outside the scope of what the framework controls. Another viable option in many cases is to use a J2EE filter to do appropriate exception handling since the filter is accessed both before and after the servlet/jsp request is performed, and can catch exceptions that occur in either of them.
2. The second type of issue is caused by giving the user too much information in an error message on the screen. Often times the error message that is sent to the screen is populated with the exception message. This is a dangerous technique since this data could often be very detailed and could give an attacker technical information about the system.
My suggestion for how to get around this involves using 2 techniques in cooperation.
a. First, for any exception in your application exception heirarchy, create member variables along the lines of userMessage and detailedMessage. ESAPI does this with their exception heirarchy, so you can browse their code for examples. The logic is that when these exceptions are created, they are created with very generic information for the user to see, and then the detailed information can be logged for admins to see. The user should only ever be presented with the generic message.
b. Second, for exceptions that don’t live in your application heirarchy (and even those that do in some cases), one should use a static very generic message to display on the screen for any security related issues. The example used above (using a different error message for a bad username and a good username/bad password – this tells the attacker the username is valid.) could be resolved by using a somewhat generic error to cover both errors, possibly “The user could not be logged in” or “Login failed”. This conveys the message to the user that the login failed, but doesn’t give specific information about why.
Note: One important point here is that this issue is a balancing act between user friendliness and security. It may save your users some frustration if they see that they’ve typed in the wrong username (honest mistake) rather than the wrong password, but that also gives an attacker opportunity. This decision, like most others must be considered in the context of your environment. My suggestion is to go with the more secure option by default, and only change if you absolutely must. Even then, you should consider putting additional protections in place, such as possibly using an ESAPI style application intrusion detection mechanism like AppSensor to track things like a user trying to login with many different usernames in a short period of time.
At this point, hopefully you’ve gotten a glimpse of how information leakage and improper error handling can negatively affect your application. Additionally, you’ve gained some insight on how to deal with exceptions and user messages properly. As mentioned before, there are various legitimate techniques that could be used, and the above is just one option.
Well, that’s all for this article – hope you’ve found it helpful. Let me know if you have any questions or suggestions.
Other articles in this series:
Part 0: The OWASP Top Ten and ESAPI
Part 1: The OWASP Top Ten and ESAPI – Part 1 – Cross Site Scripting (XSS)
Part 2: The OWASP Top Ten and ESAPI – Part 2 – Injection Flaws
Part 3: The OWASP Top Ten and ESAPI – Part 3 – Malicious File Execution
Part 4: The OWASP Top Ten and ESAPI – Part 4 – Insecure Direct Object Reference
Part 5: The OWASP Top Ten and ESAPI – Part 5 – Cross Site Request Forgery (CSRF)
Part 6: The OWASP Top Ten and ESAPI – Part 6 – Information Leakage and Improper Error Handling
Part 7: The OWASP Top Ten and ESAPI – Part 7 – Broken Authentication and Session Management
Part 8: The OWASP Top Ten and ESAPI – Part 8 – Insecure Cryptographic Storage
Part 9: The OWASP Top Ten and ESAPI – Part 9 – Insecure Communications
Part 10: The OWASP Top Ten and ESAPI – Part 10 – Failure to Restrict URL Access