Class RateLimitFilter
- java.lang.Object
-
- org.apache.catalina.filters.FilterBase
-
- org.apache.catalina.filters.RateLimitFilter
-
- All Implemented Interfaces:
Filter
public class RateLimitFilter extends FilterBase
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 RateLimiter implementation can be set via the
className
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. You can specify a different class as long as it implements theorg.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
tofalse
to disable the termination of requests that exceed the allowed limit. Then your application code can inspect the Request Attributeorg.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 a 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.
-
-
Field Summary
Fields Modifier and Type Field Description static int
DEFAULT_BUCKET_DURATION
Default duration in seconds.static int
DEFAULT_BUCKET_REQUESTS
Default number of requests per duration.static boolean
DEFAULT_ENFORCE
Default value for enforce.static boolean
DEFAULT_EXPOSE_HEADERS
Default value of the expose headers flag.static int
DEFAULT_STATUS_CODE
Default status code to return if requests per duration is exceeded.static java.lang.String
DEFAULT_STATUS_MESSAGE
Default status message to return if requests per duration is exceeded.static java.lang.String
HEADER_RATE_LIMIT
Name of the rate limit remaining quota header field defined in RateLimit header fields for HTTP (draft).static java.lang.String
HEADER_RATE_LIMIT_POLICY
Name of the rate limit policy header field defined in RateLimit header fields for HTTP (draft).static java.lang.String
RATE_LIMIT_ATTRIBUTE_COUNT
Request attribute that will contain the number of requests per duration.
-
Constructor Summary
Constructors Constructor Description RateLimitFilter()
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description void
destroy()
Called by the web container to indicate to a filter that it is being taken out of service.void
doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
ThedoFilter
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.protected Log
getLogger()
void
init(FilterConfig filterConfig)
Iterates over the configuration parameters and either logs a warning, or throws an exception for any parameter that does not have a matching setter in this filter.protected boolean
isConfigProblemFatal()
Determines if an exception when calling a setter or an unknown configuration attribute triggers the failure of the this filter which in turn will prevent the web application from starting.void
setBucketDuration(int bucketDuration)
void
setBucketRequests(int bucketRequests)
void
setEnforce(boolean enforce)
void
setExposeHeaders(boolean exposeHeaders)
void
setPolicyName(java.lang.String policyName)
void
setRateLimitClassName(java.lang.String rateLimitClassName)
void
setStatusCode(int statusCode)
void
setStatusMessage(java.lang.String statusMessage)
-
-
-
Field Detail
-
DEFAULT_BUCKET_DURATION
public static final int DEFAULT_BUCKET_DURATION
Default duration in seconds.- See Also:
- Constant Field Values
-
DEFAULT_BUCKET_REQUESTS
public static final int DEFAULT_BUCKET_REQUESTS
Default number of requests per duration.- See Also:
- Constant Field Values
-
DEFAULT_ENFORCE
public static final boolean DEFAULT_ENFORCE
Default value for enforce.- See Also:
- Constant Field Values
-
DEFAULT_EXPOSE_HEADERS
public static final boolean DEFAULT_EXPOSE_HEADERS
Default value of the expose headers flag.- See Also:
- Constant Field Values
-
HEADER_RATE_LIMIT_POLICY
public static final java.lang.String HEADER_RATE_LIMIT_POLICY
Name of the rate limit policy header field defined in RateLimit header fields for HTTP (draft).- See Also:
- Constant Field Values
-
HEADER_RATE_LIMIT
public static final java.lang.String HEADER_RATE_LIMIT
Name of the rate limit remaining quota header field defined in RateLimit header fields for HTTP (draft).- See Also:
- Constant Field Values
-
DEFAULT_STATUS_CODE
public static final int DEFAULT_STATUS_CODE
Default status code to return if requests per duration is exceeded.- See Also:
- Constant Field Values
-
DEFAULT_STATUS_MESSAGE
public static final java.lang.String DEFAULT_STATUS_MESSAGE
Default status message to return if requests per duration is exceeded.- See Also:
- Constant Field Values
-
RATE_LIMIT_ATTRIBUTE_COUNT
public static final java.lang.String RATE_LIMIT_ATTRIBUTE_COUNT
Request attribute that will contain the number of requests per duration.- See Also:
- Constant Field Values
-
-
Method Detail
-
setBucketDuration
public void setBucketDuration(int bucketDuration)
-
setBucketRequests
public void setBucketRequests(int bucketRequests)
-
setEnforce
public void setEnforce(boolean enforce)
-
setStatusCode
public void setStatusCode(int statusCode)
-
setStatusMessage
public void setStatusMessage(java.lang.String statusMessage)
-
setRateLimitClassName
public void setRateLimitClassName(java.lang.String rateLimitClassName)
-
setExposeHeaders
public void setExposeHeaders(boolean exposeHeaders)
-
setPolicyName
public void setPolicyName(java.lang.String policyName)
-
isConfigProblemFatal
protected boolean isConfigProblemFatal()
Description copied from class:FilterBase
Determines if an exception when calling a setter or an unknown configuration attribute triggers the failure of the this filter which in turn will prevent the web application from starting.- Overrides:
isConfigProblemFatal
in classFilterBase
- Returns:
true
if a problem should trigger the failure of this filter, elsefalse
-
init
public void init(FilterConfig filterConfig) throws ServletException
Description copied from class:FilterBase
Iterates over the configuration parameters and either logs a warning, or throws an exception for any parameter that does not have a matching setter in this filter.- Specified by:
init
in interfaceFilter
- Overrides:
init
in classFilterBase
- Parameters:
filterConfig
- The configuration information associated with the filter instance being initialised- Throws:
ServletException
- ifFilterBase.isConfigProblemFatal()
returnstrue
and a configured parameter does not have a matching setter
-
doFilter
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws java.io.IOException, ServletException
Description copied from interface:jakarta.servlet.Filter
ThedoFilter
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
- The request to processresponse
- The response associated with the requestchain
- Provides access to the next filter in the chain for this filter to pass the request and response to for further processing- Throws:
java.io.IOException
- if an I/O error occurs during this filter's processing of the requestServletException
- if the processing fails for any other reason
-
destroy
public void destroy()
Description copied from interface:jakarta.servlet.Filter
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.
-
getLogger
protected Log getLogger()
- Specified by:
getLogger
in classFilterBase
-
-