Why Fixed-Window Rate Limiters Fail (And How to Fix Them with Math)

2026年8月23日1 次浏览来源:Dev.to阅读原文

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.

分享
Baike.dev

baike.dev helps you discover great languages, frameworks, databases, DevOps and cloud-native tools.

Quick links

About

Contribute

Found a great developer tool? Share it with the community.

Submit a tool
© 2026 baike.dev Developer EncyclopediaUpdated daily · Discover great developer tools