Part 9 · Security for System Designers
OWASP Top 10 for Backend Developers
Most breaches don't need a genius hacker — just a missing ownership check, a string-glued SQL query or a default password. The OWASP Top 10 explained for backend developers, with the attack, the fix and a real incident for each, plus the API-specific risks.
On this page
The Problem
A data breach is when attackers get data they should not have. When you read about a big one, it is rarely a "genius hacker breaks unbreakable encryption" story. It is usually something like this:
- an API that returned any customer's record if you changed the ID in the URL,
- a login form where specially made input could run database commands,
- a server that was months behind on a security patch,
- a cloud server that was tricked into giving away its own access credentials (the keys it uses to log in to cloud services).
The same few mistakes appear again and again. The OWASP Top 10 is a list of the most serious and most common security risks in web applications. It is published by OWASP (the Open Worldwide Application Security Project), a non-profit community. For backend developers and system designers, it is the best checklist to start with.
The Core Idea
Think of the OWASP Top 10 as the most common ways houses get burgled:
- the back door was left unlocked (broken access control),
- a stranger was let in because they said "I am from the gas company" (injection: trusting what people send you),
- the lock was an old model with a known weakness (vulnerable components: old libraries with known bugs),
- the spare key was under the doormat (misconfiguration: unsafe settings),
- the alarm wasn't connected, so nobody noticed for weeks (logging and monitoring failures).
Burglars do not pick the hardest house. They check the common weak spots. Fix those first, and most attacks fail.
How It Works
The list below follows the OWASP Top 10 (2021 edition), which is still widely used in training and audits. OWASP also published a newer 2025 edition that reorganises some categories. For example, software supply chain problems (attacks through the code and tools you depend on) get their own category. Another new category covers the mishandling of errors and unusual situations. The ideas below still apply. But check the official OWASP site for the current list and numbering before you publish or audit against it.
A01: Broken Access Control
What it is: access control means rules about who may do what. It is "broken" when users can do or see things they should not:
- reading other users' data by changing an ID (IDOR, post 49: the server does not check who owns the record),
- calling admin endpoints as a normal user,
- modifying a price or
rolefield in a request, - accessing another tenant's data in a SaaS app. (A tenant is one customer account. SaaS means software that customers use online, like a subscription app.)
It's the #1 risk in the 2021 list.
GET /api/accounts/1002/statement ← logged in as account 1001… and it works 😱PATCH /api/users/1001 {"role": "admin"} ← the server blindly saves "role" (mass assignment)Fixes:
- Check permission on every request, for every object, on the server. Never trust the client (the browser or app), because users can change what it sends.
- Deny by default. Access is refused unless a rule clearly allows it.
- Limit queries to the current user or tenant (
WHERE tenant_id = ?). Also consider row-level security, where the database itself hides rows a user may not see. - Allow-list the fields users can update. An allow-list is a list of what is permitted, and everything else is refused. This avoids "mass assignment", where a request sets fields it should not, like
role,priceoris_verified. - Use IDs that are hard to guess (like random UUIDs) as an extra layer, but never as the only protection.
- Test access control with automated tests ("user A cannot read user B's order").
A02: Cryptographic Failures
What it is: sensitive data isn't properly protected:
- sent over plain HTTP (not encrypted),
- stored unencrypted,
- passwords hashed with MD5 or SHA-1,
- weak or hard-coded keys,
- old TLS versions (post 51).
Fixes:
- HTTPS everywhere, with HSTS (a header that tells browsers to always use HTTPS for your site), and TLS between internal services.
- Encrypt sensitive data at rest, with field-level encryption or tokenisation for the most sensitive data.
- Argon2id, bcrypt or scrypt for passwords (post 49).
- Keys in a KMS or secrets manager, and rotated (post 51).
- Don't store what you don't need. Data you never collect can't leak.
A03: Injection
What it is: the app treats input that it should not trust as code or commands. This can be SQL, NoSQL, operating-system commands, LDAP (a directory lookup language) or templates. The 2021 edition also puts cross-site scripting (XSS) here. XSS means an attacker makes their own JavaScript run on your web page.
SQL injection example:
// ❌ Vulnerable: input is glued into the SQL stringconst q = `SELECT * FROM users WHERE email = '${req.body.email}'`;// input: ' OR '1'='1 → query becomes: ... WHERE email = '' OR '1'='1' → returns every user- −Input is glued into the query text
- −' OR '1'='1 turns the WHERE into “always true”
- −Returns every user — or worse, runs DROP TABLE
- +The query and the data travel separately
- +Input is always treated as data, never as SQL
- +The same principle applies to OS commands, LDAP, NoSQL and templates
Fixes:
- Parameterised queries and prepared statements, always. This means the SQL text and the user's values are sent to the database separately. ORMs (libraries that let you use the database through code objects) do this by default, but be careful with their "raw query" features.
- Never build shell commands from user input. Use safe library functions, or strict allow-lists.
- Validate input (check its type, length, format and allowed values). Also encode output for the place where it is shown (HTML, URL, JavaScript) to prevent XSS. Encoding turns special characters like
<into harmless text. Modern frameworks (React, Angular, template engines) do this by default, so be careful with their "raw HTML" features. - Least-privilege database accounts: give the app's database user only the permissions it needs. It should not be able to
DROP(delete) tables.
A04: Insecure Design
What it is: the design itself is unsafe, even if the code is perfect. For example:
- a password reset that relies on easily guessed "security questions",
- no limits on how many coupons one account can redeem,
- a checkout that trusts the price sent from the browser,
- no rate limit on OTP attempts (an OTP is a one-time password; a rate limit caps how many tries are allowed).
Fixes:
- Threat modelling during design: before you build a feature, ask "how could someone abuse this?"
- Secure design patterns: work out prices on the server, use rate limits (post 43), use idempotency (post 34: repeating a request does not repeat its effect), and ask for an extra login check (step-up authentication) for sensitive actions.
- Abuse-case tests (tests that act like an attacker) next to the normal tests.
A05: Security Misconfiguration
What it is: insecure settings:
- default passwords left unchanged,
- public storage buckets,
- debug mode or detailed stack traces in production,
- open network ports you do not need, and admin panels open to the whole internet,
- CORS settings that are too open (CORS is the browser rule about which websites may call your API;
Access-Control-Allow-Origin: *lets any site), - missing security headers (HTTP headers that tell the browser to apply safety rules).
Fixes:
- Safe, repeatable settings through infrastructure as code (you describe your servers and cloud setup in files). Review these files like application code.
- Disable debug mode, directory listings and default accounts in production.
- Private by default: storage buckets, databases and admin tools are not public (post 17).
- Security headers:
Content-Security-Policy(limits which scripts the page may run),Strict-Transport-Security,X-Content-Type-Options: nosniff, andframe-ancestors(orX-Frame-Options). - Automatic scanning of settings (cloud security tools and Kubernetes policy tools).
A06: Vulnerable and Outdated Components
What it is: using libraries, frameworks, operating systems or containers that have known vulnerabilities. A vulnerability is a weakness that attackers can use. Modern apps contain hundreds of dependencies (libraries they rely on), and one bad one is enough.
Fixes:
- Know what you run: keep a software bill of materials (SBOM). This is a list of every component inside your software, like an ingredients list.
- Automatic dependency scanning (Dependabot, Renovate, Snyk, OSV-Scanner) and container image scanning. These tools compare your libraries with lists of known weaknesses.
- Patch quickly. A patch is an update that fixes a weakness. Be fastest for serious weaknesses that attackers are already using. Have a process to release urgent patches within hours or days.
- Remove unused dependencies, and prefer well-maintained ones.
A07: Identification and Authentication Failures
What it is: weak login and session handling (a session is how the server remembers you after login):
- allowing weak or breached passwords,
- no protection against credential stuffing (attackers trying leaked username/password pairs from other sites),
- no MFA,
- session IDs in URLs,
- sessions that never expire,
- predictable reset tokens.
Fixes (post 49):
- MFA and passkeys; breached-password checks.
- Rate limiting and bot detection on login, OTP and password reset endpoints (post 43).
- Secure session cookies (
HttpOnly,Secure,SameSite), session expiry, and new session IDs after login. - Password-reset tokens that are random, short-lived and usable once.
- Use a proven identity provider or library instead of building auth from scratch.
A08: Software and Data Integrity Failures
What it is: trusting code or data without checking it:
- installing unverified updates or plugins,
- insecure CI/CD pipelines,
- deserialising untrusted data into objects (turning received bytes back into program objects; in some languages this lets an attacker run code on your server, called remote code execution),
- webhooks accepted without checking signatures.
This includes supply-chain attacks, where attackers compromise a dependency or build system to reach many victims at once.
Fixes:
- Check signatures on build outputs (artefacts) and updates, and sign your own builds (for example with Sigstore, a free signing service). Follow frameworks like SLSA, a set of rules for keeping the build process trustworthy.
- Lock dependency versions with lockfiles (files that record the exact versions you use). Use trusted registries (the public stores of packages), and review new dependencies.
- Protect CI/CD (the automatic build and release pipeline): use tokens with few permissions, protected branches, required code reviews, and OIDC instead of long-lived cloud keys (post 51).
- Avoid unsafe deserialisation. Use simple data formats (like JSON) and check them against a schema (a description of the allowed shape).
- Verify webhook signatures (post 34). A webhook is a call that another service sends to your server. A signature made with HMAC (a keyed hash, post 51) proves it is genuine.
A09: Security Logging and Monitoring Failures
What it is: attacks happen and nobody notices, or there are no logs to study afterwards. Breaches often stay hidden for months.
Fixes (posts 46–48):
- Log security events: logins (success and failure), password and MFA changes, permission changes, access denials, admin actions and high-value transactions.
- Collect logs in one place, protect them from changes, and keep them long enough to investigate.
- Alert on suspicious patterns: spikes in failed logins, access from unusual locations, mass data exports.
- Never log secrets or sensitive data (post 51).
- Have an incident response plan (a plan for what to do during an attack) and practise it (post 48).
A10: Server-Side Request Forgery (SSRF)
What it is: the attacker makes your server send requests to places it should not. For example, an attacker abuses a "fetch image from URL" feature to reach internal services or the cloud metadata endpoint. The metadata endpoint is a special address (169.254.169.254) inside a cloud server that tells the server about itself. It can return temporary cloud credentials.
- POST /preview-link {url:
http://169.254.169.254/…/credentials} - GET — from inside your network
- temporary IAM credentials
- “link preview” containing the keys 😱
- Fix — allow-list destinations, block private and metadata IPs, require IMDSv2, and give the server minimal IAM rights
Fixes:
- Allow-list the destinations your server may fetch (domains and schemes).
- Block private and internal IP ranges, including
169.254.169.254, localhost and internal subnets, after DNS resolution. Also re-check after redirects. - Use IMDSv2 on AWS. This is the newer version of the metadata service, and it needs a session token, so a simple forged request does not work. Use the matching protections on other clouds.
- Run features that fetch URLs in an isolated network or service that cannot reach internal systems.
- Give servers cloud roles with the fewest permissions, so stolen credentials can do very little.
Beyond the Top 10: APIs
OWASP also publishes an API Security Top 10. It matters a lot for backend and mobile systems. Its top risks include:
- broken object-level authorisation (IDOR),
- broken authentication,
- broken object property-level authorisation (exposing or allowing edits to fields users shouldn't touch),
- unrestricted resource consumption (no rate limits and no limits on page size, posts 34 and 43),
- broken function-level authorisation (normal users calling admin functions).
Building security into the process
- Design: threat modelling (asking "what could go wrong?") for new features and designs.
- Code: secure defaults, frameworks that escape output and parameterise queries, and code review.
- CI/CD: static analysis (SAST, a tool that reads your code to find weaknesses), dependency and secret scanning, container scanning, and checks of your infrastructure-as-code files.
- Testing: dynamic scanning (DAST, a tool that attacks your running app to find weaknesses), security unit tests, and penetration testing (hired experts try to break in) for important systems.
- Production: a WAF (web application firewall, which filters bad web requests) as an extra layer, not a replacement for fixing code. Also monitoring, and a bug bounty or responsible-disclosure programme (outsiders report weaknesses to you, and you may pay them).
- People: training (for example, the free PortSwigger Web Security Academy labs), clear owners for security, and blameless incident reviews.
Trade-offs
- Security controls add friction: MFA, reviews, scanning and patching take time. But fixing a breach costs far more, in money, trust and legal consequences.
- Automated scanners catch known issues cheaply, but they give false alarms (false positives) and miss flaws in business logic (like broken access control). You need both tools and human review.
- WAFs give quick protection against common attacks, but attackers can get around them and they can block real users. They are a safety net, not a fix.
- Fast patching reduces the time you are exposed, but it risks breaking things. Good tests and staged rollouts (releasing to a few users first, Part 10) make fast patching safe.
In the Real World
Equifax (2017). Attackers exploited a known vulnerability in the Apache Struts web framework, a flaw for which a patch had been available for about two months. Personal data of around 147 million people was exposed. It's the classic example of A06: Vulnerable and Outdated Components.
Capital One (2019). An attacker used an SSRF weakness, made possible by a wrongly configured web application firewall, to reach the cloud metadata service, obtain temporary credentials, and read data from storage buckets. Around 100 million customers in the US and Canada were affected. It's a textbook A10: SSRF case, and a big reason cloud providers pushed stronger metadata protections like IMDSv2.
MOVEit (2023). A SQL injection vulnerability in the MOVEit Transfer file-sharing software was exploited by a ransomware group to steal data from thousands of organisations worldwide, including governments, banks and airlines. It shows that injection is still a top threat decades after it was first understood.
Log4Shell (2021). A critical flaw in Log4j, a Java logging library used almost everywhere, let attackers run code on servers just by getting a specially made text string written to the log. Organisations worldwide rushed to find where Log4j was used. This is exactly why SBOMs and dependency inventories matter.
Supply-chain attacks: SolarWinds (2020) and the xz backdoor (2024). Attackers compromised SolarWinds' build system and shipped malicious updates to thousands of customers, including government agencies. In 2024, a backdoor (a hidden way in) was found in xz, a widely used compression library. A contributor had planted it over several years after gaining the maintainers' trust. It was caught by a Microsoft engineer, Andres Freund, who noticed SSH logins were slightly slower than expected. Both are A08: integrity failures that pushed the industry towards signed builds, SLSA and closer scrutiny of dependencies.
Optus (2022). Australian telecom Optus suffered a breach affecting millions of current and former customers. It was widely reported to involve an API endpoint that returned customer data without proper authentication, a painful example of broken access control in APIs.
Interview Questions
Q1What is the most common web vulnerability today, and how do you prevent it?
Broken access control — especially object-level authorization (IDOR) and mass assignment. Check ownership or permission for every object on every request, deny by default, allow-list which fields a client may set, and test authorization explicitly.
Q2How do you prevent SQL injection?
Use parameterised queries or prepared statements everywhere (an ORM does this if you don't bypass it), validate input types, and run the database user with least privilege. Never build SQL by concatenating strings.
Q3What is SSRF, and why is it dangerous in the cloud?
Server-side request forgery tricks your server into fetching an attacker-chosen URL from inside your network — for example the instance metadata endpoint, which can hand out credentials. Allow-list destinations, block private and link-local ranges, require IMDSv2 and minimise the server's IAM permissions.
Q4How do you protect against vulnerable dependencies?
Keep an SBOM, scan dependencies continuously (Dependabot, Snyk, osv), patch quickly, pin versions and verify integrity, remove unused packages, and watch for supply-chain attacks such as typosquatting and compromised maintainers.
Q5What are the classic XSS defences?
Context-aware output encoding (modern frameworks do this by default — avoid bypasses like dangerouslySetInnerHTML), sanitising any HTML you must render, a strict Content-Security-Policy, and HttpOnly cookies so a successful XSS can't steal sessions.
Q6How do you build security into the development process?
Threat-model new designs, use secure defaults and shared libraries, run SAST, DAST and dependency scanning in CI, do security-focused code review, keep security logging with alerts, and run regular penetration tests and bug bounties.
Key Takeaways
- The OWASP Top 10 lists the most common, critical web risks. Most breaches exploit these basic weaknesses, not exotic ones. (Check the latest edition. The 2025 update reorganises some categories.)
- Access control (A01) is the top risk: check every object on every request, deny by default, and allow-list updatable fields.
- Injection is prevented with parameterised queries, input validation and output encoding. SSRF is prevented with allow-lists, blocked internal IPs and IMDSv2.
- Keep components patched (SBOMs, scanners), secure the supply chain and CI/CD (signing, lockfiles, OIDC), and avoid misconfigurations with infrastructure as code and private-by-default settings.
- Log and monitor security events, practise incident response, and build security into design, code review, CI/CD and testing, not just a final audit.
Further Reading
- The official OWASP Top 10 (the 2021 edition, and the newer 2025 edition)
- The OWASP API Security Top 10
- The OWASP Cheat Sheet Series (SQL Injection Prevention, SSRF Prevention, Input Validation, and Cross-Site Scripting Prevention cheat sheets)
- The OWASP Application Security Verification Standard (ASVS)
- The PortSwigger Web Security Academy (free, hands-on labs for each vulnerability type)
- The SLSA framework and the OSV vulnerability database
This wraps up Part 9. Next up, Part 10: Architecture & Deployment, starting with "Monolith vs Microservices: An Honest Comparison".
Published by Jainik · Last updated · How these lessons are made
Keep learning
Related series