Subject: #492: Alt-Svc header host restriction

From: Julian Reschke <[email-masked]>
Date: Thu, 12 Jun 2014 15:33:55 +0200

Hi there,

turns out that this is a bit messy:

1) People usually think of "host:port", and using that syntax requires 
putting the value into double quotes, as ":" is a token character -- 
unless we choose a different delimiter.

2) I started with the allowing either a simple port (as used before), or 
host:port, but here the problem is that a naked port number can be 
parsed as host name as well. Thus the colon becomes required even is the 
host part is absent.

With that, I currently have:

3.  The Alt-Svc HTTP Header Field

    An HTTP(S) origin server can advertise the availability of
    alternative services to clients by adding an Alt-Svc header field to
    responses.

    Alt-Svc       = 1#( alternative *( OWS ";" OWS parameter ) )
    alternative   = protocol-id "=" alt-authority
    protocol-id   = token ; percent-encoded ALPN protocol identifier
    alt-authority = token / quoted-string
                    ; containing [ uri-host ] ":" port

    ALPN protocol names are octet sequences with no additional
    constraints on format.  Octets not allowed in tokens ([RFC7230],
    Section 3.2.6) MUST be percent-encoded as per Section 2.1 of
    [RFC3986].  Consequently, the octet representing the percent
    character "%" (hex 25) MUST be percent-encoded as well.

    In order to have precisely one way to represent any ALPN protocol
    name, the following additional constraints apply:

    1.  Octets in the ALPN protocol MUST NOT be percent-encoded if they
        are valid token characters except "%", and

    2.  When using percent-encoding, uppercase hex digits MUST be used.

    With these constraints, recipients can apply simple string comparison
    to match protocol identifiers.

    The "alt-authority" component consists of an OPTIONAL uri-host
    ("host" in Section 3.2.2 of [RFC3986]), a colon (":"), and a port
    number.

    For example:

    Alt-Svc: http2=":8000"

    This indicates the "http2" protocol on the same host using the
    indicated port 8000.

    An example involving a change of host:

    Alt-Svc: http2="new.example.org:80"

    This indicates the "http2" protocol on the host "new.example.org",
    running on port 80.  Note that the "quoted-string" syntax needs to be
    used when a host is specified in addition to a port (":" is not an
    allowed character in "token").

    Examples for protocol name escaping:

    +--------------------+-------------+---------------------+
    | ALPN protocol name | protocol-id | Note                |
    +--------------------+-------------+---------------------+
    | http2              | http2       | No escaping needed  |
    +--------------------+-------------+---------------------+
    | w=x:y#z            | w%3Dx%3Ay#z | "=" and ":" escaped |
    +--------------------+-------------+---------------------+
    | x%y                | x%25y       | "%" needs escaping  |
    +--------------------+-------------+---------------------+

    Alt-Svc MAY occur in any HTTP response message, regardless of the
    status code.

    Alt-Svc does not allow advertisement of alternative services on other
    hosts, to protect against various header-based attacks.

    It can, however, have multiple values:

    Alt-Svc: h2c=":8000", h2=":443"

    The value(s) advertised by Alt-Svc can be used by clients to open a
    new connection to one or more alternative services immediately, or
    simultaneously with subsequent requests on the same connection.

    To reduce the ability of servers to track individual clients over
    time (see Section 9.4), an alternative service indication sent by a
    client SHOULD NOT include any alternative service information other
    than the protocol, host and port.

    When using HTTP/2 ([HTTP2]), clients SHOULD instead send an ALTSVC
    frame.  A single ALTSVC frame can be sent for a connection; a new
    frame is not needed for every request.

    Note that all field elements that allow "quoted-string" syntax MUST
    be processed as per Section 3.2.6 of [RFC7230].

Can people live with that or should we try to come up with something 
more elegant?

Best regards, Julian

PS: maybe it's time to start using JSON in header field values.

---

From: Julian Reschke <[email-masked]>
Date: Thu, 12 Jun 2014 16:27:40 +0200

On 2014-06-12 15:33, Julian Reschke wrote:
> ...

For instance, something like

   Alt-Svc: h2; port=443, h2c; host=www.examplecom; port=80

?

Best regards, Julian

---

From: Martin Thomson <[email-masked]>
Date: Thu, 12 Jun 2014 10:15:04 -0700

On 12 June 2014 06:33, Julian Reschke <[email-masked]> wrote:
> Can people live with that or should we try to come up with something more
> elegant?

What you have is reasonable either way.  Deconstructing the syntax
further is OK too, though I always find the precedence order of commas
and semi-colons to be completely unintuitive.

> PS: maybe it's time to start using JSON in header field values.

You first :)

p.s., I think we agreed to lift the restriction on other host names
and move that to -encryption.

p.p.s., Do we want q= on these?

---

From: Julian Reschke <[email-masked]>
Date: Thu, 12 Jun 2014 19:25:16 +0200

> and semi-colons to be completely unintuitive.

Indeed. But at least it's the same for a whole family of header fields.

>> PS: maybe it's time to start using JSON in header field values.

Maybe.

> and move that to -encryption.

a) the restriction is gone, no? b) -encryption?

> p.p.s., Do we want q= on these?

Or define an ordering.

Speaking of which - is it ok that the frame only can carry on 
alternate-service?

Best regards, Julian

---

From: Martin Thomson <[email-masked]>
Date: Thu, 12 Jun 2014 10:51:32 -0700

> a) the restriction is gone, no? b) -encryption?

=b.  I think that the key here is that:

The key is that the server that you end up on needs to be determined
to be authoritative by the means described in the definition of the
URL you are resolving.

Thus, for http: URIs, the server you end up on needs to use DNS name
resolution and IP routing based on the host name that is in the URI.

For https: URIs, the server you end up on needs to present a
certificate that is valid for the host name that is in the URI.

This is a property of HTTP/1.1 that we don't want to change:
https://tools.ietf.org/html/rfc7230#section-9.1

> Speaking of which - is it ok that the frame only can carry on

I didn't really consider that.  It's worth thinking through.
Subsequent frames could be said to replace ones that appear
previously.  Or we could define a more robust format that allows for
multiple entries.  Or we could allow all values to last until their
max-age; and then have values that match on all values other than
max-age update the max-age.  Let me raise some issues for this.

---

From: Julian Reschke <[email-masked]>
Date: Thu, 12 Jun 2014 20:04:45 +0200

> https://tools.ietf.org/html/rfc7230#section-9.1

Ok, we currently have 
<http://greenbytes.de/tech/webdav/draft-ietf-httpbis-alt-svc-latest.html#host_auth>:

> 2.1 Host Authentication
>
> Clients MUST NOT use alternative services with a host other than the origin's without strong server authentication; this mitigates the attack described in Section 9.2. One way to achieve this is for the alternative to use TLS with a certificate that is valid for that origin.
>
> For example, if the origin's host is "www.example.com" and an alternative is offered on "other.example.com" with the "h2" protocol, and the certificate offered is valid for "www.example.com", the client can use the alternative. However, if "other.example.com" is offered with the "h2c" protocol, the client cannot use it, because there is no mechanism in that protocol to establish strong server authentication.
>
> Furthermore, this means that the HTTP Host header field and the SNI information provided in TLS by the client will be that of the origin, not the alternative.

So it seems that this needs a rewrite.

Best regards, Julian