MEDIUM: http-ana: Add a proxy option to restrict chars in request header names
The "http-restrict-req-hdr-names" option can now be set to restrict allowed
characters in the request header names to the "[a-zA-Z0-9-]" charset.
Idea of this option is to not send header names with non-alphanumeric or
hyphen character. It is especially important for FastCGI application because
all those characters are converted to underscore. For instance,
"X-Forwarded-For" and "X_Forwarded_For" are both converted to
"HTTP_X_FORWARDED_FOR". So, header names can be mixed up by FastCGI
applications. And some HAProxy rules may be bypassed by mangling header
names. In addition, some non-HTTP compliant servers may incorrectly handle
requests when header names contain characters ouside the "[a-zA-Z0-9-]"
charset.
When this option is set, the policy must be specify:
* preserve: It disables the filtering. It is the default mode for HTTP
proxies with no FastCGI application configured.
* delete: It removes request headers with a name containing a character
outside the "[a-zA-Z0-9-]" charset. It is the default mode for
HTTP backends with a configured FastCGI application.
* reject: It rejects the request with a 403-Forbidden response if it
contains a header name with a character outside the
"[a-zA-Z0-9-]" charset.
The option is evaluated per-proxy and after http-request rules evaluation.
This patch may be backported to avoid any secuirty issue with FastCGI
application (so as far as 2.2).
diff --git a/src/cfgparse-listen.c b/src/cfgparse-listen.c
index d890295..e7cd651 100644
--- a/src/cfgparse-listen.c
+++ b/src/cfgparse-listen.c
@@ -2459,6 +2459,38 @@
}
} /* end while loop */
}
+ else if (strcmp(args[1], "http-restrict-req-hdr-names") == 0) {
+ if (kwm != KWM_STD) {
+ ha_alert("parsing [%s:%d]: negation/default is not supported for option '%s'.\n",
+ file, linenum, args[1]);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+
+ if (alertif_too_many_args(2, file, linenum, args, &err_code))
+ goto out;
+
+ if (*(args[2]) == 0) {
+ ha_alert("parsing [%s:%d] : missing parameter. option '%s' expects 'preserve', 'reject' or 'delete' option.\n",
+ file, linenum, args[1]);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+
+ curproxy->options2 &= ~PR_O2_RSTRICT_REQ_HDR_NAMES_MASK;
+ if (strcmp(args[2], "preserve") == 0)
+ curproxy->options2 |= PR_O2_RSTRICT_REQ_HDR_NAMES_NOOP;
+ else if (strcmp(args[2], "reject") == 0)
+ curproxy->options2 |= PR_O2_RSTRICT_REQ_HDR_NAMES_BLK;
+ else if (strcmp(args[2], "delete") == 0)
+ curproxy->options2 |= PR_O2_RSTRICT_REQ_HDR_NAMES_DEL;
+ else {
+ ha_alert("parsing [%s:%d] : invalid parameter '%s'. option '%s' expects 'preserve', 'reject' or 'delete' option.\n",
+ file, linenum, args[2], args[1]);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+ }
else {
const char *best = proxy_find_best_option(args[1], common_options);