If you’ve ever built an Express API, you’ve probably reached for standard rate-limiting middleware to protect your login or payment endpoints from DDoS and brute-force attacks.
Under the hood, most simple limiters use a Fixed-Window Counter.
It’s easy to write: count incoming requests, and once the minute rolls over, reset the counter to zero.
However, from a security and algorithmic standpoint, Fixed-Window counters have a massive blind spot.
The Boundary Vulnerability (The 2-Second Spike) Imagine your endpoint allows a maximum of 100 requests per minute, resetting every full minute on the clock ().
Here is how an attacker bypasses that limit without breaking your rules: At 12:00:59, the attacker fires 100 requests. (Allowed: 100/100 used).
At 12:01:00, the clock resets your counter back to
0.
At 12:01:01, the attacker fires another 100 requests. (Allowed: 100/100 used).
To your server code, everything looks fine.
But in reality, 200 requests slammed your backend within a 2-second window.
In FinTech or authentication systems, that burst is more than enough to overwhelm payment gateways or run a successful credential-stuffing attack.
The Algorithmic Fix: Sliding Window Counter To stop boundary spikes, we need a continuously sliding window rather than a rigid clock reset.
Attempt 1: The Sliding Window Log (High Memory) You store a timestamps array (a Deque) for every user request and drop timestamps older than 60 seconds.
While accurate, storing every single request timestamp takes $O(N)$ space.
If your API receives millions of requests, your server memory dies instantly.
Attempt 2: Sliding Window Counter (Optimal O(1) Math) Instead of keeping thousands of timestamps, we track only two integers: the request count of the previous window and the count of the current window.
When a request arrives, we calculate an estimated request count by weighting the previous window based on how much time has passed in the current window: Estimated Requests=Current Count+(Previous Count×Window SizeWindow Size−Time Elapsed) If the time elapsed in the current window is 75%, we only count 25% of the previous window's traffic.
Time Complexity: lookup and arithmetic.
Space Complexity: memory footprint (just two counter variables per IP).
Building the Middleware in Node.js Here is a lightweight implementation using JavaScript to track state: Why This Matters for High-Performance Systems Sub-Millisecond Speed: The decision math executes in fractions of a microsecond without iterating over huge arrays.
Boundary Smoothness: An attacker trying the 12:00:59 / 12:01:01 spike will be blocked instantly because the weight of the 12:00:59 burst carries over into the calculation.
Production Readiness: In a distributed multi-node infrastructure, this exact math scales cleanly to Redis using simple and hash keys.
Applying basic competitive programming data structures and math to API security turns naive middleware into enterprise-grade defense.