]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
http: have a headers limit
authorPhilippe Antoine <pantoine@oisf.net>
Mon, 9 Sep 2024 07:34:39 +0000 (09:34 +0200)
committerVictor Julien <vjulien@oisf.net>
Fri, 27 Sep 2024 08:34:21 +0000 (10:34 +0200)
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 bb714c917878ed13aab9e314a026f71570e84f37)

configure.ac
doc/userguide/configuration/suricata-yaml.rst
rules/http-events.rules
src/app-layer-htp.c
src/app-layer-htp.h
suricata.yaml.in

index 1eaf7c11a3fb3715be96d0ffaa7f90ddba6f8ad5..01c48196470c228843e9f5909c01dbef7d1dbd7d 100644 (file)
         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
             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:"
index 6eea5e8793121b7e62f5ee908cc7aca8ea2e12e7..7bcabdb77fedde6a1fb4d217294dd20bff8ce9e9 100644 (file)
@@ -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.
 ::
index 8c7763f1b661d49e7843564bdde5d90ce5ed808c..41f707279e9cdd669e923d60820d63aaf3ad5f7f 100644 (file)
@@ -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
index 7351797046d6133372141f449f80096c2e9bde7b..a02d9202aa67bede7e4da934c3b3405dcb2789ae 100644 (file)
@@ -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) {
index f200ea1d39e7121698a24c42d09cfd86898083e3..7a87d49c35846e51721ae93ee902dd6086da3780 100644 (file)
@@ -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,
index 8bfbaac356c75ed620e5d72c811b0284e428c94b..ba9005dc3e4ce37c667ca055f85c6362895c179b 100644 (file)
@@ -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: