http: have a headers limit

Ticket: 7191

So as to avoid quadratic complexity in libhtp.
Make the limit configurable from suricata.yaml,
and have an event when network traffic goes over the limit.

(cherry picked from commit bb714c9178)
pull/11851/head
Philippe Antoine 1 year ago committed by Victor Julien
parent 34a4625156
commit ca8bf6e64c

@ -1602,6 +1602,7 @@
AC_CHECK_LIB([htp], [htp_config_set_compression_bomb_limit],AC_DEFINE_UNQUOTED([HAVE_HTP_CONFIG_SET_COMPRESSION_BOMB_LIMIT],[1],[Found htp_config_set_compression_bomb_limit function in libhtp]) ,,[-lhtp])
AC_CHECK_LIB([htp], [htp_config_set_compression_time_limit],AC_DEFINE_UNQUOTED([HAVE_HTP_CONFIG_SET_COMPRESSION_TIME_LIMIT],[1],[Found htp_config_set_compression_time_limit function in libhtp]) ,,[-lhtp])
AC_CHECK_LIB([htp], [htp_config_set_max_tx],AC_DEFINE_UNQUOTED([HAVE_HTP_CONFIG_SET_MAX_TX],[1],[Found htp_config_set_max_tx function in libhtp]) ,,[-lhtp])
AC_CHECK_LIB([htp], [htp_config_set_number_headers_limit],AC_DEFINE_UNQUOTED([HAVE_HTP_CONFIG_SET_HEADERS_LIMIT],[1],[Found htp_config_set_number_headers_limit function in libhtp]) ,,[-lhtp])
])
if test "x$enable_non_bundled_htp" = "xno"; then
@ -1627,6 +1628,7 @@
AC_DEFINE_UNQUOTED([HAVE_HTP_CONFIG_SET_COMPRESSION_BOMB_LIMIT],[1],[Assuming htp_config_set_compression_bomb_limit function in bundled libhtp])
AC_DEFINE_UNQUOTED([HAVE_HTP_CONFIG_SET_COMPRESSION_TIME_LIMIT],[1],[Assuming htp_config_set_compression_time_limit function in bundled libhtp])
AC_DEFINE_UNQUOTED([HAVE_HTP_CONFIG_SET_MAX_TX],[1],[Assuming htp_config_set_max_tx function in bundled libhtp])
AC_DEFINE_UNQUOTED([HAVE_HTP_CONFIG_SET_HEADERS_LIMIT],[1],[Assuming htp_config_set_number_headers_limit function in bundled libhtp])
else
echo
echo " ERROR: Libhtp is not bundled. Get libhtp by doing:"

@ -1540,6 +1540,10 @@ use of libhtp.
#compression-bomb-limit: 1 Mb
# Maximum time spent decompressing a single transaction in usec
#decompression-time-limit: 100000
# Maximum number of live transactions per flow
#max-tx: 512
# Maximum used number of HTTP1 headers in one request or response
#headers-limit: 1024
Other parameters are customizable from Suricata.
::

@ -91,4 +91,9 @@ alert http any any -> any any (msg:"SURICATA HTTP failed protocol change"; flow:
#alert http any any -> any any (msg:"SURICATA HTTP request chunk extension"; flow:established; app-layer-event:http.request_chunk_extension; classtype:protocol-command-decode; sid:2221054; rev:1;)
# next sid 2221055
#alert http any any -> any any (msg:"SURICATA HTTP request missing protocol"; flow:established,to_server; app-layer-event:http.request_line_missing_protocol; classtype:protocol-command-decode; sid:2221055; rev:1;)
alert http any any -> any any (msg:"SURICATA HTTP request too many headers"; flow:established,to_server; app-layer-event:http.request_too_many_headers; classtype:protocol-command-decode; sid:2221056; rev:1;)
alert http any any -> any any (msg:"SURICATA HTTP response too many headers"; flow:established,to_client; app-layer-event:http.response_too_many_headers; classtype:protocol-command-decode; sid:2221057; rev:1;)
# next sid 2221058

@ -168,6 +168,9 @@ SCEnumCharMap http_decoder_event_table[] = {
{ "RANGE_INVALID", HTTP_DECODER_EVENT_RANGE_INVALID },
{ "REQUEST_CHUNK_EXTENSION", HTTP_DECODER_EVENT_REQUEST_CHUNK_EXTENSION },
{ "REQUEST_TOO_MANY_HEADERS", HTTP_DECODER_EVENT_REQUEST_TOO_MANY_HEADERS },
{ "RESPONSE_TOO_MANY_HEADERS", HTTP_DECODER_EVENT_RESPONSE_TOO_MANY_HEADERS },
/* suricata warnings/errors */
{ "MULTIPART_GENERIC_ERROR", HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR },
{ "MULTIPART_NO_FILEDATA", HTTP_DECODER_EVENT_MULTIPART_NO_FILEDATA },
@ -642,6 +645,8 @@ struct {
{ "Ambiguous response C-L value",
HTTP_DECODER_EVENT_DUPLICATE_CONTENT_LENGTH_FIELD_IN_RESPONSE },
{ "Request chunk extension", HTTP_DECODER_EVENT_REQUEST_CHUNK_EXTENSION },
{ "Too many request headers", HTTP_DECODER_EVENT_REQUEST_TOO_MANY_HEADERS },
{ "Too many response headers", HTTP_DECODER_EVENT_RESPONSE_TOO_MANY_HEADERS },
};
#define HTP_ERROR_MAX (sizeof(htp_errors) / sizeof(htp_errors[0]))
@ -2521,6 +2526,10 @@ static void HTPConfigSetDefaultsPhase1(HTPCfgRec *cfg_prec)
#ifdef HAVE_HTP_CONFIG_SET_MAX_TX
#define HTP_CONFIG_DEFAULT_MAX_TX_LIMIT 512
htp_config_set_max_tx(cfg_prec->cfg, HTP_CONFIG_DEFAULT_MAX_TX_LIMIT);
#endif
#ifdef HAVE_HTP_CONFIG_SET_HEADERS_LIMIT
#define HTP_CONFIG_DEFAULT_HEADERS_LIMIT 1024
htp_config_set_number_headers_limit(cfg_prec->cfg, HTP_CONFIG_DEFAULT_HEADERS_LIMIT);
#endif
/* libhtp <= 0.5.9 doesn't use soft limit, but it's impossible to set
* only the hard limit. So we set both here to the (current) htp defaults.
@ -2884,6 +2893,17 @@ static void HTPConfigParseParameters(HTPCfgRec *cfg_prec, ConfNode *s,
/* set default soft-limit with our new hard limit */
SCLogConfig("Setting HTTP max-tx limit to %" PRIu32 " bytes", limit);
htp_config_set_max_tx(cfg_prec->cfg, (size_t)limit);
#endif
#ifdef HAVE_HTP_CONFIG_SET_HEADERS_LIMIT
} else if (strcasecmp("headers-limit", p->name) == 0) {
uint32_t limit = 0;
if (ParseSizeStringU32(p->val, &limit) < 0) {
FatalError("failed to parse 'headers-limit' "
"from conf file - %s.",
p->val);
}
SCLogConfig("Setting HTTP headers limit to %" PRIu32, limit);
htp_config_set_number_headers_limit(cfg_prec->cfg, limit);
#endif
} else if (strcasecmp("randomize-inspection-sizes", p->name) == 0) {
if (!g_disable_randomness) {

@ -129,6 +129,9 @@ enum {
HTTP_DECODER_EVENT_RANGE_INVALID,
HTTP_DECODER_EVENT_REQUEST_CHUNK_EXTENSION,
HTTP_DECODER_EVENT_REQUEST_TOO_MANY_HEADERS,
HTTP_DECODER_EVENT_RESPONSE_TOO_MANY_HEADERS,
/* suricata errors/warnings */
HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR,
HTTP_DECODER_EVENT_MULTIPART_NO_FILEDATA,

@ -1099,6 +1099,8 @@ app-layer:
#decompression-time-limit: 100000
# Maximum number of live transactions per flow
#max-tx: 512
# Maximum used number of HTTP1 headers in one request or response
#headers-limit: 1024
server-config:

Loading…
Cancel
Save