mod_antiloris
mod_antiloris copied to clipboard
Mitigate Slowloris DoS attacks by preventing too many connections from an IP address
mod_antiloris
mod_antiloris is an Apache HTTP Server module that helps to mitigate Slowloris denial of service (DoS) attacks. It works by preventing new connections from the same IP address after the connection count of the IP exceeds a configurable limit.
Why mod_antiloris?
Table of Contents
- mod_antiloris
- Table of Contents
- Installation
- Install Script
- Interactive Install
- Non-Interactive Install
- Uninstall
- Tested Platforms
- Pre-Built Module
- Compilation with CMake
- Compilation of Older Versions
- Install Script
- Usage
- Example Mitigation
- Configuration
- Directives from Older Versions
- Aliases
- Configuration Examples
- Syntax
- IP Addresses
- Examples
- Versioning
- Examples
- IP Addresses
- Backwards Compatibility
- Comparison with Other Mitigation Strategies
- mod_antiloris vs. mod_reqtimeout
- mod_antiloris vs. mod_qos
- mod_antiloris vs. mod_noloris
- mod_antiloris vs. ModSecurity
- mod_antiloris vs. mod_evasive
- mod_antiloris vs. mod_limitipconn
- Testing
Installation
Install Script
There is a shell script that automates the installation of mod_antiloris, courtesy of @filippolauria.
Interactive Install
wget -q https://raw.githubusercontent.com/Deltik/mod_antiloris/main/install-antiloris.sh && chmod +x install-antiloris.sh && ./install-antiloris.sh
This script simplifies the installation process by cloning this repository, compiling the module, and configuring the necessary files for seamless integration with the Apache HTTP Server.
Non-Interactive Install
The installer can also be run non-interactively:
wget -qO- https://raw.githubusercontent.com/Deltik/mod_antiloris/main/install-antiloris.sh | sh -s - --accept-disclaimer
Uninstall
The installer can uninstall and remove the configuration files for mod_antiloris with the --uninstall option:
wget -qO- https://raw.githubusercontent.com/Deltik/mod_antiloris/main/install-antiloris.sh | sh -s - --uninstall
Tested Platforms
The script has been tested on the following platforms:
- Ubuntu 18.04
- Ubuntu 24.04
- Debian 12
- AlmaLinux 8
- AlmaLinux 9
Pre-Built Module
Pre-built modules might exist on the project's releases page. If the module is available in binary format (mod_antiloris.so), you can install it by:
- Copying
mod_antiloris.soto your Apache modules folder (/usr/lib64/apache2/modules/on some Linux systems) and - Adding the following directive to your Apache configuration file (
httpd.confor somewhere that isIncluded like/etc/apache2/conf.modules.d/mod_antiloris.conf):LoadModule antiloris_module modules/mod_antiloris.so
Compilation with CMake
(>= 0.7)
mod_antiloris has more dependencies than in previous versions, but building isn't much harder. Just make sure you have cmake installed in addition to the Apache development tools. You should also have git so that CMake can download the rest of the dependencies automatically. To be exact:
- Suggested dependency installation for Debian/Ubuntu:
apt install -y apache2-dev cmake git - Suggested dependency installation for RHEL/CentOS:
- With
dnf:dnf install -y epel-release && dnf install -y gcc /usr/bin/apxs make cmake3 git - With
yum:yum install -y epel-release && yum install -y gcc /usr/bin/apxs make cmake3 git
- With
- Suggested dependency installation for Fedora:
dnf install -y gcc /usr/bin/apxs make cmake git redhat-rpm-config
mod_antiloris is most easily installed by running these commands on your Apache server:
git clone https://github.com/Deltik/mod_antiloris.git
cd mod_antiloris
# Optional: git checkout "v${ANTILORIS_VERSION}"
# Replace ${ANTILORIS_VERSION} with the desired version of this software.
# RHEL/CentOS 6 and 7 compatibility
if type cmake3 > /dev/zero 2>&1; then alias cmake="cmake3"; fi
cmake .
make
apxs -i -a -n antiloris mod_antiloris.so
The output of the apxs command shows where the module was installed, so you can use that information to uninstall the module, if desired.
Compilation of Older Versions
(< 0.7)
mod_antiloris is most easily installed by copying or downloading the source code to your Apache server and running the following command:
apxs -a -i -c mod_antiloris.c
The output of the command shows where the module was installed, so you can use that information to uninstall the module, if desired.
Usage
mod_antiloris works best in combination with mod_reqtimeout, because:
- mod_reqtimeout drops connections if they are too slow but is vulnerable when a client opens a lot of connections and prevents legitimate connections during the timeout period.
- mod_antiloris prevents a client from hogging up connection slots but does not drop slow connections.
Using both modules at the same time protects against both kinds of DoS offenders.
Example Mitigation
LoadModule reqtimeout_module modules/mod_reqtimeout.so
<IfModule mod_reqtimeout>
RequestReadTimeout header=20-40,MinRate=500 body=20-40,MinRate=500
</IfModule>
LoadModule antiloris_module modules/mod_antiloris.so
<IfModule antiloris_module>
IPTotalLimit 16
ExemptIPs 127.0.0.1 ::1
</IfModule>
The above example mitigates Slowloris DoS attacks by:
- Using mod_reqtimeout to drop connections that don't meet the data transfer rate requirement and
- Using mod_antiloris to prevent more than 16 concurrent connections from the same IP.
Configuration
| Directive | Default | Description | Version |
|---|---|---|---|
IPTotalLimit |
30 |
Maximum simultaneous connections in any state per IP address. If set to 0, this limit does not apply. This limit takes precedence over all other limits. |
>= 0.7 |
IPOtherLimit |
10 |
Maximum simultaneous idle connections per IP address. If set to 0, this limit does not apply. |
>= 0.6 |
IPReadLimit |
10 |
Maximum simultaneous connections in READ state per IP address. If set to 0, this limit does not apply. |
>= 0.6 |
IPWriteLimit |
10 |
Maximum simultaneous connections in WRITE state per IP address. If set to 0, this limit does not apply. |
>= 0.6 |
ExemptIPs |
none | Space-delimited list of IPv4 and IPv6 addresses, ranges, or CIDRs which should not be subjected to any limits by this module. | >= 0.8 |
Directives from Older Versions
These directives no longer apply to the latest version of this module:
| Directive | Default | Description | Version |
|---|---|---|---|
IPReadLimit |
10 |
Maximum simultaneous connections in READ state per IP address. If set to 0, this limit does not apply. |
>= 0.1, < 0.5.2 |
IPReadLimit |
20 |
Maximum simultaneous connections in READ state per IP address. If set to 0, this limit does not apply. |
= 0.5.2 |
LocalIPs |
none | List of IPs (separated by spaces), the connections of which are always allowed (not subjected to any limits) | ~> 0.6.0 |
WhitelistIPs |
none | Space-delimited list of IPv4 and IPv6 addresses, ranges, or CIDRs which should not be subjected to any limits by this module. | ~> 0.7.0 |
Aliases
| Directive Alias | Is Equivalent To | Applicable Version |
|---|---|---|
LocalIPs |
WhitelistIPs |
~> 0.7.0 |
LocalIPs |
ExemptIPs |
>= 0.8 |
WhitelistIPs |
ExemptIPs |
>= 0.8 |
Configuration Examples
(>= 0.6) Allows 10 open connections in each state for a total of 30 concurrent connections per IP address,
and ignores limits for IP addresses 127.0.0.1 and ::1:
LoadModule antiloris_module modules/mod_antiloris.so
<IfModule antiloris_module>
IPOtherLimit 10
IPReadLimit 10
IPWriteLimit 10
LocalIPs 127.0.0.1 ::1
</IfModule>
(>= 0.7) Per IP address, allows 8 open connections in each state, but no more than 16 connections of any state:
LoadModule antiloris_module modules/mod_antiloris.so
<IfModule antiloris_module>
IPTotalLimit 16
IPOtherLimit 8
IPReadLimit 8
IPWriteLimit 8
</IfModule>
(>= 0.8) Default mitigation settings, but exclude Cloudflare IP addresses and localhost IP addresses:
LoadModule antiloris_module modules/mod_antiloris.so
<IfModule antiloris_module>
ExemptIPs 127.0.0.1 ::1 173.245.48.0/20 103.21.244.0/22 103.22.200.0/22 103.31.4.0/22 141.101.64.0/18 108.162.192.0/18 190.93.240.0/20 188.114.96.0/20 197.234.240.0/22 198.41.128.0/17 162.158.0.0/15 104.16.0.0/13 104.24.0.0/14 172.64.0.0/13 131.0.72.0/22 2400:cb00::/32 2606:4700::/32 2803:f800::/32 2405:b500::/32 2405:8100::/32 2a06:98c0::/29 2c0f:f248::/32
</IfModule>
Syntax
IP Addresses
For directives that accept IP addresses, this module matches IPv4 and IPv6 addresses in the form of:
- (
>= 0.6) Individual addresses (e.g.127.0.0.1matches only127.0.0.1), - (
>= 0.7) Hyphenated ranges (e.g.127.0.1.1-127.0.1.3matches127.0.1.1,127.0.1.2, and127.0.1.3), or - (
>= 0.7) CIDR notation (e.g.127.0.2.0/30matches127.0.2.0,127.0.2.1,127.0.2.2, and127.0.2.3).
Examples
Here are more examples:
127.0.0.1matches the individual IPv4 address127.0.0.1.192.168.0.100-192.168.0.200inclusively matches the IPv4 range192.168.0.100to192.168.0.200.10.0.0.0/8inclusively matches the IPv4 range from10.0.0.0to10.255.255.255.::1matches the individual IPv6 address0:0:0:0:0:0:0:0001.::ffff:ac10:0-::ffff:ac10:8inclusively matches the IPv6 range0:0:0:0:0:ffff:ac10:0to0:0:0:0:0:ffff:ac10:8.FD12:3456:789A:1::/64inclusively matches the IPv6 rangefd12:3456:789a:0001:0:0:0:0tofd12:3456:789a:0001:ffff:ffff:ffff:ffff.
Versioning
This software uses Semantic Versioning. From a version number MAJOR.MINOR.PATCH:
MAJORincreases when behavior changes that breaks how previous versions worked,MINORincreases when new features are added while being compatible with how previous versions worked, andPATCHincreases when bugs are fixed without breaking how previous versions worked.
In the documentation, version constraints are used to indicate to which versions the piece of documentation applies:
>=means starting from this version,>means after this version,<=means up to and including this version,<means up to but not including this version,=means this version only, and~>means this version and any newer versions after the last point (.).
Examples
>= 1.5matches version1.5.0and higher.> 1.4matches version1.4.1and higher.<= 1.3.1matches version1.3.1,1.3.0,1.3, and lower.< 1.4matches any version lower than1.4.= 1.0matches version1.0and1.0.0.~> 1.4is the same as>= 1.4, < 2.~> 1.3.0is the same as>= 1.3.0, < 1.4.~> 2is the same as>= 2.0.0.= 1.0, = 1.1, = 1.2, = 1.3matches only versions1.0,1.1,1.2,1.3, and their.0PATCHversions.
Backwards Compatibility
This module is a fork of NewEraCracker's mod_antiloris, which itself is a fork of mind04's mod_antiloris.
mod_antiloris versions < 1 are intended to be backwards-compatible with both upstream projects, but the default directive values may have changed.
Comparison with Other Mitigation Strategies
mod_antiloris vs. mod_reqtimeout
mod_reqtimeout effectively kicks slow connections, but it does not prevent those connections from being made in the first place. This means that during mod_reqtimeout's timeout grace period, Apache's connection slots can be filled up.
mod_antiloris prevents too many slow connections made from one client. This addresses the drawback of mod_reqtimeout. For the best DoS mitigation, mod_antiloris should be combined with mod_reqtimeout.
mod_antiloris vs. mod_qos
At the time of writing, mod_qos only works on Apache 2.2 with MPM worker. mod_qos is probably better than mod_antiloris on Apache 2.2 and MPM worker, but it seems to be broken on newer Apache major versions and on other MPMs.
mod_antiloris vs. mod_noloris
mod_noloris is based on mod_antiloris = 0.3, but it runs an IP ban check on a (default) 10-second timer instead of on every request like in mod_antiloris. This leaves a window of time for a Slowloris DoS to make Apache unresponsive.
mod_noloris also has other drawbacks:
- Banned IPs are not unbanned until the server is restarted, which means legitimate requests can be banned indefinitely if the client is sufficiently unlucky.
- Only connections in the
SERVER_BUSY_READstate are counted, so variant Slowloris attacks using a different state would be immune to mitigations. - A more clever Slowloris attacker can anticipate the timer to make their attack invisible to mod_noloris.
- Banned IPs are scanned sequentially on every request (linear time) instead of looked up in a hash table (constant time). The bigger the banlist, the larger the performance penalty upon every request, even if the request is legitimate.
Although mod_noloris in theory consumes less time and resources on every request (if the banlist is empty) due to the deferred connection scan, the savings are negligible. On a test server with 150 connection slots, mod_antiloris configured with an allowlist of Cloudflare IP addresses had practically no effect on the response time. The test was conducted by requesting a static HTML file 100000 times with 10 concurrent requests to download the entire file. Data summary:
| Slowloris mitigation | N | min (s) | q1 (s) | median (s) | q3 (s) | max (s) | mean (s) | stddev (s) |
|---|---|---|---|---|---|---|---|---|
| none | 100000 | 0.000573 | 0.001035 | 0.001123 | 0.001231 | 0.008474 | 0.001170 | 0.000300 |
mod_antiloris = 0.7.2 |
100000 | 0.000539 | 0.001068 | 0.001166 | 0.001287 | 0.010362 | 0.001212 | 0.000314 |
mod_antiloris = 0.8.0 |
100000 | 0.000510 | 0.001054 | 0.001146 | 0.001260 | 0.011931 | 0.001197 | 0.000312 |
mod_antiloris vs. ModSecurity
ModSecurity depends on other sources to decide whether to block a connection. At the time of writing, the OWASP ModSecurity Core Rule Set V3.0 has a rule to block too many requests to dynamic resources, but there is nothing by default to block Slowloris specifically.
It is possible to use the HTTP 408 returned by mod_reqtimeout to increment a denial-of-service counter in ModSecurity, but this suffers from the same drawbacks as mod_reqtimeout.
mod_antiloris vs. mod_evasive
mod_evasive does nothing to mitigate Slowloris. It is designed to return HTTP 403 to the client if the client makes too many requests, but it assumes that the client is willing to receive the response. Slowloris, of course, doesn't, so the connection slots remain occupied.
mod_antiloris vs. mod_limitipconn
mod_limitipconn is conceptually similar to mod_antiloris, but mod_limitipconn hooks too late and can't mitigate Slowloris. It is designed to return HTTP 503 to the client if the client makes too many connections, but it assumes that the client is willing to receive the response. Slowloris, of course, doesn't, so the connection slots remain occupied.
Testing
(>= 0.7)
After generating the build files from cmake, tests can simply be run with this command:
make test
