The Rate Limit Filter can help mitigate Denial of Service
(DoS) and Brute Force attacks by limiting the number of a requests that are
allowed from a single IP address within a time window (also referred
to as a time bucket), e.g. 300 Requests per 60 seconds.
The filter works by incrementing a counter in a time bucket for each IP
address, and if the counter exceeds the allowed limit then further requests
from that IP are dropped with a "429 Too many requests" response
until the bucket time ends and a new bucket starts.
The RateLimiter implementation can be set via the rateLimitClassName
init param. The default implementation,
org.apache.catalina.util.FastRateLimiter, is optimized for
efficiency and low overhead so it converts some configured values to more
efficient values. For example, a configuration of a 60 seconds time bucket
is converted to 65.536 seconds. That allows for very fast bucket calculation
using bit shift arithmetic. In order to remain true to the user intent, the
configured number of requests is then multiplied by the same ratio, so a
configuration of 100 Requests per 60 seconds, has the real values of 109
Requests per 65 seconds. An alternative implementation,
org.apache.catalina.util.ExactRateLimiter, is intended to
provide a less efficient but more accurate control, whose effective duration
in seconds and number of requests allowed are consist with the configured
values. You can specify a different class as long as it implements the
org.apache.catalina.util.RateLimiter interface.
It is common to set up different restrictions for different URIs.
For example, a login page or authentication script is typically expected
to get far less requests than the rest of the application, so you can add
a filter definition that would allow only 5 requests per 15 seconds and map
those URIs to it.
You can set enforce to false
to disable the termination of requests that exceed the allowed limit. Then
your application code can inspect the Request Attribute
org.apache.catalina.filters.RateLimitFilter.Count and decide
how to handle the request based on other information that it has, e.g. allow
more requests to certain users based on roles, etc.
exposeHeaders enables the output of the rate limiter
configuration and state via an HTTP response header as per RateLimit
header fields for HTTP (draft).
WARNING: if Tomcat is behind a reverse proxy then you must
make sure that the Rate Limit Filter sees the client IP address, so if for
example you are using the Remote IP Filter,
then the filter mapping for the Rate Limit Filter must come after
the mapping of the Remote IP Filter to ensure that each request has its IP
address resolved before the Rate Limit Filter is applied. Failure to do so
will count requests from different IPs in the same bucket and will result in
a self inflicted DoS attack.