diff --git a/docs/log-message-tags/next-number b/docs/log-message-tags/next-number index 01d130b6cac..9f0b3f30565 100644 --- a/docs/log-message-tags/next-number +++ b/docs/log-message-tags/next-number @@ -1 +1 @@ -10543 +10544 diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c index 46d3b071454..57864291944 100644 --- a/modules/proxy/mod_proxy.c +++ b/modules/proxy/mod_proxy.c @@ -1591,6 +1591,8 @@ static void * create_proxy_config(apr_pool_t *p, server_rec *s) ps->id = apr_psprintf(p, "p%x", 1); /* simply for storage size */ ps->viaopt = via_off; /* initially backward compatible with 1.3.1 */ ps->viaopt_set = 0; /* 0 means default */ + ps->underscored_headers = underscored_headers_allow; /* don't introduce breaking change */ + ps->underscored_headers_set = 0; ps->req = 0; ps->max_balancers = 0; ps->bal_persist = 0; @@ -1752,6 +1754,8 @@ static void * merge_proxy_config(apr_pool_t *p, void *basev, void *overridesv) ps->id = (overrides->id == NULL) ? base->id : overrides->id; ps->viaopt = (overrides->viaopt_set == 0) ? base->viaopt : overrides->viaopt; ps->viaopt_set = overrides->viaopt_set || base->viaopt_set; + ps->underscored_headers = (overrides->underscored_headers_set == 0) ? base->underscored_headers : overrides->underscored_headers; + ps->underscored_headers_set = overrides->underscored_headers_set || base->underscored_headers_set; ps->req = (overrides->req_set == 0) ? base->req : overrides->req; ps->req_set = overrides->req_set || base->req_set; ps->bgrowth = (overrides->bgrowth_set == 0) ? base->bgrowth : overrides->bgrowth; @@ -2577,6 +2581,25 @@ static const char* return NULL; } +static const char* + set_underscored_headers(cmd_parms *parms, void *dummy, const char *arg) +{ + proxy_server_conf *psf = + ap_get_module_config(parms->server->module_config, &proxy_module); + + if (strcasecmp(arg, "Allow") == 0) + psf->underscored_headers = underscored_headers_allow; + else if (strcasecmp(arg, "Drop") == 0) + psf->underscored_headers = underscored_headers_drop; + else if (strcasecmp(arg, "Reject") == 0) + psf->underscored_headers = underscored_headers_reject; + else + return "ProxyUnderscoredHeaders must be one of: Allow | Drop | Reject"; + + psf->underscored_headers_set = 1; + return NULL; +} + static const char* set_bad_opt(cmd_parms *parms, void *dummy, const char *arg) { @@ -3066,6 +3089,8 @@ static const command_rec proxy_cmds[] = "The default intranet domain name (in absence of a domain in the URL)"), AP_INIT_TAKE1("ProxyVia", set_via_opt, NULL, RSRC_CONF, "Configure Via: proxy header header to one of: on | off | block | full"), + AP_INIT_TAKE1("ProxyUnderscoredHeaders", set_underscored_headers, NULL, RSRC_CONF, + "Handling of headers with underscores to backend: allow | drop | reject"), AP_INIT_ITERATE("ProxyErrorOverride", set_proxy_error_override, NULL, RSRC_CONF|ACCESS_CONF, "use our error handling pages instead of the servers' we are proxying"), AP_INIT_FLAG("ProxyPreserveHost", set_preserve_host, NULL, RSRC_CONF|ACCESS_CONF, diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h index d51510fc02f..b178584a709 100644 --- a/modules/proxy/mod_proxy.h +++ b/modules/proxy/mod_proxy.h @@ -173,6 +173,11 @@ typedef struct { via_block, via_full } viaopt; /* how to deal with proxy Via: headers */ + enum { + underscored_headers_allow, + underscored_headers_drop, + underscored_headers_reject + } underscored_headers; apr_size_t recv_buffer_size; apr_size_t io_buffer_size; long maxfwd; @@ -194,6 +199,7 @@ typedef struct { unsigned int req_set:1; unsigned int viaopt_set:1; + unsigned int underscored_headers_set:1; unsigned int recv_buffer_size_set:1; unsigned int io_buffer_size_set:1; unsigned int maxfwd_set:1; diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c index bfeee868558..8c912953ebf 100644 --- a/modules/proxy/mod_proxy_http.c +++ b/modules/proxy/mod_proxy_http.c @@ -28,6 +28,34 @@ static int (*ap_proxy_clear_connection_fn)(request_rec *r, apr_table_t *headers) static apr_status_t ap_proxygetline(apr_bucket_brigade *bb, char *s, int n, request_rec *r, int flags, int *read); +static int filter_underscored_headers(request_rec *r, proxy_server_conf *conf) +{ + const apr_array_header_t *hdrs_arr = apr_table_elts(r->headers_in); + const apr_table_entry_t *hdrs = (const apr_table_entry_t *) hdrs_arr->elts; + int i; + + if (conf->underscored_headers == underscored_headers_allow) + return OK; + + for (i = 0; i < hdrs_arr->nelts; i++) { + if (!hdrs[i].key) continue; + if (!ap_strchr(hdrs[i].key, '_')) continue; + if (conf->underscored_headers == underscored_headers_drop) { + ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, + "dropped underscored header '%s'", hdrs[i].key); + apr_table_unset(r->headers_in, hdrs[i].key); + } + if (conf->underscored_headers == underscored_headers_reject) { + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(10543) + "rejected request for underscored header '%s'", + hdrs[i].key); + return HTTP_BAD_REQUEST; + } + } + + return OK; +} + static const char *get_url_scheme(const char **url, int *is_ssl) { const char *u = *url; @@ -1966,6 +1994,13 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker, } ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "HTTP: serving URL %s", url); + /* check if any request header contains underscore (_), + drop such header or reject the whole request accordingly to conf + */ + if ((status = filter_underscored_headers(r, conf)) != OK) { + return status; + } + /* create space for state information */ if ((status = ap_proxy_acquire_connection(scheme, &backend, worker, r->server)) != OK) {