API Security
What I Do
I provide guidance on securing APIs against the OWASP API Security Top 10 risks. This includes authentication and authorization enforcement, rate limiting, input validation, response filtering, and protection against broken object-level authorization, mass assignment, and excessive data exposure.
When to Use Me
- Designing authentication and authorization for new API endpoints
- Implementing rate limiting and throttling strategies
- Protecting against BOLA (Broken Object Level Authorization) vulnerabilities
- Validating request payloads and filtering response data
- Securing GraphQL endpoints against introspection abuse and query complexity attacks
- Adding API gateway security policies
Core Concepts
- OWASP API Security Top 10: BOLA, broken authentication, broken object property level authorization, unrestricted resource consumption, broken function level authorization, unrestricted access to sensitive business flows, server-side request forgery, security misconfiguration, improper inventory management, unsafe consumption of APIs.
- Object-Level Authorization: Verify the requesting user has access to the specific resource instance, not just the resource type.
- Rate Limiting: Enforce request quotas per user, IP, or API key to prevent abuse and denial of service.
- Input Schema Validation: Validate request bodies against strict schemas rejecting unexpected fields.
- Response Filtering: Return only the fields the client needs rather than entire database objects.
- API Key Management: Rotate keys, scope them to specific endpoints, and never expose them in client-side code.
- Mass Assignment Protection: Explicitly define which fields are writable to prevent clients from modifying unintended properties.
Code Examples
1. Object-Level Authorization Check (Python/FastAPI)
from fastapi import HTTPException, Depends
from typing import Any
async def get_document(
document_id: int,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
) -> Any:
document = db.query(Document).filter(Document.id == document_id).first()
if not document:
raise HTTPException(status_code=404, detail="Not found")
if document.owner_id != current_user.id and not current_user.is_admin:
raise HTTPException(status_code=403, detail="Forbidden")
return document
2. Rate Limiting Middleware (Python/FastAPI)
import time
from collections import defaultdict
from fastapi import Request, HTTPException
from starlette.middleware.base import BaseHTTPMiddleware
class RateLimitMiddleware(BaseHTTPMiddleware):
def __init__(self, app, max_requests: int = 100, window_seconds: int = 60):
super().__init__(app)
self.max_requests = max_requests
self.window = window_seconds
self.requests: dict = defaultdict(list)
async def dispatch(self, request: Request, call_next):
client_ip = request.client.host
now = time.time()
self.requests[client_ip] = [
t for t in self.requests[client_ip] if now - t < self.window
]
if len(self.requests[client_ip]) >= self.max_requests:
raise HTTPException(status_code=429, detail="Rate limit exceeded")
self.requests[client_ip].append(now)
response = await call_next(request)
response.headers["X-RateLimit-Limit"] = str(self.max_requests)
response.headers["X-RateLimit-Remaining"] = str(
self.max_requests - len(self.requests[client_ip])
)
return response
3. Mass Assignment Protection (Python/Pydantic)
from pydantic import BaseModel
from typing import Optional
class UserCreate(BaseModel):
username: str
email: str
password: str
class UserUpdate(BaseModel):
email: Optional[str] = None
display_name: Optional[str] = None
class UserInternal(BaseModel):
id: int
username: str
email: str
is_admin: bool
password_hash: str
class UserResponse(BaseModel):
id: int
username: str
email: str
display_name: Optional[str] = None
4. GraphQL Query Depth Limiting (Node.js)
const depthLimit = require('graphql-depth-limit');
const { createComplexityLimitRule } = require('graphql-validation-complexity');
const server = new ApolloServer({
typeDefs,
resolvers,
validationRules: [
depthLimit(5),
createComplexityLimitRule(1000, {
onCost: (cost) => console.log('Query cost:', cost),
}),
],
introspection: process.env.NODE_ENV !== 'production',
});
Best Practices
- Check object-level authorization on every endpoint that accesses a specific resource by ID.
- Use explicit allowlists for writable fields to prevent mass assignment attacks.
- Validate all request payloads against strict schemas and reject unexpected fields.
- Return minimal response data using dedicated response models rather than raw database objects.
- Implement rate limiting per user, API key, and IP with appropriate windows and limits.
- Disable GraphQL introspection in production and enforce query depth and complexity limits.
- Use short-lived tokens (JWT with 15-minute expiry) with refresh token rotation.
- Log all authentication failures and authorization denials with request context.
- Version your APIs and deprecate old versions with clear timelines.
- Require TLS 1.2+ for all API communication and reject plaintext requests.
1---2name: api-security3description: Securing REST, GraphQL, and gRPC APIs against abuse, injection, broken authentication, and data exposure4---56# API Security78## What I Do910I provide guidance on securing APIs against the OWASP API Security Top 10 risks. This includes authentication and authorization enforcement, rate limiting, input validation, response filtering, and protection against broken object-level authorization, mass assignment, and excessive data exposure.1112## When to Use Me1314- Designing authentication and authorization for new API endpoints15- Implementing rate limiting and throttling strategies16- Protecting against BOLA (Broken Object Level Authorization) vulnerabilities17- Validating request payloads and filtering response data18- Securing GraphQL endpoints against introspection abuse and query complexity attacks19- Adding API gateway security policies2021## Core Concepts22231. **OWASP API Security Top 10**: BOLA, broken authentication, broken object property level authorization, unrestricted resource consumption, broken function level authorization, unrestricted access to sensitive business flows, server-side request forgery, security misconfiguration, improper inventory management, unsafe consumption of APIs.242. **Object-Level Authorization**: Verify the requesting user has access to the specific resource instance, not just the resource type.253. **Rate Limiting**: Enforce request quotas per user, IP, or API key to prevent abuse and denial of service.264. **Input Schema Validation**: Validate request bodies against strict schemas rejecting unexpected fields.275. **Response Filtering**: Return only the fields the client needs rather than entire database objects.286. **API Key Management**: Rotate keys, scope them to specific endpoints, and never expose them in client-side code.297. **Mass Assignment Protection**: Explicitly define which fields are writable to prevent clients from modifying unintended properties.3031## Code Examples3233### 1. Object-Level Authorization Check (Python/FastAPI)3435```python36from fastapi import HTTPException, Depends37from typing import Any3839async def get_document(40 document_id: int,41 current_user: User = Depends(get_current_user),42 db: Session = Depends(get_db),43) -> Any:44 document = db.query(Document).filter(Document.id == document_id).first()45 if not document:46 raise HTTPException(status_code=404, detail="Not found")47 if document.owner_id != current_user.id and not current_user.is_admin:48 raise HTTPException(status_code=403, detail="Forbidden")49 return document50```5152### 2. Rate Limiting Middleware (Python/FastAPI)5354```python55import time56from collections import defaultdict57from fastapi import Request, HTTPException58from starlette.middleware.base import BaseHTTPMiddleware5960class RateLimitMiddleware(BaseHTTPMiddleware):61 def __init__(self, app, max_requests: int = 100, window_seconds: int = 60):62 super().__init__(app)63 self.max_requests = max_requests64 self.window = window_seconds65 self.requests: dict = defaultdict(list)6667 async def dispatch(self, request: Request, call_next):68 client_ip = request.client.host69 now = time.time()70 self.requests[client_ip] = [71 t for t in self.requests[client_ip] if now - t < self.window72 ]73 if len(self.requests[client_ip]) >= self.max_requests:74 raise HTTPException(status_code=429, detail="Rate limit exceeded")75 self.requests[client_ip].append(now)76 response = await call_next(request)77 response.headers["X-RateLimit-Limit"] = str(self.max_requests)78 response.headers["X-RateLimit-Remaining"] = str(79 self.max_requests - len(self.requests[client_ip])80 )81 return response82```8384### 3. Mass Assignment Protection (Python/Pydantic)8586```python87from pydantic import BaseModel88from typing import Optional8990class UserCreate(BaseModel):91 username: str92 email: str93 password: str9495class UserUpdate(BaseModel):96 email: Optional[str] = None97 display_name: Optional[str] = None9899class UserInternal(BaseModel):100 id: int101 username: str102 email: str103 is_admin: bool104 password_hash: str105106class UserResponse(BaseModel):107 id: int108 username: str109 email: str110 display_name: Optional[str] = None111```112113### 4. GraphQL Query Depth Limiting (Node.js)114115```javascript116const depthLimit = require('graphql-depth-limit');117const { createComplexityLimitRule } = require('graphql-validation-complexity');118119const server = new ApolloServer({120 typeDefs,121 resolvers,122 validationRules: [123 depthLimit(5),124 createComplexityLimitRule(1000, {125 onCost: (cost) => console.log('Query cost:', cost),126 }),127 ],128 introspection: process.env.NODE_ENV !== 'production',129});130```131132## Best Practices1331341. **Check object-level authorization** on every endpoint that accesses a specific resource by ID.1352. **Use explicit allowlists** for writable fields to prevent mass assignment attacks.1363. **Validate all request payloads** against strict schemas and reject unexpected fields.1374. **Return minimal response data** using dedicated response models rather than raw database objects.1385. **Implement rate limiting** per user, API key, and IP with appropriate windows and limits.1396. **Disable GraphQL introspection** in production and enforce query depth and complexity limits.1407. **Use short-lived tokens** (JWT with 15-minute expiry) with refresh token rotation.1418. **Log all authentication failures** and authorization denials with request context.1429. **Version your APIs** and deprecate old versions with clear timelines.14310. **Require TLS 1.2+** for all API communication and reject plaintext requests.