The Threat Landscape: OWASP API Security Top 10 (2023)
Securing REST APIs requires addressing the specific attack vectors detailed in the OWASP API Security Top 10:
OWASP API Security Top 10 (2023) Vulnerability & Defense Matrix
| OWASP API Ranking | Vulnerability Class | Core Failure Mechanism | Engineering Defensive Architecture | Verification & Detection Tool |
|---|---|---|---|---|
| API1:2023 | Broken Object Level Authorization (BOLA) | Endpoints accept object IDs without verifying ownership | Database queries scoped explicitly by authenticated tenant ID | Wescequre API Scanner parameter fuzzer |
| API2:2023 | Broken Authentication | Weak JWT validation, missing rotation, token leaks | Asymmetric RS256/EdDSA JWTs, short expiry (15m), Redis revocation | Auth token inspection suite |
| API3:2023 | Broken Object Property Level Authorization (BOPLA) | Mass assignment binds internal fields (role, is_admin) | Strict Zod DTO allowlists; explicit response serialization DTOs | Input fuzzing & parameter audit |
| API4:2023 | Unrestricted Resource Consumption | Missing rate limits, unbounded page sizes, slow regexes | Redis sliding-window rate limiting, max page limits (max 100) | Endpoint load & stress tests |
| API5:2023 | Broken Function Level Authorization (BFLA) | Exposing administrative routes to standard user roles | Declarative RBAC middleware enforced on 100% of routes | Role-switch permission audits |
| API6:2023 | Unrestricted Access to Sensitive Business Flows | Automated bot purchasing, scraping, bulk SMS triggers | Device fingerprinting, CAPTCHA gating, business logic limits | Bot mitigation & rate audits |
| API7:2023 | Server-Side Request Forgery (SSRF) | Server fetches remote URLs provided by untrusted input | Network egress filtering, metadata IP blocking (169.254.169.254) | Cloud metadata probe checks |
| API8:2023 | Security Misconfiguration | Verbose stack traces, unhardened CORS, default credentials | Production error redaction, strict CORS origins, security headers | Security header audits |
| API9:2023 | Improper Inventory Management | Deprecated v1 endpoints, undocumented shadow APIs | Automated OpenAPI spec generation from code, decommission checks | Discovery crawlers |
| API10:2023 | Unsafe Consumption of Third-Party APIs | Blindly trusting data from external webhooks and services | Strict schema validation and TLS verification on upstream APIs | Webhook input fuzzing |
Eliminating Broken Object Level Authorization (BOLA / IDOR)
Broken Object Level Authorization (BOLA), historically known as Insecure Direct Object References (IDOR), is the #1 vulnerability in modern APIs.
BOLA occurs when an API endpoint accepts an arbitrary user-supplied object identifier (e.g., GET /api/invoices/1042) without verifying whether the authenticated user has legitimate ownership rights to that object. Attackers simply iterate through sequential IDs to exfiltrate database records.
The Golden Rule of Authorization:
Never trust the client-supplied object ID alone. Always bind the query to the tenant or user ID extracted from the cryptographically verified authentication token:
// Hardened Resource Ownership Middleware in TypeScript / Express
import { Request, Response, NextFunction } from 'express';
import { db } from '@/lib/db';
export async function verifyInvoiceOwnership(
req: Request,
res: Response,
next: NextFunction
) {
const invoiceId = req.params.id;
const currentUserId = req.user?.id;
// Query invoice filtered explicitly by CURRENT USER ID and TENANT
const invoice = await db.invoice.findFirst({
where: {
id: invoiceId,
organizationId: req.user?.organizationId, // Mandatory multi-tenant boundary
},
});
if (!invoice) {
// Return 404 rather than 403 to prevent resource existence enumeration
return res.status(404).json({ error: 'Invoice not found' });
}
req.invoice = invoice;
next();
}JWT Hardening: Asymmetric Signatures & Token Revocation
JSON Web Tokens (JWTs) are widely used for stateless authorization, but common configuration blunders leave them vulnerable:
- Use Asymmetric Signatures (RS256 or Ed25519): Sign tokens on the authentication server using a private key and verify them on API gateways using a public key. Avoid symmetric HS256 in distributed systems to prevent sharing secret keys across services.
- Short Access Token Lifetimes: Set access token expiration to 15 minutes. Issue long-lived refresh tokens stored in secure,
HttpOnlycookies. - Refresh Token Rotation & Revocation: Store active refresh token hashes in Redis. When a refresh token is used, issue a new token and invalidate the old one immediately. If an old token is reused, revoke the entire family (detecting token theft).
Rate Limiting & Resource Quota Architecture
Without rate limiting, APIs are vulnerable to Denial of Service (DoS), brute-force attacks, and scraping. Implement a sliding window counter using Redis:
// Redis Sliding Window Rate Limiter Middleware in Node.js
import { Request, Response, NextFunction } from 'express';
import Redis from 'ioredis';
const redis = new Redis(process.env.REDIS_URL!);
const LIMIT = 100; // 100 requests
const WINDOW_SECONDS = 60; // per minute
export async function rateLimiter(req: Request, res: Response, next: NextFunction) {
const identifier = req.user?.id || req.ip;
const key = `ratelimit:${identifier}`;
const currentCount = await redis.incr(key);
if (currentCount === 1) {
await redis.expire(key, WINDOW_SECONDS);
}
res.setHeader('X-RateLimit-Limit', LIMIT);
res.setHeader('X-RateLimit-Remaining', Math.max(0, LIMIT - currentCount));
if (currentCount > LIMIT) {
return res.status(429).json({
error: 'Too Many Requests',
retryAfter: await redis.ttl(key),
});
}
next();
}GraphQL Security: Depth Limiting & Query Cost Analysis
Unlike REST, GraphQL allows clients to define the exact shape of query responses. Attackers exploit this with circular nested queries (e.g., user -> friends -> user -> friends...) that cause exponential database load (DoS):
- Depth Limiting: Enforce a maximum query nesting depth (e.g., max 6 levels) using libraries like
graphql-depth-limit. - Query Cost Analysis: Assign complexity weights to fields and reject queries exceeding a maximum computational threshold.
- Disable Introspection in Production: Disable schema introspection (
__schemaqueries) in production deployments to prevent attackers from discovering hidden administrative mutations.
Common Mistakes to Avoid
❌Relying on client-side routing to restrict access to sensitive API endpoints
Why it happens: Developers hide UI buttons for unprivileged users, assuming backend APIs are protected.
Why it matters: Attackers interact with raw HTTP endpoints using cURL or Postman, bypassing UI controls.
Correct approach: Enforce authorization checks on 100% of backend API handlers.
❌Using sequential integer IDs for public database resources (`/api/users/1`)
Why it happens: Default auto-incrementing database primary keys.
Why it matters: Enables trivial resource scraping and exposes business metrics (e.g., total registered users).
Correct approach: Use randomly generated UUIDv4 or KSUID identifiers for external API endpoints.
Troubleshooting Guide
Problem: CORS error: 'No 'Access-Control-Allow-Origin' header is present on the requested resource'
Possible Causes:
- Client application domain is not explicitly whitelisted in the API's CORS middleware configuration.
How to verify: Inspect preflight HTTP OPTIONS request headers in browser Network tab.
How to fix: Configure CORS middleware with an explicit allowlist of trusted origins; avoid `Access-Control-Allow-Origin: *` when credentials are supported.
Actionable Checklist
Wescequre Platform · Surface Monitor
Application Attack Surface Analyzer
Inspect open ports, TLS certificate chains, HTTP headers, and API endpoint security posture.
Includes: TLS/SSL cipher suite & expiration monitoring · Security header verification (CSP, HSTS) · Subdomain asset discovery
Frequently Asked Questions
Traditional server-rendered MVC apps managed state server-side. Modern APIs decouple frontend clients from backend databases, exposing granular CRUD endpoints and raw record IDs directly to browsers and mobile clients.
No. Standard JWT payloads are only base64url encoded, NOT encrypted. Any client or network observer can decode and read claims. Never place passwords, PII, or internal secrets inside JWT claims.
You can launch automated OWASP API Top 10 audits directly through the [Wescequre API Scanner](/dashboard/scan), which tests parameter fuzzing, BOLA, JWT weaknesses, and rate limiting.
Authoritative Sources & References
- OWASP: OWASP API Security Top 10 (2023)OWASP Foundation (official)View Source
- NIST SP 800-204: Security Strategies for Microservices-based Application SystemsNIST (official)View Source
- IETF RFC 7519: JSON Web Token (JWT) SpecificationIETF (official)View Source
Related Guides
Continue exploring related technical architecture and defensive guides
authentication · passwords
Secure Authentication Architecture: Passwords, MFA & Passkeys
Developer blueprint for authentication architecture: Argon2id password hashing parameters, FIDO2/WebAuthn passkey implementation, and credential stuffing defense.
sessions · cookies
Secure Session Management: Cookies, Tokens & Best Practices
Technical guide to session security: cryptographically secure cookie prefixes (`__Host-`), session fixation defense, idle timeouts, and Redis session architectures.
input validation · sanitization
Input Validation & Sanitization: Defensive Programming Guide
Developer blueprint for input validation: schema-based allowlists with Zod, ReDoS catastrophic backtracking defense, and safe multipart file upload pipelines.
