API Penetration Testing & Security
Overview
This skill focuses on ensuring robust API security by preventing common vulnerabilities such as those listed in the OWASP API Security Top 10. It covers Broken Object Level Authorization (BOLA), Mass Assignment, rate limiting, JWT weaknesses, and injection attacks.
Core Principles
1. Authorization and BOLA (Broken Object Level Authorization)
Ensure that users can only access data they own.
- Always validate ownership: When an endpoint accesses a resource by ID, verify that the authenticated user is authorized to access that specific ID.
- Use indirect references: Where possible, use non-sequential or random IDs (UUIDs) to prevent enumeration.
2. Mass Assignment
Prevent attackers from updating fields they shouldn't have access to (e.g., isAdmin, balance).
- Explicit binding: Only allow specific properties to be bound from the request payload to the object.
- Use DTOs (Data Transfer Objects): Map incoming requests to DTOs rather than directly to domain models.
3. Rate Limiting and DoS Prevention
Protect endpoints from abuse by implementing rate limits.
- IP & User-based limiting: Limit requests per IP and per authenticated user.
- Complex endpoints: Apply stricter limits to computationally expensive endpoints (e.g., login, search).
4. JWT Token Validation Weaknesses
Ensure JWTs are generated and validated securely.
- Use strong algorithms: Enforce strong algorithms like RS256. Do not allow 'none' algorithm.
- Validate claims: Always validate
exp,iss,aud, andnbfclaims. - Store secrets securely: Never hardcode secrets. Use key management services.
5. Input Sanitization & Injection Prevention (SQL/NoSQL)
Never trust user input.
- Parameterized queries: Always use parameterized queries or ORMs to prevent SQL injection.
- Sanitize NoSQL inputs: Ensure NoSQL queries do not accept objects containing operators (e.g.,
$gt,$ne) from user input directly.
Code Examples
Bad: BOLA Vulnerability
// Express.js example - Vulnerable
app.get('/api/users/:id/data', async (req, res) => {
// Missing check: Does req.user own this :id?
const data = await db.getUserData(req.params.id);
res.json(data);
});
Good: BOLA Prevention
// Express.js example - Secure
app.get('/api/users/:id/data', async (req, res) => {
const targetId = req.params.id;
if (req.user.id !== targetId && req.user.role !== 'admin') {
return res.status(403).json({ error: 'Forbidden' });
}
const data = await db.getUserData(targetId);
res.json(data);
});
Checklist for API Security Review
- Are all endpoints authenticated?
- Is BOLA explicitly checked for all resource-accessing endpoints?
- Are DTOs used to prevent Mass Assignment?
- Is rate limiting configured globally and strictly on sensitive endpoints?
- Is the JWT algorithm explicitly verified?
- Are all database queries parameterized?
- Are inputs validated against a strict schema (e.g., using Zod or Joi)?