Start with assumptions and controls
Security failures start when a backend trusts a fact that a request does not prove. Treat values from browsers, clients, jobs, and dependencies as untrusted until code validates them at the point of use.
For each request, name the assumptions about input shape, identity, origin, ownership, and dependency behavior. Then layer controls around them: validate input, keep data separate from commands, authenticate the caller, authorize each object and function, apply browser and transport policies, use least-privilege credentials, and record sensitive actions.
The rest of this guide focuses on the backend. It shows where these controls apply when data crosses into a database, an operating system, a browser, or another service.
Scope: four contexts
Trace each request through the contexts it crosses:
- Browser
HTML, JavaScript, and cookies run in the client context.
- Network
HTTP traffic and transport encryption have their own controls.
- Server OS
Processes, shells, and operating-system permissions form another context.
- Backend application
Application code enforces its own input and access policies. This chapter focuses here.
Browser, network, operating system, and application are distinct security contexts.
How to read this model
A four-compartment enclosure with separate controls. The object is a teaching analogy. Inspecting a part highlights its role; it does not execute or simulate the software. Cabinet trays are records, workpieces are data, and latches are checks. Unless an explanation states a quantity, compartments and sample workpieces do not denote data counts. Part dimensions are not a quantitative scale.
The rest of these notes focus on the backend (green). The OS, network, and browser are separate contexts.
The core question
Attackers do not care about your framework, library, or language. They ask one question:
Every vulnerability in these notes comes down to that. The developer assumed:
- the input from the user was clean
- the user was who they said they were
- the request came from their own front end
- no one would open the network tab and modify parameters
These assumptions feel reasonable under a deadline. But attackers don't use the app the way you expect. They poke at every boundary, modify every input, and guess every assumption.
The mental model: data crossing boundaries
Your backend speaks multiple languages at once:
- Database
SQL syntax and values must be kept separate.
- Browser
HTML, CSS, and JavaScript each require context-appropriate output handling.
- Operating system
Avoid shell interpretation of untrusted input; prefer argument-based process APIs.
Treat data according to the destination interpreter, not as an interchangeable string.
How to read this model
An output selector with SQL, document, and shell receptacles. The object is a teaching analogy. Inspecting a part highlights its role; it does not execute or simulate the software. Cabinet trays are records, workpieces are data, and latches are checks. Unless an explanation states a quantity, compartments and sample workpieces do not denote data counts. Part dimensions are not a quantitative scale.
Each language has its own grammar, its own special characters, and its own way to separate commands from data.
- User input
Treat external input as untrusted data.
- Interpreter boundary
SQL, shell, and HTML/JavaScript have different syntax rules.
- Control
Use parameterization, safe APIs, and context-appropriate encoding to preserve the data/code distinction.
Injection occurs when an interpreter receives attacker-controlled text as code.
How to read this model
An input holder separated from a program control die. The object is a teaching analogy. Inspecting a part highlights its role; it does not execute or simulate the software. Cabinet trays are records, workpieces are data, and latches are checks. Unless an explanation states a quantity, compartments and sample workpieces do not denote data counts. Part dimensions are not a quantitative scale.
Most vulnerabilities appear exactly here: a user speaking one language crosses into another language, and their "data" becomes a command.
Defense in depth
No single defense is perfect. Layer them so an attacker must break all of them at once:
- Validate
Validate fields and parse expected types at input boundaries.
- Parameterize
Keep data separate from executable statements and commands.
- Authorize
Check permission at the actual point of access.
- Constrain and observe
Apply appropriate headers, browser policies, cookie flags, logging, monitoring, and audit trails.
One check cannot replace all the other security controls.
How to read this model
A guarded fixture with independent inspection latches. The object is a teaching analogy. Inspecting a part highlights its role; it does not execute or simulate the software. Cabinet trays are records, workpieces are data, and latches are checks. Unless an explanation states a quantity, compartments and sample workpieces do not denote data counts. Part dimensions are not a quantitative scale.
Ask these three questions on every line, and you avoid most backend vulnerabilities.
Resources
- PortSwigger Academy: free, hands-on labs for most web vulnerabilities.
- OWASP Top 10: the current list of top web risks.
- OWASP Cheat Sheet Series: best-practice sheets per topic.
Map of the deep dive
| Note | Covers |
|---|---|
| injection attacks | SQL, NoSQL, command injection |
| authentication | passwords, sessions, JWT, rate limiting |
| authorization | BOLA, BFLA, horizontal/vertical attacks |
| xss and csrf | stored/reflected XSS, CSP, CSRF |
| misconfiguration | secrets, log levels, security headers |