Commit 2cffd4c4 authored by William A. Rowe Jr's avatar William A. Rowe Jr
Browse files

Rename the previously undocumented HTTPProtocol directive
to EnforceHTTPProtocol, and invert the default behavior
to strictly observe RFC 7230 unless otherwise configured.
And Document This.

The relaxation option is renamed 'Unsafe'. 'Strict' is no
longer case sensitive. 'min=0.9|1.0' is now the verbose
'Allow0.9' or 'Require1.0' case-insenstive grammer. The
exclusivity tests have been modified to detect conflicts.

The 'strict,log' option failed to enforce strict conformance,
and has been removed. Unsafe, informational logging is possible
in any loadable module, after the request data is unsafely
accepted.

This triggers a group of failures in t/apache/headers.t as
expected since those patterns violated RFC 7230 section 3.2.4.
Submitted by: wrowe
Backport: r1756540

Correct AP_HTTP_CONFORMANCE_ flags
Submitted by: wrowe
Backport: r1756555

Renaming this directive to HttpProtocolOptions after discussion on dev@
Submitted by: wrowe
Backport: r1756649

Perform correct, strict parsing of the request line, handling the
http protocol tag, url and method appropriately, and attempting 
to extract values even in the presence of unusual whitespace in
keeping with section 3.5, prior to responding with whatever
error reply is needed. Conforms to RFC7230 in all respects,
the section 3.5 optional behavior can be disabled by the user
with a new HttpProtocolOptions StrictWhitespace flag. In all
cases, the_request is regenerated from the parsed components
with exactly two space characters.

Shift sf's 'strict' method check from the Strict behavior because
it violates forward proxy logic, adding a new RegisteredMethods
flag, as it will certainly be useful to some.
Submitted by: wrowe
Backport: r1756729



git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x-merge-http-strict@1769662 13f79535-47bb-0310-9956-ffa450edef68
parent 80281ca0
Loading
Loading
Loading
Loading
+81 −0
Original line number Diff line number Diff line
@@ -1238,6 +1238,87 @@ EnableSendfile On
</usage>
</directivesynopsis>

<directivesynopsis>
<name>HTTPProtocolOptions</name>
<description>Modify restrictions on HTTP Request Messages</description>
<syntax>HTTPProtocolOptions [Strict|Unsafe] [Allow0.9|Require1.0] 
[StrictWhitespace|LenientWhitespace] [RegisteredMethods|LenientMethods]</syntax>
<default>HTTPProtocolOptions Strict Allow0.9 LenientWhitespace 
LenientMethods</default>
<contextlist><context>server config</context>
<context>virtual host</context></contextlist>
<compatibility>2.2.32 or 2.4.24 and later</compatibility>

<usage>
    <p>This directive changes the rules applied to the HTTP Request Line
    (<a href="https://tools.ietf.org/html/rfc7230#section-3.1.1"
      >RFC 7230 &sect;3.1.1</a>) and the HTTP Request Header Fields
    (<a href="https://tools.ietf.org/html/rfc7230#section-3.2"
      >RFC 7230 &sect;3.2</a>), which are now applied by default or using
    the <code>Strict</code> option. Due to legacy modules, applications or
    custom user-agents which must be deperecated, an <code>Unsafe</code>
    option has been added to revert to the legacy behavior. These rules are
    applied prior to request processing, so must be configured at the global
    or default (first) matching virtual host section, by interface and not
    by name, to be honored.</p>

    <p>Prior to the introduction of this directive, the Apache HTTP Server
    request message parsers were tolerant of a number of forms of input
    which did not conform to the protocol.
    <a href="https://tools.ietf.org/html/rfc7230#section-9.4"
      >RFC 7230 &sect;9.4 Request Splitting</a> and
    <a href="https://tools.ietf.org/html/rfc7230#section-9.5"
      >&sect;9.5 Response Smuggling</a> call out only two of the potential
    risks of accepting non-conformant request messages. As of the introduction
    of this directive, all grammer rules of the specification are enforced in
    the default <code>Strict</code> operating mode.</p>

    <p>Users are strongly cautioned against toggling the <code>Unsafe</code>
    mode of operation for these reasons, most especially on outward-facing,
    publicly accessible server deployments. Reviewing the messages within the
    <directive>ErrorLog</directive>, configured with
    <directive>LogLevel</directive> <code>info</code> level or below,
    can help identify such faulty requests along with their origin.
    Users should pay particular attention to any 400 responses in the access
    log for indiciations that valid requests are unexpectedly rejected.</p>

    <p><a href="https://tools.ietf.org/html/rfc2616#section-19.6"
         >RFC 2616 &sect;19.6</a> "Compatibility With Previous Versions" had
    encouraged HTTP servers to support legacy HTTP/0.9 requests. RFC 7230
    superceeds this with "The expectation to support HTTP/0.9 requests has
    been removed" and offers additional comments in 
    <a href="https://tools.ietf.org/html/rfc7230#appendix-A"
      >RFC 2616 Appendix A</a>. The <code>Require1.0</code> option allows
    the user to remove support of the default <code>Allow0.9</code> option's
    behavior.</p>

    <p><a href="https://tools.ietf.org/html/rfc7230#section-3.5"
         >RFC 7230 &sect;3.5</a> "Message Parsing Robustness" permits, and
    identifies potential risks of parsing messages containing non-space
    character whitespace. While the spec defines that exactly one space
    seperates the URI from the method, and the protocol from the URI, the
    Apache HTTP Server has traditionally been lenient in accepting other
    whitespace including one or more horizontal-tab or space characters.
    The default <code>LenientWhitespace</code> continues to accept such
    requests from non-conforming user-agents, but the administrator may toggle
    the <code>StrictWhitespace</code> option to insist on precisely two spaces
    in the request line. Other whitespace including vertical-tab, form-feed,
    and carriage-return characters are rejected and cannot be supported.</p>

    <p><a href="https://tools.ietf.org/html/rfc7231#section-4.1"
         >RFC 7231 &sect;4.1</a> "Request Methods" "Overview" requires that
    origin servers shall respond with an error when an unsupported method
    is encountered in the request line. This already happens when the
    <code>LenientMethods</code> option is used, but administrators may wish
    to toggle the <code>RegisteredMethods</code> option and register all
    permitted method tokens using the <directive>RegisterHttpMethod</directive>
    directive, particularly if the <code>Unsafe</code> option has been toggled.
    The <code>RegisteredMethods</code> option should <strong>not</strong>
    be toggled for forward proxy hosts, as the methods supported by the
    origin servers are unknown to the proxy server.</p>
</usage>
</directivesynopsis>

<directivesynopsis>
<name>Error</name>
<description>Abort configuration parsing with a custom error message</description>
+2 −0
Original line number Diff line number Diff line
@@ -491,6 +491,8 @@
 *                          Add http_conformance to core_server_config
 *                          Add ap_has_cntrl(), ap_get_http_token()
 *                          Add ap_scan_http_field_[content|token]()
 *                          Added http_whitespace and http_methods to
 *                          core_server_config
 */

#define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */
+12 −2
Original line number Diff line number Diff line
@@ -732,10 +732,20 @@ typedef struct {
    char http09_enable;

#define AP_HTTP_CONFORMANCE_UNSET     0
#define AP_HTTP_CONFORMANCE_LIBERAL   1
#define AP_HTTP_CONFORMANCE_UNSAFE    1
#define AP_HTTP_CONFORMANCE_STRICT    2
#define AP_HTTP_CONFORMANCE_LOGONLY   4
    char http_conformance;

#define AP_HTTP_WHITESPACE_UNSET      0
#define AP_HTTP_WHITESPACE_LENIENT    1
#define AP_HTTP_WHITESPACE_STRICT     2
    char http_whitespace;

#define AP_HTTP_METHODS_UNSET         0
#define AP_HTTP_METHODS_LENIENT       1
#define AP_HTTP_METHODS_REGISTERED    2
    char http_methods;

} core_server_config;

/* for AddOutputFiltersByType in core.c */
+2 −2
Original line number Diff line number Diff line
@@ -1302,9 +1302,9 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f,
    }

    conf = ap_get_core_module_config(r->server->module_config);
    if (conf->http_conformance & AP_HTTP_CONFORMANCE_STRICT) {
    if (conf->http_conformance != AP_HTTP_CONFORMANCE_UNSAFE) {
        int ok = check_headers(r);
        if (!ok && !(conf->http_conformance & AP_HTTP_CONFORMANCE_LOGONLY)) {
        if (!ok) {
            ap_die(HTTP_INTERNAL_SERVER_ERROR, r);
            return AP_FILTER_ERROR;
        }
+51 −30
Original line number Diff line number Diff line
@@ -525,6 +525,12 @@ static void *merge_core_server_configs(apr_pool_t *p, void *basev, void *virtv)
    if (virt->http_conformance != AP_HTTP_CONFORMANCE_UNSET)
        conf->http_conformance = virt->http_conformance;

    if (virt->http_whitespace != AP_HTTP_WHITESPACE_UNSET)
        conf->http_whitespace = virt->http_whitespace;

    if (virt->http_methods != AP_HTTP_METHODS_UNSET)
        conf->http_methods = virt->http_methods;

    /* no action for virt->accf_map, not allowed per-vhost */

    if (virt->protocol)
@@ -3901,38 +3907,53 @@ static const char *set_protocols_honor_order(cmd_parms *cmd, void *dummy,
    return NULL;
}

static const char *set_http_protocol(cmd_parms *cmd, void *dummy,
static const char *set_http_protocol_options(cmd_parms *cmd, void *dummy,
                                             const char *arg)
{
    core_server_config *conf =
        ap_get_core_module_config(cmd->server->module_config);

    if (strncmp(arg, "min=", 4) == 0) {
        arg += 4;
        if (strcmp(arg, "0.9") == 0)
            conf->http09_enable = AP_HTTP09_ENABLE;
        else if (strcmp(arg, "1.0") == 0)
            conf->http09_enable = AP_HTTP09_DISABLE;
        else
            return "HttpProtocol 'min' must be one of '0.9' and '1.0'";
        return NULL;
    }

    if (strcmp(arg, "strict") == 0)
        conf->http_conformance = AP_HTTP_CONFORMANCE_STRICT;
    else if (strcmp(arg, "strict,log-only") == 0)
        conf->http_conformance = AP_HTTP_CONFORMANCE_STRICT|
                                 AP_HTTP_CONFORMANCE_LOGONLY;
    else if (strcmp(arg, "liberal") == 0)
        conf->http_conformance = AP_HTTP_CONFORMANCE_LIBERAL;
    if (strcasecmp(arg, "allow0.9") == 0)
        conf->http09_enable |= AP_HTTP09_ENABLE;
    else if (strcasecmp(arg, "require1.0") == 0)
        conf->http09_enable |= AP_HTTP09_DISABLE;
    else if (strcasecmp(arg, "strict") == 0)
        conf->http_conformance |= AP_HTTP_CONFORMANCE_STRICT;
    else if (strcasecmp(arg, "unsafe") == 0)
        conf->http_conformance |= AP_HTTP_CONFORMANCE_UNSAFE;
    else if (strcasecmp(arg, "strictwhitespace") == 0)
        conf->http_whitespace |= AP_HTTP_WHITESPACE_STRICT;
    else if (strcasecmp(arg, "lenientwhitespace") == 0)
        conf->http_whitespace |= AP_HTTP_WHITESPACE_LENIENT;
    else if (strcasecmp(arg, "registeredmethods") == 0)
        conf->http_methods |= AP_HTTP_METHODS_REGISTERED;
    else if (strcasecmp(arg, "lenientmethods") == 0)
        conf->http_methods |= AP_HTTP_METHODS_LENIENT;
    else
        return "HttpProtocol accepts 'min=0.9', 'min=1.0', 'liberal', "
               "'strict', 'strict,log-only'";

    if ((conf->http_conformance & AP_HTTP_CONFORMANCE_STRICT) &&
        (conf->http_conformance & AP_HTTP_CONFORMANCE_LIBERAL)) {
        return "HttpProtocol 'strict' and 'liberal' are mutually exclusive";
    }
        return "HttpProtocolOptions accepts 'Allow0.9' (default) or "
               "'Require1.0', 'Unsafe' or 'Strict' (default), "
               "'StrictWhitespace' or 'LenientWhitespace (default), and "
               "'RegisteredMethods' or 'LenientMethods (default)";

    if ((conf->http09_enable & AP_HTTP09_ENABLE)
            && (conf->http09_enable & AP_HTTP09_DISABLE))
        return "HttpProtocolOptions 'Allow0.9' and 'Require1.0'"
               " are mutually exclusive";

    if ((conf->http_conformance & AP_HTTP_CONFORMANCE_STRICT)
            && (conf->http_conformance & AP_HTTP_CONFORMANCE_UNSAFE))
        return "HttpProtocolOptions 'Strict' and 'Unsafe'"
               " are mutually exclusive";

    if ((conf->http_whitespace & AP_HTTP_WHITESPACE_STRICT)
            && (conf->http_whitespace & AP_HTTP_WHITESPACE_LENIENT))
        return "HttpProtocolOptions 'StrictWhitespace' and 'LenientWhitespace'"
               " are mutually exclusive";

    if ((conf->http_methods & AP_HTTP_METHODS_REGISTERED)
            && (conf->http_methods & AP_HTTP_METHODS_LENIENT))
        return "HttpProtocolOptions 'RegisteredMethods' and 'LenientMethods'"
               " are mutually exclusive";

    return NULL;
}
@@ -4470,9 +4491,9 @@ AP_INIT_ITERATE("Protocols", set_protocols, NULL, RSRC_CONF,
AP_INIT_TAKE1("ProtocolsHonorOrder", set_protocols_honor_order, NULL, RSRC_CONF,
              "'off' (default) or 'on' to respect given order of protocols, "
              "by default the client specified order determines selection"),
AP_INIT_ITERATE("HttpProtocol", set_http_protocol, NULL, RSRC_CONF,
              "'min=0.9' (default) or 'min=1.0' to allow/deny HTTP/0.9; "
              "'liberal', 'strict', 'strict,log-only'"),
AP_INIT_ITERATE("HttpProtocolOptions", set_http_protocol_options, NULL, RSRC_CONF,
              "'Allow0.9' or 'Require1.0' (default) to allow or deny HTTP/0.9; "
              "'Unsafe' or 'Strict' (default) to process incorrect requests"),
AP_INIT_ITERATE("RegisterHttpMethod", set_http_method, NULL, RSRC_CONF,
                "Registers non-standard HTTP methods"),
{ NULL }
Loading