Web Attacks — OWASP Essentials
Injection, XSS, CSRF, SSRF — how the classic attacks work and the one correct defense for each.
SQL Injection — Data Becomes Code
Every injection attack is the same root bug: untrusted input concatenated into something executable. Classic SQLi: a login form value of ' OR 1=1 -- turns your query’s WHERE clause into a tautology.
# VULNERABLE — string concatenation builds the query cur.execute("SELECT * FROM users WHERE name = '" + name + "'") # SAFE — parameterized: input is data, never SQL cur.execute("SELECT * FROM users WHERE name = %s", (name,))
XSS — Injecting Into the Browser
Cross-site scripting is injection where the interpreter is the victim’s browser: attacker-controlled text ends up in a page as live HTML/JS, running with the session of whoever views it — stealing tokens, performing actions, rewriting the page.
| Type | Where the payload lives | Example |
|---|---|---|
| Stored | Saved server-side — hits every viewer | Malicious script in a comment field |
| Reflected | Echoed from the request | Search term rendered unescaped in results |
| DOM-based | Never touches the server | JS writes location.hash into innerHTML |
Defenses stack: contextual output encoding (escape for HTML, attribute, JS, URL contexts — frameworks like React do this by default until you use dangerouslySetInnerHTML), a Content-Security-Policy restricting where scripts may load from, and httpOnly cookies so stolen DOM access doesn’t equal stolen session.
CSRF — the Browser Betrays You
Cross-site request forgery: an evil page makes your logged-in browser send a state-changing request to a site where you have a session — the browser helpfully attaches cookies, so the request looks authentic. Classic: a hidden form auto-submitting POST /transfer to your bank.
SameSite=Laxcookies — not sent on cross-site POSTs- CSRF tokens: per-session secret the evil page can’t read
- Re-auth / step-up for sensitive actions
- Cookies attach automatically to any request to their domain
- GET/POST from any origin is allowed by the web platform
- User is logged in somewhere ≈ always
SSRF, IDOR & the Top-10 Map
SSRF: the attacker makes your server issue requests — “fetch this URL for me” endpoints tricked into hitting http://169.254.169.254/ (cloud metadata, credentials) or internal admin services. Defend with allowlists of destinations and blocking link-local/private ranges. IDOR: direct object references (/invoice/18) without per-object authorization — the most common real-world authz bug; fix by checking ownership server-side on every access.
| OWASP theme | Representative bug | Core defense |
|---|---|---|
| Broken access control | IDOR, missing function-level checks | Server-side authz on every object |
| Injection | SQLi, command injection, XSS | Parameterize; encode output; allowlist |
| Cryptographic failures | Plain HTTP, MD5 passwords | TLS everywhere; argon2/bcrypt |
| Misconfiguration | Default creds, open buckets, debug on | Hardened baselines; config scanning |
| Vulnerable components | Known-CVE dependencies | Inventory + patch cadence + audit tooling |
| SSRF | Metadata-endpoint theft | Destination allowlists; egress filtering |
Interview Questions
What single principle underlies SQLi, XSS and command injection?
Untrusted data crossing into an interpreter as code. The universal fix is keeping data and code structurally separate: parameterized queries, contextual output encoding, and never building shell commands from input.
XSS vs CSRF.
XSS injects script that runs in the victim’s page — full session access, can read responses. CSRF tricks the victim’s browser into sending a request using auto-attached cookies — blind, but state-changing. Different defenses: encoding/CSP vs SameSite/tokens.
Why is SSRF suddenly a big deal in cloud environments?
Because the juiciest internal endpoint became universal: the cloud metadata service (169.254.169.254) hands out instance credentials. One “fetch a URL” feature plus SSRF equals stolen cloud keys — the Capital One breach pattern.
How do you actually prevent IDOR?
Authorization checks at the data layer, tied to the authenticated principal: every query for object X includes “and X belongs to (or is readable by) this user”. Unguessable IDs (UUIDs) reduce discovery but are not authorization.