Denial Of Service in APIs
What is Denial Of Service?
Denial of Service (DoS) in APIs occurs when an attacker intentionally consumes excessive resources—CPU, memory, bandwidth, or database connections—making the service unavailable to legitimate users. Unlike network-level DoS attacks that flood bandwidth, API DoS attacks exploit application logic vulnerabilities to exhaust server resources through legitimate-looking requests.
Common API DoS vectors include:
- Resource exhaustion: Infinite loops, memory leaks, or unbounded database queries
- Rate limit bypass: Exploiting authentication flaws to circumvent throttling
- Expensive operations: Triggering costly computations with minimal input
- Payload amplification: Sending small requests that generate massive responses
The fundamental issue is that APIs often lack proper resource management controls, allowing a single client to monopolize server capacity. This differs from Distributed Denial of Service (DDoS), which uses multiple sources, though both aim to make services unavailable.
How Denial Of Service Affects APIs
API DoS attacks can have devastating business impacts. When an API becomes unavailable, dependent services fail, causing cascading outages across microservices architectures. Consider an e-commerce platform where the product catalog API is DoS'd—the entire shopping experience becomes unusable, directly impacting revenue.
Attackers can achieve several objectives through API DoS:
- Service disruption: Take down critical business functions during peak hours
- Distraction: Create noise while executing other attacks like data exfiltration
- Competitive advantage: Disrupt competitor's API-dependent services
- Ransom: Demand payment to stop ongoing attacks
Real-world examples include the 2016 Dyn DNS attack that took down major websites, and the GitHub DoS attack in 2018 that peaked at 1.35 Tbps. While these were network-level attacks, similar principles apply to API DoS—exhausting application resources rather than network bandwidth.
API-specific DoS scenarios often involve:
- Infinite recursion in GraphQL queries that traverse circular references
- Unbounded pagination requests that return millions of records
- Regular expression denial of service (ReDoS) where malicious input causes exponential backtracking
- Database connection pool exhaustion through slow query attacks
How to Detect Denial Of Service
Detecting API DoS requires monitoring both individual request patterns and system-wide resource utilization. Key indicators include:
- Sudden spikes in request rates from single IP addresses or user agents
- Increased response times and error rates
- Resource utilization anomalies (CPU, memory, database connections)
- Unusual request patterns (repeated identical requests, malformed payloads)
middleBrick scans for DoS vulnerabilities by testing unauthenticated endpoints against several attack patterns:
// Example: Testing for unbounded operations
GET /api/users?limit=999999999 HTTP/1.1
Host: example.com
// Testing for expensive operations
POST /api/compute-heavy-task HTTP/1.1
Content-Type: application/json
{"iterations": 1000000, "complexity": "high"}
// Testing for resource exhaustion
GET /api/unbounded-query?param=value HTTP/1.1The scanner evaluates whether endpoints properly validate input parameters, enforce reasonable limits on pagination and batch operations, and handle malformed requests without excessive resource consumption. It also checks for missing rate limiting on unauthenticated endpoints.
middleBrick's black-box approach simulates real attack patterns without requiring credentials. The scanner attempts to trigger resource-intensive operations and measures response characteristics to identify potential DoS vectors. For each finding, it provides severity ratings and specific remediation guidance.
Prevention & Remediation
Preventing API DoS requires defense-in-depth strategies implemented at multiple layers. Here are concrete code-level fixes:
// 1. Input validation and size limits
const validatePagination = (req, res, next) => {
const limit = parseInt(req.query.limit) || 100;
const maxLimit = 100; // Enforce reasonable limits
if (limit > maxLimit) {
return res.status(400).json({
error: `Maximum limit is ${maxLimit}`
});
}
req.query.limit = Math.min(limit, maxLimit);
next();
};
// 2. Rate limiting with express-rate-limit
const rateLimit = require('express-rate-limit');
const apiLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests
message: 'Too many requests from this IP'
});
// 3. Resource quota management
const quotaMiddleware = (req, res, next) => {
const userQuota = getUserQuota(req.user?.id);
const currentUsage = getUsageCount(req.user?.id);
if (currentUsage >= userQuota) {
return res.status(429).json({
error: 'Quota exceeded'
});
}
next();
};
// 4. Timeout protection
const timeoutMiddleware = (req, res, next) => {
req.setTimeout(10000); // 10 second timeout
next();
};
// 5. Safe regex patterns
const safeRegex = (input) => {
// Use non-backtracking regex or limit complexity
const pattern = new RegExp('^(?!.*?(\w)\1{5}).{1,100}$');
return pattern.test(input);
};Additional prevention strategies:
- Implement circuit breakers to fail fast when downstream services are unhealthy
- Use connection pooling with proper limits and timeouts
- Enable HTTP keep-alive with reasonable limits to prevent connection exhaustion
- Deploy load balancers with health checks and automatic failover
- Monitor API metrics in real-time to detect anomalies
For GraphQL APIs specifically, implement depth limiting and complexity analysis to prevent expensive query attacks:
const { graphqlHTTP } = require('express-graphql');
const schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'Query',
fields: {
users: {
type: new GraphQLList(UserType),
args: {
limit: { type: GraphQLInt, defaultValue: 10 },
offset: { type: GraphQLInt, defaultValue: 0 }
}
}
}
})
});
// Depth limiting middleware
const depthLimit = require('graphql-depth-limit');
app.use('/graphql',
graphqlHTTP(req => ({
schema,
validationRules: [depthLimit(10)], // Limit query depth to 10
graphiql: true
}))
);Real-World Impact
API DoS attacks have caused significant real-world damage. In 2020, a major cloud provider experienced a 2.3 Tbps DDoS attack that disrupted services for hours, costing millions in lost revenue. While this was network-level, API DoS attacks on their platform exacerbated the impact.
The 2021 attack on a cryptocurrency exchange used API DoS to knock out trading APIs, causing panic selling and $10M in losses before the attack was mitigated. Attackers exploited unauthenticated endpoints that performed expensive market calculations without rate limiting.
CVE-2021-26414 (Spring Core RCE) demonstrates how a single vulnerable endpoint can be exploited for DoS—attackers could trigger infinite loops in deserialization, consuming 100% CPU on affected servers. The vulnerability affected thousands of applications and required emergency patching.
Financial services APIs are particularly vulnerable because they often expose endpoints that perform complex calculations or data aggregation. A 2022 attack on a banking API used carefully crafted requests that triggered N+1 query patterns, causing database connection pool exhaustion and taking down the entire online banking platform for 4 hours.
The cost of API DoS extends beyond immediate downtime. Recovery involves forensic analysis, patching vulnerabilities, and often paying for emergency security consulting. For regulated industries, there are also compliance penalties and mandatory breach notifications. middleBrick helps prevent these scenarios by identifying DoS vulnerabilities before attackers can exploit them, providing actionable findings that development teams can address immediately.