On 11/04/2016 03:20 PM, [email protected] wrote: > Author: wrowe > Date: Fri Nov 4 14:20:16 2016 > New Revision: 1768036 > > URL: http://svn.apache.org/viewvc?rev=1768036&view=rev > Log: > Add an option to enforce stricter HTTP conformance > > This is a first stab, the checks will likely have to be revised. > For now, we check > > * if the request line contains control characters > * if the request uri has fragment or username/password > * that the request method is standard or registered with RegisterHttpMethod > * that the request protocol is of the form HTTP/[1-9]+.[0-9]+, > or missing for 0.9 > * if there is garbage in the request line after the protocol > * if any request header contains control characters > * if any request header has an empty name > * for the host name in the URL or Host header: > - if an IPv4 dotted decimal address: Reject octal or hex values, require > exactly four parts > - if a DNS host name: Reject non-alphanumeric characters besides '.' and > '-'. As a side effect, this rejects multiple Host headers. > * if any response header contains control characters > * if any response header has an empty name > * that the Location response header (if present) has a valid scheme and is > absolute > > If we have a host name both from the URL and the Host header, we replace the > Host header with the value from the URL to enforce RFC conformance. > > There is a log-only mode, but the loglevels of the logged messages need some > thought/work. Currently, the checks for incoming data log for 'core' and the > checks for outgoing data log for 'http'. Maybe we need a way to configure the > loglevels separately from the core/http loglevels. > > change protocol number parsing in strict mode according to HTTPbis draft > - only accept single digit version components > - don't accept white-space after protocol specification > > Clean up comment, fix log tags. > Submitted by: sf > Backports: r1426877, r1426879, r1426988, r1426992 > >
> Modified: httpd/httpd/branches/2.4.x-merge-http-strict/server/vhost.c > URL: > http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x-merge-http-strict/server/vhost.c?rev=1768036&r1=1768035&r2=1768036&view=diff > ============================================================================== > --- httpd/httpd/branches/2.4.x-merge-http-strict/server/vhost.c (original) > +++ httpd/httpd/branches/2.4.x-merge-http-strict/server/vhost.c Fri Nov 4 > 14:20:16 2016 > @@ -1040,23 +1108,79 @@ static void check_serverpath(request_rec > } > } > > +static APR_INLINE const char *construct_host_header(request_rec *r, > + int is_v6literal) > +{ > + struct iovec iov[5]; > + apr_size_t nvec = 0; > + /* > + * We cannot use ap_get_server_name/port here, because we must > + * ignore UseCanonicalName/Port. > + */ > + if (is_v6literal) { > + iov[nvec].iov_base = "["; > + iov[nvec].iov_len = 1; > + nvec++; > + } > + iov[nvec].iov_base = (void *)r->hostname; > + iov[nvec].iov_len = strlen(r->hostname); > + nvec++; > + if (is_v6literal) { > + iov[nvec].iov_base = "]"; > + iov[nvec].iov_len = 1; > + nvec++; > + } > + if (r->parsed_uri.port_str) { > + iov[nvec].iov_base = ":"; > + iov[nvec].iov_len = 1; > + nvec++; > + iov[nvec].iov_base = r->parsed_uri.port_str; > + iov[nvec].iov_len = strlen(r->parsed_uri.port_str); > + nvec++; > + } > + return apr_pstrcatv(r->pool, iov, nvec, NULL); > +} > > AP_DECLARE(void) ap_update_vhost_from_headers(request_rec *r) > { > - const char *host_header; > + core_server_config *conf = > ap_get_core_module_config(r->server->module_config); > + const char *host_header = apr_table_get(r->headers_in, "Host"); > + int is_v6literal, have_hostname_from_url = 0; > > if (r->hostname) { > /* > * If there was a host part in the Request-URI, ignore the 'Host' > * header. > */ > - fix_hostname(r, NULL); > + have_hostname_from_url = 1; > + is_v6literal = fix_hostname(r, NULL, conf->http_conformance); > } > - else if ((host_header = apr_table_get(r->headers_in, "Host")) != NULL ) { > - fix_hostname(r, host_header); > + else if (host_header != NULL) { > + is_v6literal = fix_hostname(r, host_header, conf->http_conformance); > } > if (r->status != HTTP_OK) > return; > + > + if (conf->http_conformance & AP_HTTP_CONFORMANCE_STRICT) { > + /* > + * If we have both hostname from an absoluteURI and a Host header, > + * we must ignore the Host header (RFC 2616 5.2). > + * To enforce this, we reset the Host header to the value from the > + * request line. > + */ > + if (have_hostname_from_url && host_header != NULL) { > + const char *info = "Would replace"; > + const char *new = construct_host_header(r, is_v6literal); > + if (!(conf->http_conformance & AP_HTTP_CONFORMANCE_LOGONLY)) { > + apr_table_set(r->headers_in, "Host", r->hostname); Hm, why don't we use "new" here instead of r->hostname > + info = "Replacing"; > + } > + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02417) > + "%s Host header '%s' with host from request uri: " > + "'%s'", info, host_header, new); > + } > + } > + > /* check if we tucked away a name_chain */ > if (r->connection->vhost_lookup_data) { > if (r->hostname) > > > Regards RĂ¼diger
