Error and exception handling in web applications can introduce security issues, often in the form of denial of service (i.e., when a service crashes because of poor error handling) and information disclosure (i.e., when an exception containing sensitive details about the system is propagated to the user/attacker).

To combat this, the system needs to fail gracefully, revealing little details about the failure and recovering as much as possible. When it comes to exceptions, managed languages have simple and well-understood mechanisms for exception handling. However, throughout my research I have failed to find advice on how to construct a proper exception handling mechanism in modern web applications that include several layers of logic between the database and the client applications.

For example, the Spring framework has the controller (that provides the APIs and handles HTTP requests), the service (that contains the majority of the business logic) and the repositories (that handle communication between the application and the database). Additionally, the service can interface with utility components and modules that offer various functionality (i.e., file access, algorithm calculation). The following data flow diagram illustrates this architecture.

Simple data flow diagram of modern web applications

By examining the origin of exceptions, we can see that the Calculation Engine, Repository, and File Access Utility can (potentially) reveal some details about the system, should an exception be thrown when interfacing with the different datastores (i.e., information about the SQL database, knowledge base schema, etc.).

The questions then becomes, where should developers handle these exceptions, and reduce the risk to both information disclosure and denial of service?

An approach that seems suitable for me is to handle exceptions as they arise and wrap them into application-specific exceptions. The parts of the application that have data flows that cross a trust boundary (e.g., to the file system, the Internet) should sanitize all exceptions by wrapping them into "more friendly" custom exceptions (created by the developers) to stop any risk from information disclosure being propagated further, as well as to localize any component failure. The internal components should then know how to handle application exceptions more suitably.

The main drawback of this approach is that the exception handling mechanism is more complex, as it requires the introduction of application-specific exceptions for each category of native (and applicable) exceptions.

Does this approach have any other pros and cons, and is there an alternative design that handles the balance between security and workload better?


Voting to close this as it is not a question about security. It is a question about software engineering and architecture:

The best place to handle the exception is as close as possible to where the exception occurs - the separation of functionality is all about abstraction - the remote higher levels are separate because they don't know about what is going on in the lower layers hence they cannot provide meaningful messages about the event not handle an automated response. Having said that, it is essential to track the (potentially distributed) transaction in order to

  • accurately log the connection between cause and effect
  • resolve data issues

And that means the entry point has a very specific role to play in case exceptions occur; it needs to tag the transaction with a unique identifier propagated with the sub component messages.


You mention

where should developers handle these exceptions, and reduce the risk to both information disclosure and denial of service?

The exceptions of your services or programs should be handler by the program/service it self as general rule. If the service don't handle the generated exceptions then that could be a security issue depending on the fault.

The correct approach will be to verify the correct use of the API, for example if your service use the function HTTPPost that can raise ConnectionError or BadURI, is responsibility of the program to handle properly to avoid unknown paths on the execution of it.

I give you a good practique for software that runs on backends as example, normally the service have a method run that handle the HTTP request, SMTP or whatever and this method is always on a try block and catching all the exceptions. Once you have this in place you can start go in depth to your code and make more specify exception block and verify that your system is stable, hope this helps you a bit.

Not the answer you're looking for? Browse other questions tagged or ask your own question.