]> 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>
Wed, 25 Sep 2024 08:42:48 +0000 (10:42 +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.

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 03ffadd89b27581fed7217ccc68f1b715029a36d..413cda2aebc7e3fe42bebc9fb1449128a9722a43 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 24233b2bb79e222fbb5ec0b432f47f85a4c71f94..3dfc950ec64101e037c3b20abd54200a42e817b6 100644 (file)
@@ -1588,6 +1588,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 b5cce76bf235c645a0b5a72f94522520ff6b3493..e08d84eb46cdb9d2baabac47979aaa1366041dfb 100644 (file)
@@ -93,4 +93,7 @@ alert http any any -> any any (msg:"SURICATA HTTP failed protocol change"; flow:
 
 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;)
 
-# next sid 2221056
+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 e327696ab027a7efdf061ad741fe31c513af83b7..3f3037ca30a1c47282bae63d4e259b2af3915ef9 100644 (file)
@@ -170,6 +170,9 @@ SCEnumCharMap http_decoder_event_table[] = {
     { "REQUEST_CHUNK_EXTENSION", HTTP_DECODER_EVENT_REQUEST_CHUNK_EXTENSION },
     { "REQUEST_LINE_MISSING_PROTOCOL", HTTP_DECODER_EVENT_REQUEST_LINE_MISSING_PROTOCOL },
 
+    { "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 },
@@ -629,6 +632,8 @@ struct {
             HTTP_DECODER_EVENT_DUPLICATE_CONTENT_LENGTH_FIELD_IN_RESPONSE },
     { "Request chunk extension", HTTP_DECODER_EVENT_REQUEST_CHUNK_EXTENSION },
     { "Request line: missing protocol", HTTP_DECODER_EVENT_REQUEST_LINE_MISSING_PROTOCOL },
+    { "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]))
@@ -2101,6 +2106,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.
@@ -2461,6 +2470,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, 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 9c39ba393ffd96af5bfc3db066677eef098dc0e5..55ff9c9b9fce60dd68e5826601a206bc768e6b40 100644 (file)
@@ -126,6 +126,8 @@ enum {
     HTTP_DECODER_EVENT_RANGE_INVALID,
     HTTP_DECODER_EVENT_REQUEST_CHUNK_EXTENSION,
     HTTP_DECODER_EVENT_REQUEST_LINE_MISSING_PROTOCOL,
+    HTTP_DECODER_EVENT_REQUEST_TOO_MANY_HEADERS,
+    HTTP_DECODER_EVENT_RESPONSE_TOO_MANY_HEADERS,
 
     /* suricata errors/warnings */
     HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR,
index 3e73623c4b21388658e8ddc2ddf17bdc2cd760e5..013411ece4e375528222b486ea68aafa589fb3dc 100644 (file)
@@ -1098,6 +1098,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: