Web Applications & APIs
Real-world web apps are multi-tier, API-driven, and OAuth-enabled. This module covers the threat landscape for modern web architecture โ REST APIs, OAuth 2.0 flows, frontend injection, and microservices.
๐ฏ Learning Objectives
- Threat model a multi-tier web application with a separate API layer
- Identify threats specific to OAuth 2.0 and token-based auth flows
- Map OWASP Top 10 to STRIDE categories
- Enumerate API-specific threats: broken object-level auth, mass assignment, rate limiting
- Understand cross-site attacks: XSS, CSRF, CORS misconfigurations
1Multi-Tier Web Architecture
Modern web apps separate concerns into distinct tiers. Each tier boundary is a new trust boundary โ and a new attack surface.
2OWASP Top 10 Mapped to STRIDE
The OWASP Top 10 is the industry's most-referenced list of critical web application risks. Here's how it maps to STRIDE โ connecting what OWASP names to what STRIDE categorizes:
| OWASP Top 10 (2021) | STRIDE | Core Risk | Example |
|---|---|---|---|
| A01: Broken Access Control | E ยท I | IDOR, privilege escalation, path traversal | User accesses admin panel without admin role |
| A02: Cryptographic Failures | I | Weak encryption, plaintext secrets, TLS downgrade | Passwords stored as MD5 hashes |
| A03: Injection | T ยท I ยท E | SQL, NoSQL, OS command, LDAP injection | SQL injection via unsanitized search field |
| A04: Insecure Design | S ยท T ยท E | Missing threat models, design-level flaws | Password reset doesn't verify email ownership |
| A05: Security Misconfiguration | I ยท D | Default creds, open S3 buckets, verbose errors | Debug mode on in production |
| A06: Vulnerable Components | T ยท I ยท E | Outdated libraries with known CVEs | Log4Shell in an old Log4j version |
| A07: Auth Failures | S ยท E | Weak passwords, session fixation, no MFA | Session token not invalidated after logout |
| A08: Software/Data Integrity | T | CI/CD pipeline attacks, insecure deserialization | Malicious npm package in build pipeline |
| A09: Logging Failures | R | No audit trail, sensitive data in logs | Failed logins not logged โ breach goes undetected |
| A10: SSRF | I ยท E | Server makes requests to internal resources | Image URL parameter fetches AWS metadata endpoint |
3OAuth 2.0 Threat Model
OAuth 2.0 is everywhere โ "Login with Google/GitHub/Facebook." But its flows introduce complex trust relationships and several well-known attack vectors. Let's model them.
| ID | OAuth Threat | STRIDE | Mitigation |
|---|---|---|---|
| T-01 | Missing 'state' parameter โ CSRF allows attacker to trick user into linking their account with the attacker's identity | S | Always generate cryptographically random state; validate on callback |
| T-02 | Authorization code interception โ code stolen from redirect URI, exchanged for tokens | S ยท T | Use PKCE (Proof Key for Code Exchange) โ mandatory for public clients (SPAs, mobile) |
| T-03 | Client secret in SPA/mobile โ decompilable, visible in source | I | Use PKCE instead of client_secret for public clients. Secrets are server-side only. |
| T-04 | Access token in URL fragment / query string โ logged in browser history, server logs, Referer headers | I | Never pass tokens in URLs. Use Authorization Code flow (back-channel token exchange) not Implicit flow. |
| T-05 | Open redirect on redirect_uri โ redirect_uri not strictly validated, tokens sent to attacker's server | S ยท I | Register exact redirect URIs, no wildcards. Validate against allowlist server-side. |
4Cross-Site Attacks: XSS & CSRF
Cross-Site Scripting (XSS)
STRIDE: Information Disclosure + Spoofing + Elevation of Privilege
XSS injects malicious JavaScript into a page viewed by other users. Three types:
- Output encoding โ encode all user data before rendering in HTML (
<not<) - Content Security Policy (CSP) โ restrict which scripts can execute
- Use frameworks correctly โ React's JSX auto-encodes; avoid
dangerouslySetInnerHTML - HttpOnly cookies โ prevents JS from stealing session tokens even if XSS succeeds
Cross-Site Request Forgery (CSRF)
STRIDE: Spoofing + Tampering
CSRF tricks a logged-in user's browser into making unintended requests to a site where they're authenticated โ without the user knowing.
bank.com. They visit evil.com, which has a hidden form:<form action="https://bank.com/transfer" method="POST">
<input name="amount" value="10000">
<input name="to" value="attacker-account">
</form>The form auto-submits. The browser sends the user's session cookie automatically. The bank sees a valid authenticated request and processes the transfer.
- CSRF tokens โ random value in forms, validated server-side
- SameSite cookie attribute โ
SameSite=StrictorLaxprevents cross-site cookie sending - Custom request headers โ REST APIs check for
X-Requested-Withor custom header (browsers don't send these cross-origin without CORS preflight) - Double Submit Cookie โ compare cookie value to request parameter
CORS Misconfiguration
STRIDE: Information Disclosure + Elevation of Privilege
CORS controls which origins can make cross-site API requests. A misconfigured CORS policy can undo all your other auth protections.
| Misconfiguration | Impact | Fix |
|---|---|---|
Access-Control-Allow-Origin: * with credentials |
Any site can read API responses with user's cookies | Never combine * with allow-credentials: true |
Reflecting Origin header without validation |
Any attacker origin is trusted | Validate against strict allowlist of origins |
null origin trusted |
Sandboxed iframes and file:// URIs can access API | Never trust Origin: null |
5API-Specific Threats (OWASP API Top 10)
APIs have their own unique threat landscape beyond the classic web app. The OWASP API Security Top 10 covers these. Here are the most critical:
GET /api/invoices/4521 returns any invoice, not just the caller's. Most common and impactful API vulnerability.{"name": "Alice", "isAdmin": true}. If the API doesn't filter which fields can be set by clients, the user promotes themselves to admin.// โ Mass assignment vulnerability
const user = await User.update(req.params.id, req.body); // All fields!
// โ
Allowlist specific fields
const { name, email, bio } = req.body; // Only permitted fields
const user = await User.update(req.params.id, { name, email, bio });
http://169.254.169.254/latest/meta-data/ โ the AWS metadata endpoint โ to steal IAM credentials and compromise the entire cloud account.6Microservices Architecture Threats
When an app splits into microservices, the internal network becomes a new attack surface โ one that often has far more trust than it should.
Key Microservices Threats
| Threat | STRIDE | Mitigation |
|---|---|---|
| Service impersonation โ malicious service claims to be a trusted internal service | S | Mutual TLS (mTLS) for all service-to-service calls; service mesh (Istio/Linkerd) |
| Lateral movement โ compromised service attacks all others on flat internal network | E | Network segmentation; principle of least privilege per service; service-level authorization |
| Secrets sprawl โ each service hardcodes DB creds, API keys | I | Centralized secrets management (Vault, AWS Secrets Manager); service identities (not shared secrets) |
| Event queue poisoning โ injecting malicious messages into Kafka/RabbitMQ | T | Message signing, input validation on consumer side; queue access controls |
7Knowledge Check
User.update(id, req.body) without filtering fields. A user sends {"name": "Bob", "isAdmin": true, "creditBalance": 99999}. What vulnerability is this?8Module Summary
- Each architectural tier has its own threat profile โ model them separately
- OWASP Top 10 maps directly to STRIDE โ know both lists and their relationship
- OAuth 2.0: use Auth Code + PKCE for public clients; validate state; allowlist redirect URIs
- XSS: output encoding + CSP; CSRF: SameSite cookies + CSRF tokens
- API threats: BOLA/IDOR, mass assignment, SSRF โ validate authorization on every request
- Microservices: don't trust internal network by default; use mTLS and least privilege per service