Hi,

On Thu, May 01, 2025 at 01:08:22AM -0400, Demi Marie Obenour wrote:
> I noticed that if HAProxy receives a message containing \x01 in a
> field value, it will happily forward that message.  This appears
> to be permitted by RFC9113 and RFC9114.  However, it might cause
> a problem if the message is a response, the response is sent to
> the client over HTTP/3, and the client uses nghttp3.  nghttp3 will
> silently discard the field, causing HAProxy and the client to
> disagree on whether the field exists.
> 
> Is this a serious concern, or is it considered too theoretical to
> matter?  From my reading of https://github.com/ngtcp2/nghttp3/discussions/346,
> it seems that the nghttp3 maintainer considers this to be working
> as intended (a valid decision).  Is there anything that should be
> be done on the HAProxy side, or is HAProxy thinking that a header
> exists when a client thinks it does not expected behavior?

When H2 begun, some people saw a great opportunity in its ability
to be fully binary-transparent, while others (like us) dealing with
intermediaries saw a big danger in it. From what I remember (but I
could be wrong, I'd need to recheck), the spec only requires that
chars are filtered when converting from H2 to H1. And IIRC in the
end only CR, LF and NUL are forbidden in header values in H2, as
a protective measure for H2 to H1 translation, while HPACK takes
care of permitting absolutely everything.

The thing is that full H2 applications are explicitly permitted
to rely on this. For example you could imagine sending payload's
SHA256 digests directly in a header, escaping NUL with \0, LF
with \n, CR with \r and '\' with '\\' an keep it compact like
this. So while we have to perform the cleanup for H2,H3 -> H1,
we cannot afford to be excessive and go beyond the spec where
applications expect it to work as permitted by the spec.

However I find it particularly dangerous to silently discard some
headers. It's offering an invitation to a remote attacker to declare
which headers will be locally discarded. It's exactly the same as
using a Connection header that has long been abused for this. The
spec does not offer such provisions for selectively eliminating
headers. If a message is not acceptable, it must be rejected,
otherwise it must be accepted. Header fields form semantics together
and selectively accepting/dropping some of them can only result in
changing the semantics of the message. For example, in H1,
transfer-encoding has precedence over content-length. Imagine if an
agent would selectively accept transfer-encoding. This could make
one in the path rely on it and another one ignore it and rely on a
different content-length.

Maybe we could start to think about having options to be stricter
than the spec (e.g. enforce HTTP/1 syntax on all versions) in order
to protect known vulnerable implementations, but I'm afraid that if
we go down that route, this becomes and endless chase...

Regards,
Willy


Reply via email to