API Security Hardening
API gateways, schema validation, response filtering (projection), rate limiting on all endpoints, per-object authorization checks, audit logging of every API call. The production API security checklist.
API gateways, schema validation, response filtering (projection), rate limiting on all endpoints, per-object authorization checks, audit logging of every API call. The production API security checklist.
A single misconfigured API gateway or a missing authorisation check can expose millions of records. Defence in depth for APIs means layering gateway controls, schema validation, response filtering, and per-object authorisation checks so that no single bypass compromises the system.
API security cannot rely on a single control. Defence in depth means stacking multiple independent layers so that if one fails, the next still protects the system. Every request should pass through an API gateway that handles authentication, rate limiting, and schema validation before reaching the application controller. Inside the controller, each handler must perform its own per-object authorisation check and filter the response to return only the fields the client is allowed to see.
An API gateway like Kong, AWS API Gateway, or Netflix Zuul acts as the single entry point. It terminates TLS, validates API keys, enforces rate limits, logs every request, and can reject malformed payloads before they reach your application. This pattern is sometimes called the "gateway pattern" or "edge service" pattern. The gateway is the first line of defence, but it must be backed by application-level checks because a gateway bypass (e.g. internal network access to the backend) would otherwise bypass all controls.
Schema validation using the OpenAPI specification (or JSON Schema) ensures that every request body matches a documented contract. Requests with unexpected fields, wrong data types, or excessively large payloads are rejected at the gateway. This prevents a class of attacks where an attacker sends a malformed request that triggers unexpected behaviour in the application logic.
Toggle security controls on and off in the gateway configuration, then send a test request to see which layers pass or block it.
No requests yet.
In 2019, a former AWS employee exploited a misconfigured Web Application Firewall (WAF) on Capital One's API gateway to perform a Server-Side Request Forgery (SSRF) attack. The attacker used the SSRF to reach the AWS metadata service (169.254.169.254) and exfiltrate temporary credentials that granted access to Capital One's S3 buckets. Over 100 million credit card applications were exposed, including names, addresses, credit scores, and Social Security numbers. Capital One eventually paid $190 million in fines.
The root cause was not a missing auth check in the application logic but a weakness in the gateway layer: the WAF did not block requests to the metadata service, and the gateway's network configuration allowed outbound traffic to internal AWS endpoints. After the breach, Capital One implemented proper gateway hardening: network segmentation between the gateway and backend services, blocking access to the metadata service at the gateway level, and adding SSRF-specific WAF rules. The incident is a textbook case of why every layer in the defence-in-depth stack must be configured correctly.
GraphQL introduces unique attack surfaces. Without depth limiting, an attacker can send a deeply nested query like user { friends { friends { friends ... } } } that causes exponential database load. Cost analysis assigns a cost value to each field and rejects queries that exceed a budget. Field-level middleware ensures that a resolver checks authorisation even if the parent resolver has already checked it — GraphQL's resolver chain makes per-field checks essential. Persisted queries disable ad-hoc GraphQL queries in production, allowing only pre-approved query strings.
For REST APIs, never include sensitive data in URL parameters (e.g. tokens, API keys) because URLs are logged by proxies, load balancers, and browser history. Enforce the Content-Type header and reject requests with unexpected content types (e.g. reject XML if you only accept JSON). Set request body size limits at the gateway to prevent large payload attacks. Use HATEOAS-style responses where the server tells the client which actions are available, preventing enumeration of hidden endpoints.
// Per-object authorisation — every handler checks ownership
async function getOrder(req: Request, res: Response) {
const user = await authenticate(req);
const order = await db.order.findUnique({
where: { id: req.params.id },
});
// Must check: does this user own this order?
if (order.userId !== user.id) {
return res.status(403).json({ error: 'forbidden' });
}
// Response filtering — only return allowed fields
const { id, status, createdAt, items } = order;
return res.json({ id, status, createdAt, items });
}Rate limiting should apply to every endpoint, not just login. A search endpoint or a graphql batch endpoint can be abused just as easily as an auth endpoint. Every API call should also be logged with a consistent audit trail that includes the user ID, IP address, endpoint, timestamp, and response status. Logs are essential for post-incident forensics. Finally, configure CORS strictly — allow only the specific origins that need access, never use a wildcard in production.
1.What is the primary purpose of an API gateway in a defence-in-depth architecture?
2.Which GraphQL-specific defence prevents attackers from sending exponentially nested queries?
3.What was the root cause of the 2019 Capital One data breach?