~/learn / how-apps-are-built

How Applications Are Built

The architecture patterns behind modern web applications, the request lifecycle every framework shares, and how knowing the structure tells you exactly where security checks live and where they get missed.

intermediateupdated

You can test an application as a black box, but you will find far more if you can picture how it is built. Most web applications follow a handful of well-known patterns, and once you recognize them you can predict where input is validated, where authorization is checked, and which corners developers habitually forget. This is the practical payoff of studying how code is structured: not memorizing a catalog of design patterns, but understanding the assumptions each layer bakes in, because an assumption is where a bug hides.

The request lifecycle

In nearly every framework a request flows through the same stages, and each stage is a place a check can be present, absent, or inconsistent:

  1. Web server or load balancer terminates TLS, applies limits, and forwards the request.
  2. Middleware runs for every request: logging, sessions, CSRF, CORS, authentication.
  3. Router matches the method and path to a handler.
  4. Controller or handler parses parameters, checks authorization, and calls business logic.
  5. Models or services apply rules and reach the database through an ORM.
  6. View or serializer turns data into HTML or JSON.

The single most useful mental model in application security is that authentication is centralized (one place, stage 2) while authorization is distributed (every controller and every object, stages 4 and 5). That asymmetry is why access control is the number one bug class: you cannot forget to authenticate, because it is one gate everyone passes, but you can forget one of a hundred ownership checks. See MVC, routing, and middleware.

Why this helps you find bugs

  • If authorization lives in each controller action, look for the one action that forgot it.
  • If the router exposes every public method automatically, look for methods never meant to be routes.
  • If the ORM binds request parameters straight onto models, look for fields that should never be user-settable. See ORMs and mass assignment.
  • If there is a separate API for the mobile app, look for checks the web frontend performs that the API does not. Two front doors rarely enforce identical rules.
  • If services call each other internally, look for the service that assumes every caller is already trusted and authorized. See services and trust boundaries.

Every one of these is “find the place that deviates from the framework’s safe default,” which is why knowing the defaults is the whole skill.

Recognizing the stack

Response headers, cookie names, error pages, file extensions, and URL shapes give frameworks away, and the framework tells you its defaults and its common mistakes. _session_id and /rails/ suggest Rails; csrftoken suggests Django; JSESSIONID a Java servlet container; laravel_session Laravel; ASP.NET_SessionId ASP.NET; connect.sid an Express app. Stack traces, X-Powered-By, and the exact 404 page narrow it further. The header analyzer and the fingerprinting commands in the cheatsheet help.

Knowing the framework hands you its defaults for free, and the most interesting bugs are almost always where a developer stepped outside those defaults, because that is where they had to get the security right by hand.

Go deeper