Secure coding

Improper error handling

Howard Poston
August 25, 2020 by
Howard Poston

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

Learn Secure Coding

Build your secure coding skills in C/C++, iOS, Java, .NET, Node.js, PHP and other languages.

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

Learn Secure Coding

Build your secure coding skills in C/C++, iOS, Java, .NET, Node.js, PHP and other languages.

Sources

Howard Poston
Howard Poston

Howard Poston is a copywriter, author, and course developer with experience in cybersecurity and blockchain security, cryptography, and malware analysis. He has an MS in Cyber Operations, a decade of experience in cybersecurity, and over five years of experience as a freelance consultant providing training and content creation for cyber and blockchain security. He is also the creator of over a dozen cybersecurity courses, has authored two books, and has spoken at numerous cybersecurity conferences. He can be reached by email at howard@howardposton.com or via his website at https://www.howardposton.com.