mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-07-26 11:49:16 +00:00
feat(api): add global rate limiter for all API endpoints (#317)
Apply a global rate limit of 100 requests/min per IP to all /api/ routes in production, configurable via API_RATE_LIMIT env var. Auth endpoints retain their existing stricter limits which stack independently. Returns 429 Too Many Requests when exceeded.
This commit is contained in:
@@ -7,6 +7,9 @@ JWT_SECRET=your-secure-jwt-secret-here
|
||||
# Directory containing docker-compose files
|
||||
COMPOSE_DIR=/path/to/your/compose/files
|
||||
|
||||
# Global API rate limit (requests per minute per IP, production only)
|
||||
API_RATE_LIMIT=100
|
||||
|
||||
# ─── SSO / LDAP Configuration (Admiral) ───────────────────────────
|
||||
|
||||
# LDAP / Active Directory
|
||||
|
||||
@@ -13,6 +13,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
* **api:** global rate limiter on all `/api/` routes — 100 requests/min per IP in production (configurable via `API_RATE_LIMIT` env var). Auth endpoints retain their existing stricter limits (5 req/15min) which stack independently. Returns `429 Too Many Requests` when exceeded.
|
||||
|
||||
### Fixed
|
||||
|
||||
* **security:** enforce `isValidStackName()` on all routes that accept a `stackName` parameter — 11 routes had no validation and 2 used a weaker manual check; all now use the canonical `^[a-zA-Z0-9_-]+$` regex guard, returning `400 Invalid stack name` on rejection
|
||||
|
||||
@@ -133,6 +133,21 @@ app.use(cors({
|
||||
credentials: true,
|
||||
}));
|
||||
|
||||
// Global API rate limiter — caps total requests per IP across all /api/ routes.
|
||||
// Auth-specific limiters (authRateLimiter, ssoRateLimiter) apply additional,
|
||||
// stricter limits on their respective routes and stack independently.
|
||||
const globalApiLimiter = rateLimit({
|
||||
windowMs: 60 * 1000,
|
||||
max: process.env.NODE_ENV === 'production'
|
||||
? parseInt(process.env.API_RATE_LIMIT || '100', 10)
|
||||
: 1000,
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
message: { error: 'Too many requests. Please try again shortly.' },
|
||||
});
|
||||
|
||||
app.use('/api/', globalApiLimiter);
|
||||
|
||||
// Conditionally parse JSON bodies. Remote proxy requests must NOT have their body
|
||||
// consumed here: express.json() drains the IncomingMessage stream into req.body
|
||||
// and http-proxy then pipes an already-ended stream to the remote server.
|
||||
|
||||
@@ -88,7 +88,19 @@ This applies to all stack endpoints: read, write, deploy, down, restart, stop, s
|
||||
|
||||
## Rate limiting
|
||||
|
||||
Authentication endpoints (`/api/auth/*`) are rate-limited to **5 requests per 15 minutes** in production. API token-authenticated requests are not rate-limited.
|
||||
All `/api/` endpoints are subject to a global rate limit of **100 requests per minute** per IP address. When exceeded, the server responds with `429 Too Many Requests`:
|
||||
|
||||
```json
|
||||
{
|
||||
"error": "Too many requests. Please try again shortly."
|
||||
}
|
||||
```
|
||||
|
||||
Authentication endpoints (`/api/auth/*`) have an additional, stricter limit of **5 requests per 15 minutes** to prevent brute-force attacks. Both limits apply independently — a login request counts against both the global limit and the auth limit.
|
||||
|
||||
The global rate limit is configurable via the `API_RATE_LIMIT` environment variable (requests per minute, default `100`).
|
||||
|
||||
Standard rate limit headers (`RateLimit-Limit`, `RateLimit-Remaining`, `RateLimit-Reset`) are included in all API responses.
|
||||
|
||||
## License tier requirements
|
||||
|
||||
|
||||
Reference in New Issue
Block a user