Improper error handling
Every application has the potential for an error to occur. Even if an application is completely standalone, there is the potential that a fault will occur with the computer’s CPU or RAM that could affect execution.
Handling errors correctly is essential to the security of an application. If an error occurs and is not properly managed, it is possible that an attacker could exploit it. Alternatively, a poorly-handled error might leak sensitive data from an application that could aid in its exploitation.
Learn Secure Coding
Common error handling mistakes
Proper error handling is essential to application security. When developing an application, it is important to both ensure that any failure cases are handled securely and that the application does not leak sensitive data via error messages or side channels.
Failing to handle errors correctly
Error handling can go wrong in a number of different ways. Some common examples of mistakes that developers make when handling errors include:
- Not testing for errors. Many different operations within an application can cause errors, such as accessing files or allocating memory. Before attempting to read from or write to a file or a pointer, it is important to test that the file was opened or the memory was allocated properly
- Catching but not handling errors. Languages like C++ have structures for handling code that could throw errors (like try-catch). If a catch block catches an exception but doesn’t fix the problem, then the application could continue to run in an invalid state
- Not handling all of the errors. Structures like C++’s try-catch can enable a catch block to handle all exceptions thrown by the code in the try block. Using this feature may make the code easier to write but introduces the possibility that an unforeseen exception could break an application
When developing an application, it is important to ensure that all error cases are managed securely. This includes both testing the return value of any functions that return false upon failure (like C++’s malloC) and ensuring that exception-handling code reliably returns an application to a usable state or exits it cleanly.
Leaking data in error messages
Error messages are intended to provide information to the user. However, when creating error messages, it is important to ensure that they do not provide too much data. If they do, it may help an attacker to exploit the code.
A common example of providing “too much” information in an error message is the feedback provided for an authentication page. In some cases, the error message may say “The username that you entered is incorrect” or “The password that you entered is incorrect”.
By differentiating between an incorrect username and an incorrect password, this application makes it much easier for an attacker to perform a brute-force or credential stuffing attack against an application. Searching the complete space of potential username and password combinations is much more difficult and time-consuming than trying to find the password associated with a particular username that is known to exist on the application.
Leaking data through side channels
Error messages are not the only way in which an application can leak sensitive data. An attacker targeting a particular application can also glean useful data from side channels or unintentional sources of data about an application’s operations.
A number of different potential side channels exist, including power usage, electromagnetic emissions from a chip and application execution time. Of these, timing side channels are the easiest to measure and exploit remotely.
Going back to our authentication example, consider the case where an application is designed to execute efficiently. Namely, it will stop running and present an error message as soon as the user’s input is determined to be incorrect.
Even if the error message is the same for all cases, the application’s runtime can leak sensitive information about the correct authentication credentials. If the username is tested first, then an authentication attempt with a valid username will take longer to generate an error than an invalid username. If a password is checked character-by-character, then passwords with more correct characters will result in a longer runtime. These optimizations provide an attacker with the ability to dramatically decrease the time necessary to guess a set of valid credentials.
Handling errors properly
Any application can have errors occur, and it is important to ensure that these errors are handled properly and securely. This requires avoiding both potential extremes in error handling: failing to handle an error properly and creating data leaks by handling them “too well.”
Learn Secure Coding
Sources
- CWE CATEGORY: Error Conditions, Return Values, Status Codes, cwe.mitre.org
- CWE-209: Generation of Error Message Containing Sensitive Information, cwe.mitre.org
- Timing side-channel attack example, security.stackexchange.com