Hello Willy.

Thanks a lot for the discussion on the Jetty issue report.  I hope this can
be fixed somehow.

In the meantime, I have implemented a workaround, duplicating the backend,
one with proto h2 support (h2_backend) and another without (h1_backend).

And then I have this in the frontend:

  use_backend h1_backend if HTTP_1.0 or HTTP_1.1
  default_backend h2_backend

Also thanks a lot for the connection share warning related to the proxy
protocol.  We have switched to option forwardfor instead, which I
understand is the right option at the http level.  We will replace it by option
forwarded once Ubuntu updates haproxy package version.

Regards,
Óscar


On Fri, Feb 24, 2023 at 4:13 PM Óscar Frías Barranco <ofr...@gmail.com>
wrote:

> Hello Willy.
>
> Thank you very much for the detailed answer.  I have reported this in
> Jetty issue tracker, I hope they can support this use case:
> https://github.com/eclipse/jetty.project/issues/9436
>
> Kind regards,
> Óscar
>
>
> On Fri, Feb 24, 2023 at 2:44 PM Willy Tarreau <w...@1wt.eu> wrote:
>
>> Hello,
>>
>> On Fri, Feb 24, 2023 at 02:19:30PM +0100, Óscar Frías Barranco wrote:
>> > Hello
>> >
>> > I am using haproxy 2.4.18 with a frontend configured with alpn
>> h2,http/1.1
>> >
>> > The problem that I am facing is that if I add "proto h2" to the
>> backends,
>> > when a remote client connects to the frontend using HTTP 1.1, the
>> request
>> > is sent to the backend server without copying the "Host" header to the
>> > ":authority" pseudo-header.
>>
>> This is normal and expected, it complies with the spec that is pretty
>> strict about this:
>>
>>    https://www.rfc-editor.org/rfc/rfc7540#section-8.1.2.3
>>
>>       The ":authority" pseudo-header field includes the authority
>>       portion of the target URI ([RFC3986], Section 3.2).  The authority
>>       MUST NOT include the deprecated "userinfo" subcomponent for "http"
>>       or "https" schemed URIs.
>>
>>       To ensure that the HTTP/1.1 request line can be reproduced
>>       accurately, this pseudo-header field MUST be omitted when
>>       translating from an HTTP/1.1 request that has a request target in
>>       origin or asterisk form (see [RFC7230], Section 5.3).
>>
>> and was further refined in the updated spec:
>>
>>
>> https://www.rfc-editor.org/rfc/rfc9113#name-request-pseudo-header-field
>>
>>    The ":authority" pseudo-header field conveys the authority portion
>> (Section
>>    3.2 of [RFC3986]) of the target URI (Section 7.1 of [HTTP]).
>>    (...)
>>    An intermediary that forwards a request over HTTP/2 MUST construct an
>>    ":authority" pseudo-header field using the authority information from
>> the
>>    control data of the original request, unless the original request's
>> target URI
>>    does not contain authority information (in which case it MUST NOT
>> generate
>>    ":authority"). Note that the Host header field is not the sole source
>> of this
>>    information; see Section 7.2 of [HTTP].
>>
>> If the HTTP/1 request contains an authority part, it will appear there.
>> Otherwise only the host is used. In summary, the H2 request looks very
>> close to the H1 one: Host conveys Host, authority conveys authority.
>>
>> > This causes the application server (Jetty in my case) to report the
>> backend
>> > server numeric IP address as the server name instead of reporting the
>> web
>> > domain (which is in the Host header) as one would expect.  The URI
>> reported
>> > at the application level is also wrong (numeric instead of the domain)
>> for
>> > the same reason I suppose.
>>
>> Given that :authority is not mandatory, I presume there should be at
>> least an option in Jetty to report the Host when it is missing. For
>> example RFC7540 used to hint about this:
>>
>>       Clients
>>       that generate HTTP/2 requests directly SHOULD use the ":authority"
>>       pseudo-header field instead of the Host header field.  An
>>       intermediary that converts an HTTP/2 request to HTTP/1.1 MUST
>>       create a Host header field if one is not present in a request by
>>       copying the value of the ":authority" pseudo-header field.
>>
>> > If the remote user connects to the frontend with HTTP/2 everything is
>> > correct (I assume that is because the :authority pseudo header was
>> already
>> > in there).
>> >
>> > If I remove "proto h2" from the backend, everything is OK too (because
>> in
>> > this case :authority is converted to a Host header when connecting to
>> the
>> > backend).
>> >
>> > Is there something I can do to fix this?  Is this a bug (either from
>> > haproxy or Jetty) ?
>>
>> I suspect it's not a bug but a config decision on Jetty's side.
>>
>> Particularly, a few years ago some vulnerabilities were exposed in H2
>> agents not strictly following the spec regarding host vs :authority,
>> making combinations of such agents rather "fun". It's very possible
>> that some implementations have decided to restrict the fallbacks by
>> default and to only rely on :authority unless configured to look at
>> Host when missing, according to the spec.
>>
>> If required there is a hack that can be used to force an authority.
>> If you force an authority in your request it should normally work:
>>
>>    http-request set-uri https://%[req.hdr(host)]%[pathq]
>>
>> But it would be cleaner to make sure the server accepts a request that
>> only has a host and no authority.
>>
>> Regards,
>> Willy
>>
>

Reply via email to