Overview

9 Handling failures securely

Failures and security are tightly coupled: systems tend to reveal internal details when they break, and the way failures are handled often determines how secure a system really is. The chapter explains why design choices around error signaling and handling have security implications, showing how stack traces, exception messages, and cascading failures can leak sensitive information or destabilize a system. It sets the stage from low-level code constructs to high-level architecture, emphasizing that secure software must be designed with failure as an expected condition, not an afterthought.

A key theme is to separate business and technical failures. Intermixing them (for example, by throwing the same generic exception type for both) leads to fragile code, confusing control flow, and accidental data leaks. The authors recommend explicit domain-specific exception types for business outcomes, a catch-all “safety net” for business exceptions, and a global handler to convert technical failures into safe, user-friendly responses. Just as important: never stuff business data into technical exceptions, and model sensitive data so it can’t be casually logged or serialized (for example, via a read-once pattern). An alternative approach avoids domain exceptions altogether by representing failures as expected results (such as a Result type), which reduces ambiguity, limits payload leakage, and reserves exceptions for true bugs or invariant violations.

Availability is treated as a security goal in its own right. The chapter links resilience and responsiveness to security by introducing fail-fast mechanisms (circuit breakers with timeouts), asynchronous buffering (queues) and backpressure, and fault isolation via bulkheads at location, infrastructure, and code levels (for example, thread pools and separate resource partitions). It stresses that fallback behavior is a business decision that must be modeled in the domain. Finally, it addresses bad data handling: don’t “repair” inputs before validation (filters can create dangerous derivatives), and never echo user input verbatim in errors or logs to avoid XSS and second-order attacks. The overarching message is to design for failure—at both code and system levels—to prevent data exposure, contain faults, and keep systems secure and available.

Three reasons for throwing exceptions in an application: business rule violations, technical errors, and framework failures
ch09 reasons for throwing exceptions small
The possible outcomes of a money transfer between bank accounts
ch09 money transfer flow chart small
The three states of a circuit breaker
ch09 circuit breaker small
A ship hull constructed with bulkheads.
ch09 bulkheads ship hull small
Protecting business functionality by partitioning workload
ch09 partitioned servers small
Bad characters filtered out for all data sources.
ch09 repair filter small
Relationship between repairing data and validation
ch09 repair validation exception small

 Summary

  • Separating business exceptions and technical exceptions is a good design strategy because technical details don’t belong in the domain.
  • You shouldn’t intermix technical and business exceptions using the same type.
  • It’s a good design practice to never include business data in technical exceptions, regardless of whether it’s sensitive or not.
  • You can create more secure code by designing for failures and treating failures as normal, unexceptional results.
  • Availability is an important security goal for software systems.
  • Resilience and responsiveness are traits that add security by improving the availability of a system.
  • You can use design patterns like circuit breakers, bulkheads, and timeouts to design for availability.
  • Repairing data before validation is dangerous and should be avoided at all costs.
  • You should never echo input verbatim.

FAQ

Why should I separate business exceptions from technical exceptions?Business exceptions express domain rules (for example, AccountNotFound), while technical exceptions signal infrastructure or platform failures (for example, database timeouts). Mixing them causes ambiguity, fragile handling (like checking message text), and data leakage. Create an explicit domain exception hierarchy (for example, AccountException → AccountNotFound) and handle business exceptions in the domain; let only technical exceptions reach a global handler.
How do stack traces and exception messages leak sensitive information, and how can I prevent it?Stack traces reveal implementation details (language, frameworks, storage) and sometimes internal paths. Messages often include business data. To prevent leaks: use a global exception handler; show generic error pages to users; log minimally and securely; avoid exposing stack traces to clients; and avoid embedding domain data in technical exception messages.
What is a safe way to handle exception payloads?Never include business data in technical exceptions. Prefer technical identifiers (for example, connection ID) over customer/account details. Model sensitive data explicitly and consider the read-once pattern to detect illegal reuse (for example, logging). Assume exceptions can cross context boundaries; keep payload strictly technical.
If I use exceptions, how can I signal a domain condition like “account not found” safely?Define explicit domain exceptions (for example, AccountNotFound extends AccountException) and throw them for domain outcomes. Catch specific domain exceptions locally and map them to domain-level results (for example, Balance.unknown). Catch the domain marker type (AccountException) as a safety net and translate unexpected domain errors to a generic technical failure.
What’s the alternative to using exceptions for expected failures?Model failures as return values, not exceptions. Use a Result type (success/failure with reason like INSUFFICIENT_FUNDS). Benefits: removes ambiguity between domain and technical failures, avoids accidental logging of payloads, and keeps handling in the right context. Exceptions then indicate bugs or invariant violations only.
How do circuit breakers and timeouts improve security and availability?Circuit breakers isolate failing dependencies by switching among closed, open (fail fast), and half-open (trial) states. They prevent cascading failures and keep the system responsive under stress. Always set timeouts on calls; an infinite wait leads to resource exhaustion and downtime. Together, breakers and timeouts increase resilience and thus security via availability.
What are bulkheads, and how can I apply them?Bulkheads partition resources to stop failures from spreading. Apply them at: location level (multiple regions), infrastructure level (separate server pools for browse vs checkout), and code level (thread pools and bounded queues per workload). Avoid hidden dependencies (shared DBs, queues, or hardware) that defeat isolation.
Why is responsiveness a security concern, and how do I design for it?Availability includes responding within acceptable time. Under load, prefer fast, clear errors (fail fast) to long timeouts. Use queues to decouple acceptance from processing, apply backpressure, and reject or defer when capacity is exceeded. Responsive systems are harder to take down via load-based attacks.
Why is “repairing” data before validation dangerous?Pre-validation “repair” mutates input and can create harmful derivatives while giving a false sense of safety. For example, stripping “<” and “>” may still leave encoded scripts that execute later. Validate against strict contracts per context, and fix data at the source or handle transformation explicitly with clear semantics.
Why should I never echo input verbatim in errors or logs, and what should I do instead?Echoing input enables XSS and second-order attacks (malicious inputs executed in admin tools or logs). Instead: avoid verbatim echo; if you must show data, contextually encode/escape it; centralize and sanitize error reporting; treat logs as sensitive, minimize payload, and restrict access.

pro $24.99 per month

  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose one free eBook per month to keep
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime

lite $19.99 per month

  • access to all Manning books, including MEAPs!

team

5, 10 or 20 seats+ for your team - learn more


choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • Secure by Design ebook for free
choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • Secure by Design ebook for free
choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • Secure by Design ebook for free