Servlet filter that 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 filter 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.
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.
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.
| Modifier and Type | Field and Description |
|---|---|
| private int | |
| pack-priv transient TimeBucketCounter | |
| private int | |
| private int | |
| public static final int | DEFAULT_BUCKET_DURATION
default duration in seconds |
| public static final int | DEFAULT_BUCKET_REQUESTS
default number of requests per duration |
| public static final boolean | DEFAULT_ENFORCE
default value for enforce |
| public static final int | DEFAULT_STATUS_CODE
default status code to return if requests per duration exceeded |
| public static final String | DEFAULT_STATUS_MESSAGE
default status message to return if requests per duration exceeded |
| private boolean | |
| private transient Log | |
| public static final String | PARAM_BUCKET_DURATION
init-param to set the bucket duration in seconds |
| public static final String | PARAM_BUCKET_REQUESTS
init-param to set the bucket number of requests |
| public static final String | PARAM_ENFORCE
init-param to set the enforce flag |
| public static final String | PARAM_STATUS_CODE
init-param to set a custom status code if requests per duration exceeded |
| public static final String | PARAM_STATUS_MESSAGE
init-param to set a custom status message if requests per duration exceeded |
| public static final String | RATE_LIMIT_ATTRIBUTE_COUNT
request attribute that will contain the number of requests per duration |
| private static final long | |
| private static final StringManager | |
| private int | |
| private String |
| Access | Constructor and Description |
|---|---|
| public |
| Modifier and Type | Method and Description |
|---|---|
| public void | destroy()
Overrides default jakarta. Called by the web container to indicate to a filter that it is being taken out of service. |
| public void | doFilter(ServletRequest
The request to process request, ServletResponse The response associated with the request response, FilterChain Provides access to the next filter in the chain for this filter to pass the request and response
to for further processing chain)Implements jakarta. The |
| public int | |
| public int | |
| public void | init()
Overrides jakarta. Convenience method for sub-classes to save them having to call |
| actualRequests | back to summary |
|---|---|
| private int actualRequests | |
| bucketCounter | back to summary |
|---|---|
| pack-priv transient TimeBucketCounter bucketCounter | |
| bucketDuration | back to summary |
|---|---|
| private int bucketDuration | |
| bucketRequests | back to summary |
|---|---|
| private int bucketRequests | |
| DEFAULT_BUCKET_DURATION | back to summary |
|---|---|
| public static final int DEFAULT_BUCKET_DURATION default duration in seconds | |
| DEFAULT_BUCKET_REQUESTS | back to summary |
|---|---|
| public static final int DEFAULT_BUCKET_REQUESTS default number of requests per duration | |
| DEFAULT_ENFORCE | back to summary |
|---|---|
| public static final boolean DEFAULT_ENFORCE default value for enforce | |
| DEFAULT_STATUS_CODE | back to summary |
|---|---|
| public static final int DEFAULT_STATUS_CODE default status code to return if requests per duration exceeded | |
| DEFAULT_STATUS_MESSAGE | back to summary |
|---|---|
| public static final String DEFAULT_STATUS_MESSAGE default status message to return if requests per duration exceeded | |
| enforce | back to summary |
|---|---|
| private boolean enforce | |
| log | back to summary |
|---|---|
| private transient Log log | |
| PARAM_BUCKET_DURATION | back to summary |
|---|---|
| public static final String PARAM_BUCKET_DURATION init-param to set the bucket duration in seconds | |
| PARAM_BUCKET_REQUESTS | back to summary |
|---|---|
| public static final String PARAM_BUCKET_REQUESTS init-param to set the bucket number of requests | |
| PARAM_ENFORCE | back to summary |
|---|---|
| public static final String PARAM_ENFORCE init-param to set the enforce flag | |
| PARAM_STATUS_CODE | back to summary |
|---|---|
| public static final String PARAM_STATUS_CODE init-param to set a custom status code if requests per duration exceeded | |
| PARAM_STATUS_MESSAGE | back to summary |
|---|---|
| public static final String PARAM_STATUS_MESSAGE init-param to set a custom status message if requests per duration exceeded | |
| RATE_LIMIT_ATTRIBUTE_COUNT | back to summary |
|---|---|
| public static final String RATE_LIMIT_ATTRIBUTE_COUNT request attribute that will contain the number of requests per duration | |
| serialVersionUID | back to summary |
|---|---|
| private static final long serialVersionUID | |
| sm | back to summary |
|---|---|
| private static final StringManager sm | |
| statusCode | back to summary |
|---|---|
| private int statusCode | |
| statusMessage | back to summary |
|---|---|
| private String statusMessage | |
| RateLimitFilter | back to summary |
|---|---|
| public RateLimitFilter() | |
| destroy | back to summary |
|---|---|
| public void destroy() Overrides default jakarta. Doc from jakarta. Called by the web container to indicate to a filter that it is being taken out of service. This method is only
called once all threads within the filter's doFilter method have exited or after a timeout period has passed.
After the web container calls this method, it will not call the doFilter method again on this instance of the
filter.
| |
| doFilter | back to summary |
|---|---|
| public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException Implements jakarta. Doc from jakarta. The
A typical implementation of this method would follow the following pattern:-
| |
| getActualDurationInSeconds | back to summary |
|---|---|
public int getActualDurationInSeconds()
| |
| getActualRequests | back to summary |
|---|---|
public int getActualRequests()
| |
| init | back to summary |
|---|---|
| public void init() throws ServletException Overrides jakarta. Doc from jakarta. Convenience method for sub-classes to save them having to call
| |