Top Description Fields Constructors Methods
org.apache.catalina.filters

public Class RateLimitFilter

extends GenericFilter
Class Inheritance
Imports
java.io.IOException, java.util.concurrent.ScheduledExecutorService, jakarta.servlet.FilterChain, .FilterConfig, .GenericFilter, .ServletException, .ServletRequest, .ServletResponse, jakarta.servlet.http.HttpServletResponse, org.apache.catalina.util.TimeBucketCounter, org.apache.juli.logging.Log, .LogFactory, org.apache.tomcat.util.res.StringManager, org.apache.tomcat.util.threads.ScheduledThreadPoolExecutor

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.

Field Summary

Modifier and TypeField 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

Constructor Summary

AccessConstructor and Description
public

Method Summary

Modifier and TypeMethod and Description
public void
destroy()

Overrides default jakarta.servlet.Filter.destroy.

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.servlet.Filter.doFilter.

The doFilter method of the Filter is called by the container each time a request/response pair is passed through the chain due to a client request for a resource at the end of the chain.

public int

Returns:

the actual duration of a time bucket in milliseconds
getActualDurationInSeconds
()

public int

Returns:

the actual maximum allowed requests per time bucket
getActualRequests
()

public void
init()

Overrides jakarta.servlet.GenericFilter.init.

Convenience method for sub-classes to save them having to call super.init(config).

Inherited from jakarta.servlet.GenericFilter:
getFilterConfiggetFilterNamegetInitParametergetInitParameterNamesgetServletContextinit

Field Detail

actualRequestsback to summary
private int actualRequests
bucketCounterback to summary
pack-priv transient TimeBucketCounter bucketCounter
bucketDurationback to summary
private int bucketDuration
bucketRequestsback to summary
private int bucketRequests
DEFAULT_BUCKET_DURATIONback to summary
public static final int DEFAULT_BUCKET_DURATION

default duration in seconds

DEFAULT_BUCKET_REQUESTSback to summary
public static final int DEFAULT_BUCKET_REQUESTS

default number of requests per duration

DEFAULT_ENFORCEback to summary
public static final boolean DEFAULT_ENFORCE

default value for enforce

DEFAULT_STATUS_CODEback to summary
public static final int DEFAULT_STATUS_CODE

default status code to return if requests per duration exceeded

DEFAULT_STATUS_MESSAGEback to summary
public static final String DEFAULT_STATUS_MESSAGE

default status message to return if requests per duration exceeded

enforceback to summary
private boolean enforce
logback to summary
private transient Log log
PARAM_BUCKET_DURATIONback to summary
public static final String PARAM_BUCKET_DURATION

init-param to set the bucket duration in seconds

PARAM_BUCKET_REQUESTSback to summary
public static final String PARAM_BUCKET_REQUESTS

init-param to set the bucket number of requests

PARAM_ENFORCEback to summary
public static final String PARAM_ENFORCE

init-param to set the enforce flag

PARAM_STATUS_CODEback to summary
public static final String PARAM_STATUS_CODE

init-param to set a custom status code if requests per duration exceeded

PARAM_STATUS_MESSAGEback 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_COUNTback to summary
public static final String RATE_LIMIT_ATTRIBUTE_COUNT

request attribute that will contain the number of requests per duration

serialVersionUIDback to summary
private static final long serialVersionUID

Hides jakarta.servlet.GenericFilter.serialVersionUID.

smback to summary
private static final StringManager sm
statusCodeback to summary
private int statusCode
statusMessageback to summary
private String statusMessage

Constructor Detail

RateLimitFilterback to summary
public RateLimitFilter()

Method Detail

destroyback to summary
public void destroy()

Overrides default jakarta.servlet.Filter.destroy.

Doc from jakarta.servlet.Filter.destroy.

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.

This method gives the filter an opportunity to clean up any resources that are being held (for example, memory, file handles, threads) and make sure that any persistent state is synchronized with the filter's current state in memory. The default implementation is a NO-OP.

Annotations
@Override
doFilterback to summary
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException

Implements jakarta.servlet.Filter.doFilter.

Doc from jakarta.servlet.Filter.doFilter.

The doFilter method of the Filter is called by the container each time a request/response pair is passed through the chain due to a client request for a resource at the end of the chain. The FilterChain passed in to this method allows the Filter to pass on the request and response to the next entity in the chain.

A typical implementation of this method would follow the following pattern:-
1. Examine the request
2. Optionally wrap the request object with a custom implementation to filter content or headers for input filtering
3. Optionally wrap the response object with a custom implementation to filter content or headers for output filtering
4. a) Either invoke the next entity in the chain using the FilterChain object (chain.doFilter()),
4. b) or not pass on the request/response pair to the next entity in the filter chain to block the request processing
5. Directly set headers on the response after invocation of the next entity in the filter chain.

Parameters
request:ServletRequest

The request to process

response:ServletResponse

The response associated with the request

chain:FilterChain

Provides access to the next filter in the chain for this filter to pass the request and response to for further processing

Annotations
@Override
Exceptions
IOException:
if an I/O error occurs during this filter's processing of the request
ServletException:
if the processing fails for any other reason
getActualDurationInSecondsback to summary
public int getActualDurationInSeconds()
Returns:int

the actual duration of a time bucket in milliseconds

getActualRequestsback to summary
public int getActualRequests()
Returns:int

the actual maximum allowed requests per time bucket

initback to summary
public void init() throws ServletException

Overrides jakarta.servlet.GenericFilter.init.

Doc from jakarta.servlet.GenericFilter.init.

Convenience method for sub-classes to save them having to call super.init(config). This is a NO-OP by default.

Annotations
@Override
Exceptions
ServletException:
If an exception occurs that interrupts the Filter's normal operation