-
Notifications
You must be signed in to change notification settings - Fork 103
HTTP security
Frang is an internal Tempesta module for enforcing security limits to prevent Web attacks and mitigate HTTP(S) (D)DoS attacks. It uses static limiting and checking of ingress HTTP requests.
Learn how to configure limits when migrating from NGINX.
Frang limits are split into two parts: connection level limits and message level limits. The rules how the limits can be defined and the ways how malicious traffic can be blocked differ for both of the types.
The main portion of it's logic is on the HTTP layer, so it's recommended that
ip_block
option (enabled by default) is used to block malicious users
at IP layer.
The limits are described inside section frang_limits
. The section may appear:
-
at top level - to configure connection level limits and to override default values for message level limits for vhosts below this directive section. May appear multiple times. Implicit
default
vhost will use the last effective set of the message level limits. -
inside
vhost
section - to override defaults for locations of the current vhost below this directive section. May appear multiple times. Implicitdefault
location of the vhost will use the last effective set of the limits. -
inside
location
section - to configure message level limits for the current location.
Even if section frang_limits
is not stated in the configuration file, the
whole Frang subsystem is enabled with defaults.
The global Frang limits must be specified before all vhosts, which must inherit the global limits.
See examples below how the limits can be configured and overridden.
The Frang limits are calculated inside sliding windows, mostly window size equals to 1 second, but some limits have configurable window size.
Some of the limits (all *_burst
limits and request_rate
) work using a
history ring buffer of 8 slots each of 125ms, so the tracking history is
1 second. This implies the property of amnesia: if a client has issued say
1000 requests immediately with only 10 requests per second in a rate limit,
then after 1 second it still can be normally serviced unless ip_block on
was specified.
Minor bursts also can actually exceed the specified limit, but not more than 2 times. This may happen if the actual burst is tracked in 2 consequent slots in the history buffer instead of one. Keep this in mind during configuration and troubleshooting.
Connection level limits are applied at very early processing stages, when there is not enough data to determine target vhost. E.g. when a client establishes connections or until full set of request headers is received. Thus connection level limits are configured only globally.
Limits of this type can not work with
block_action
,
which sends HTTP error messages, since a connection under inspection of
a limit from this section is either not yet established or is going to be
terminated, i.e. there is nowhere to send an error message.
If the limit is reached, then Tempesta FW resets a connection (sends TCP RST
segment). A client can try to reestablish a connection and it can be serviced
if it satisfies all the limits this time and unless the ip_block on
is specified.
ip_block [off|on]
If disabled client connection(-s) are closed of security events. If enabled
client connections are closed and client will be blocked by it's IP address.
Defaults: off
- disabled.
request_rate [NUM]
Maximum number of requests per second from a single client across all it's
connections. 0
to disable the limit.
Defaults: 0
(disabled).
request_burst [NUM]
Maximum burst of request rate on short periods of time (125 ms). The option
can be used independently from request_rate
limit. 0
to disable the limit.
Defaults: 0
(disabled).
connection_rate [NUM]
Maximum number of new connection openings per second from a single client.
0
to disable the limit.
Defaults: 0
(disabled).
connection_burst [NUM]
Maximum burst of new connection openings rate on short periods of time (125 ms)
from a single client.
Having that browsers may issue about 6 connections simultaneously to a host,
a reasonable value for the limit is 10-20
.
The option can be used independently from connection_rate
limit.
0
to disable the limit.
Defaults: 0
(disabled).
concurrent_connections [NUM]
Maximum number of new concurrent connections from a single client.
0
to disable the limit.
Defaults: 0
(disabled).
client_header_timeout [TIME]
Maximum time in seconds to receive the whole HTTP headers set of incoming
request.0
to disable the limit.
Defaults: 0
(disabled).
client_body_timeout [TIME]
Maximum time in seconds to receive the whole HTTP body of incoming
request.0
to disable the limit.
Defaults: 0
(disabled).
http_header_chunk_cnt [NUM]
HTTP messages can be sent by parts. The option controls maximum number of parts
(chunks) in the request header part.0
to disable the limit.
Defaults: 0
(disabled).
http_body_chunk_cnt [NUM]
HTTP messages can be sent by parts. The option controls maximum number of parts
(chunks) in the request body part.0
to disable the limit.
Defaults: 0
(disabled).
tls_connection_rate [NUM]
Maximum number of new TLS sessions established with a single client per second.
Establishing a new TLS connection (handshake
processing) requires much more computations on server side than on resuming a
previous one. Malicious clients can DDoS server constantly establishing
thousands new TLS connection. With the option Tempesta blocks new connections
with a client, if it establishes new TLS connections too often.
Defaults: 0
(disabled).
tls_connection_burst [NUM]
disable the limit.
Maximum burst of new TLS sessions rate on short periods of time (125 ms) from a single client.
The option can be used independently from tls_connection_rate
limit. 0
to
Defaults: 0
(disabled).
tls_incomplete_connection_rate [NUM]
Block client if it fails more than NUM
TLS handshakes per second.
Defaults: 0
(disabled).
Message level limits are accounted on later processing stages when target vhost and location are already known. Such request can be configured globally as defaults, per vhost and per location.
These limits can trigger both the blocking on the IP layer (with ip_block
option)
or sending an HTTP error message (with
block_action
).
However, bear in mind how both of the options interact with each other, i.e. if both
of them are enabled like in the wrong configuration:
frang_limits {
ip_block on;
http_ct_required true;
}
block_action attack reply;
If the http_ct_required
rule is triggered, then Frang immediately calls the
IP filter, which
- resets the client TCP connection with
RST
segment and - blocks the client IP on the Netfilter layer.
This means that we can not send any data, including an error HTTP response,
to the client. In other words, in this configuration
block_action
statement for triggeredhttp_ct_required
rule is just ignored.
http_uri_len [NUM]
Maximum length of URI part in a request.0
to disable the limit.
Defaults: 0
(disabled).
http_field_len [NUM]
Maximum length of a single HTTP header field in an incoming request. This limit
is helpful to prevent
HTTP Response Splitting
and other attacks using arbitrary injections in HTTP headers.
0
to disable the limit.
Defaults: 0
(disabled).
http_body_len [NUM]
Maximum length of HTTP message body of incoming request. 0
to disable the limit.
Defaults: 1073741824
(1 Gb).
http_header_cnt [NUM]
Maximum number of HTTP headers in a HTTP message. 0
to disable the limit.
Defaults: 0
(disabled).
http_host_required [true|false]
A request has an explicit authority declaration. The authority must not be an IP
address. Host:
header is a mandatory for HTTP/1.1 requests, but if the URI
has a full form with authority provided, it must have the same value as Host:
header. In HTTP/2 requests at least one of headers :authority
or host:
must be provided, the headers must have the same values, if both are provided
simultaneously. Also when Forwarded:
header with host
parameter is provided,
it also must be the same as :authority
and host:
. In case of multiple Forwarded:
headers were provided, only first header need to match.
Port, requested in authority, must be equal to the TCP port, where request was
received. The only exception is the protocols below HTTP/1.1, since an authority is not
defined for them, they must not provide authority headers.
Defaults: true
.
Notice While mismatching of SNI and virtual host names is the common source of vhost confusion Tempesta FW does not validate SNI against virtual host name in run time. Instead, it validates Subject Alternative Names (SAN) on certificate loading for the vhost and later, in run time, validates SNI against the available SANs.
http_ct_required [true|false]
Require presence of Content-Type
header in a request.
Defaults: false
.
http_trailer_split_allowed [true|false]
Allow the same header appear in both request header part and chunked trailer
part.
Defaults: false
.
http_methods METHOD [METHOD]...
The list of accepted HTTP methods (see
OWASP recommendations).
Defaults: limit disabled (all methods are allowed).
Example: http_methods get post head;
http_ct_vals ["CONTENT_TYPE"]...
The list of accepted values for Content-Type
header. Note that the full types must
be specified, i.e. if you need to allow text/html
and text/plain
, then you
should specify http_ct_vals "text/plain" "text/html"
, http_ct_vals "text/*"
won't match the required values.
Defaults: limit disabled (all values are allowed).
Example: http_ct_vals "text/plain" "text/html";
http_resp_code_block RESPONSE_CODE [RESPONSE_CODE]... LIMIT TIME_FRAME_IN_SECONDS
Block client if it cause to many errors on backend server in the selected
time frame (responses from the Tempesta cache is not counted for this limit).
See Password crackers section.
RESPONSE_CODE
- status code in the response from backend server.
LIMIT
- responses count.
TIME_FRAME_IN_SECONDS
- size of sliding window to count the limit.
Defaults: limit disabled.
Example: http_resp_code_block 403 404 502 20 5;
http_method_override_allowed [true|false]
The option controls how the requests with method override headers
(X-Http-Method
, X-Method-Override
, X-Http-Method-Override
) are processed.
Defaults: false.
If the option is disabled (defaults) such requests are blocked. If the option
is enabled, the overridden method is used as primary request method inside
request processing logic. The overridden method must be allowed by http_methods
directive, otherwise it will be blocked. Keep in mind that in all cases unsafe
method cannot override safe method (GET, HEAD, OPTIONS, TRACE, PROPFIND).
Example 1. Configure all Frang limits globally for all vhosts.
frang_limits {
request_rate 20;
request_burst 15;
connection_rate 8;
connection_burst 6;
concurrent_connections 8;
client_header_timeout 20;
client_body_timeout 10;
http_uri_len 1024;
http_field_len 256;
http_ct_required false;
http_methods get post head;
http_ct_vals "text/plain" "text/html";
http_header_chunk_cnt 10;
http_body_chunk_cnt 0;
http_resp_code_block 403 404 502 20 5;
}
# The `frang_limits` section is listed before vhosts definitions, thus the
# vhosts and all their locations will be using the limits defined above.
vhost crm.example.com {
...
}
vhost example.com {
...
}
...
Example 2. Global/connection-level vs per-vhost/message limits.
listen 192.168.100.4:443 proto=https;
srv_group default {
server 127.0.0.1:8080 conns_n=4;
}
vhost default {
tls_certificate /root/tempesta/etc/tfw-root.crt;
tls_certificate_key /root/tempesta/etc/tfw-root.key;
resp_hdr_set Strict-Transport-Security "max-age=31536000; includeSubDomains";
frang_limits {
http_methods GET;
http_uri_len 512;
http_resp_code_block 400 403 404 3 10;
}
proxy_pass default;
}
cache 0;
frang_limits {
client_header_timeout 20;
client_body_timeout 10;
http_header_chunk_cnt 10;
http_body_chunk_cnt 0;
}
block_action attack reply;
http_chain {
-> default;
}
Example 3. Overriding Frang limits default values.
# Any limits can be overridden, update just one to keep the example short.
frang_limits {
http_uri_len 1024;
}
vhost crm.example.com {
# No `frang_limits` section in this vhost, effective Frang configuration is:
# http_uri_len 1024;
...
}
frang_limits {
http_uri_len 2048;
}
# Frang configuration was updated, current defaults is:
# http_uri_len 2048;
vhost example.com {
location prefix "/img/" {
frang_limits {
http_uri_len 3096;
}
# Frang configuration was updated inside location, current defaults is:
# http_uri_len 3096;
}
location prefix "/video/" {
# Frang configuration was not updated inside location, keep using
# global defaults. Effective configuration is:
# http_uri_len 2048;
}
frang_limits {
http_uri_len 1024;
}
# Frang configuration was updated, current defaults for other locations is:
# http_uri_len 1024;
location prefix "/docs/" {
# Frang configuration was not updated inside location, keep using
# global defaults. Effective configuration is:
# http_uri_len 1024;
}
# Frang limits for implicit default location is:
# http_uri_len 1024;
}
vhost test-net.com {
# Frang settings was updated multiple times in vhost `example.com` section,
# but that changes doesn't affect global defaults. Effective configuration
# is:
# http_uri_len 2048;
}
...
Following configuration options define allowed character sets in various HTTP fields:
-
http_uri_brange - URI path. Note that Accept and Referer headers are also verified by the characters set.
-
http_token_brange - each header field value defined with 'token' by RFC 7230, e.g. unknown for Tempesta FW HTTP methods and HTTP headers, Connection or Transfer-Encoding extension values, Cookie name (note that value is processed with its own alphabet
http_cookie_brange
), E-Tag value. -
http_qetoken_brange - 'token' with DQUOTE and '=', e.g. Cache-Control, Pragma, and Keep-Alive headers extension values.
-
http_nctl_brange - 'non-control characters' for generic filed values defined by RFC 7230 Apendix B and RFC 5234 Apendix B.1. Currently used for HTTP date headers, such as Expires, Date, Last-Modified, and If-Modified-Since, extension values only.
-
http_xff_brange - X-Forwarded-For Node ID defined by RFC 7239.
-
http_etag_brange - ETag accepted characters set (RFC 7232 2.3).
-
http_cookie_brange - Cookie header values.
-
http_ctext_vchar_brange - 'ctext | VCHAR' headers, e.g. User-Agent.
Syntax for the directives is:
http_XXX_brange RANGES
, where RANGES
is a list of space separated ranges (integers in range [0-255])
or integers for single characters. Hex and decimal encodings are accepted.
Example:
http_uri_brange 0x2f 0x61-0x7a 48 0x2A;
HTTP Strict Transport Security (HSTS)
is defined in (RFC 6797) and can be
implemented just by adding Strict-Transport-Security
header to a required
vhost or location:
resp_hdr_set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Let's see a simple example to understand Tempesta filtering.
Run Tempesta FW with Frang configured and put some load onto the system to make Frang generate a blocking rule:
$ dmesg | grep frang
[tempesta] Warning: frang: connections max num. exceeded for 192.168.0.1: 9 (lim=8)
Frang's rate limiting calls the filter module that stores the blocked IPs in Tempesta DB, so now we can run some queries on the database (you can read more about tdbq):
# ./tdbq -a info
Tempesta DB version: 0.1.14
Open tables: filter
INFO: records=1 status=OK zero-copy
The table filter
contains all blocked IP addresses.