Modern backends are mostly APIs — JSON over HTTP, consumed by web apps, mobile apps, and other services. That makes the API layer where most of your attack surface lives, and where most of the lessons so far come together. OWASP maintains a dedicated API Security Top 10 precisely because API breaches have their own characteristic shape, and it’s a genuinely useful map of where things go wrong. This lesson walks the everyday risks from that list and then digs into rate limiting, the one defensive mechanism that deserves its own explanation.
The API Risks That Actually Get You
You don’t need to memorise all ten items; you need to recognise the handful that cause the real incidents. Here they are, with the mistake and the fix.
- Broken Object Level Authorization (BOLA) — the number-one API risk, covered in depth in Lesson 3. Changing an id in the URL to access another user’s object, because the server checked authentication but not ownership. Fix: scope every object access by owner/tenant, on read, write, and delete.
- Broken authentication — weak or missing auth: guessable tokens, tokens that never expire, no lockout or rate limit on login, accepting
alg:noneJWTs (Lesson 2). Fix: strong auth, short-lived tokens, rate-limited and lockout-protected login, pinned JWT algorithms. - Broken Object Property Authorization / mass assignment — the one worth a closer look (below). The API lets a user write fields they shouldn’t, like flipping their own
is_admin. Fix: explicitly allowlist which fields a request may set. - Unrestricted resource consumption — no rate limits or quotas, so an attacker can brute-force credentials, scrape all your data, or run up a huge cloud bill (the “denial of wallet” variant). Fix: rate limits, quotas, pagination caps, timeouts (below).
- Security misconfiguration — debug mode on in production, verbose stack traces leaking internals, overly permissive CORS (
Access-Control-Allow-Origin: *with credentials), missing security headers (Lesson 5). Fix: harden defaults, return generic errors, lock CORS down to the origins that actually need it.
The thread running through the top of this list is unmistakable: authorization bugs dominate real API breaches. Not fancy exploits — forgotten checks. The single most valuable habit for API security is the one from Lesson 3: on every endpoint, check who may touch what.
Mass Assignment: The Convenience Trap
Mass assignment deserves special attention because the very framework feature that makes you productive is what creates the bug. Many frameworks let you bind an incoming request body straight to a model object in one line — user.update(request.body) — which is wonderfully convenient and quietly dangerous. If the request includes fields you didn’t intend to expose, they get written too.
The illustrative scenario (made up to show the mechanism): your “update profile” endpoint expects {name, bio}. An attacker sends {name, bio, is_admin: true, account_balance: 999999}. If your code binds the whole body to the user model, you just handed them admin and a fortune. The attacker learned the extra field names by reading your API responses, your mobile app, or just guessing common ones.
The fix is to explicitly allowlist the fields a request may set, never bind the raw body wholesale. Accept only name and bio; ignore everything else. Concretely: use a strict input schema / DTO that lists exactly the writable fields, or your framework’s “permit these params” mechanism. Sensitive fields (is_admin, role, verified, balance, owner_id) should only ever be settable through dedicated, authorized code paths — never through a general update endpoint. This is really the property-level sibling of BOLA: just as you check which objects a user may touch, you must control which fields of an object a user may write.
Rate Limiting: A Token Bucket
Rate limiting shows up repeatedly in this course — as brute-force defense (Lesson 2), DoS defense (Lesson 1), and resource-consumption defense (above) — so it’s worth understanding the mechanism. The standard model is a token bucket, and it’s pleasingly simple.
Picture a bucket that holds up to N tokens (the burst capacity) and refills at a steady rate (say, 10 tokens per second). Each request takes one token: if a token is available, the request is allowed (200); if the bucket is empty, the request is rejected (429 Too Many Requests). Because the bucket refills over time, legitimate users with normal bursts sail through, while anyone hammering the endpoint quickly drains it and gets throttled. The two knobs — bucket size (how big a burst you tolerate) and refill rate (sustained throughput) — let you tune it per endpoint.
Where it matters most:
- Login, OTP, and password-reset endpoints — the front line against credential stuffing and brute-force. As Lesson 2 showed, a slow password hash already limits guessing; rate limiting plus account lockout / exponential backoff closes the gap. These endpoints deserve the tightest limits.
- Per-user and per-IP limits. An attacker rotates IP addresses to dodge IP limits, so also limit per account/token. A logged-in abuser doesn’t change identity, so per-user limits catch them. You want both.
- Expensive endpoints — search, export, report generation, LLM calls, anything that costs real compute or money. Rate limits here protect both availability and your bill.
- Return
429with aRetry-Afterheader, and limit at the edge (API gateway / load balancer) where you can, so abusive traffic is dropped before it ever reaches your application and consumes resources.
Rate limiting is one of those controls that quietly prevents a whole category of attacks, costs little, and is easy to add — a gateway or a small middleware with a shared counter (often in Redis) gets you most of the way.
A Few More API Habits
- Validate and type-check every input against a schema (Lesson 4). Reject unexpected shapes early.
- Don’t leak internals in errors. A 500 should say “something went wrong,” not print a stack trace and SQL. Log the detail server-side; return a generic message and a request id.
- Lock down CORS. Only the origins that genuinely need cross-origin access should be allowed, and be very careful combining
Allow-Credentials: truewith broad origins. - Version and deprecate carefully. Old, unmaintained API versions are a classic soft underbelly — an attacker uses
v1becausev1never got the fixv2did. - Authenticate service-to-service calls too. Internal APIs aren’t safe just because they’re “internal” (Lesson 10, Lesson 5’s SSRF). Require auth between services.
Pitfalls to Avoid
- Missing object-level authorization (BOLA). The top API breach cause. Check ownership on every object access (Lesson 3).
- Mass assignment. Binding the raw request body to your model lets attackers set
is_admin. Allowlist writable fields explicitly. - No rate limiting. Invites brute-force, scraping, and bill-shock. Add token-bucket limits, tightest on auth and expensive endpoints.
- Only IP-based limits. Attackers rotate IPs. Limit per-user/token as well.
- Verbose errors and debug mode in production. They leak internals. Return generic errors with a request id; log detail server-side.
- Permissive CORS.
*with credentials is dangerous. Allow only the origins that need it. - Forgotten old API versions and unauthenticated internal APIs. Deprecate old versions; authenticate service-to-service calls.
Quick Recap
- APIs are most of your attack surface; the OWASP API Security Top 10 maps where they break.
- Authorization bugs dominate: BOLA (object ownership) and broken object-property authz (mass assignment) are the big ones — check who may touch what, and allowlist which fields a request may set.
- Guard against broken authentication, unrestricted consumption, and misconfiguration (short tokens, quotas, generic errors, tight CORS).
- Rate limiting is a token bucket: spend a token per request, 429 when empty, refill steadily. Apply it hardest to auth and expensive endpoints, per-user and per-IP, at the edge.
Next lesson: your code is mostly other people’s code. We’ll look at supply-chain security — dependencies, SBOMs, and hardening the CI/CD pipeline that turns your code into a running artifact.