Skip to content

http: allow ignoring unknown upgrade requests#37150

Closed
ggreenway wants to merge 6 commits intoenvoyproxy:mainfrom
ggreenway:ignore-upgrades
Closed

http: allow ignoring unknown upgrade requests#37150
ggreenway wants to merge 6 commits intoenvoyproxy:mainfrom
ggreenway:ignore-upgrades

Conversation

@ggreenway
Copy link
Member

Fixes #36305

Add configuration to ignore either all unknown upgrade requests, or specific upgrade requests. This is allowed in https://datatracker.ietf.org/doc/html/rfc7230#section-6.7:

A server MAY ignore a received Upgrade
header field if it wishes to continue using the current protocol on
that connection.

Risk Level: Medium
Testing: TODO
Docs Changes:
Release Notes: TODO

Fixes envoyproxy#36305

Signed-off-by: Greg Greenway <ggreenway@apple.com>
@repokitteh-read-only
Copy link

As a reminder, PRs marked as draft will not be automatically assigned reviewers,
or be handled by maintainer-oncall triage.

Please mark your PR as ready when you want it to be reviewed!

🐱

Caused by: #37150 was opened by ggreenway.

see: more, trace.

@repokitteh-read-only
Copy link

CC @envoyproxy/api-shepherds: Your approval is needed for changes made to (api/envoy/|docs/root/api-docs/).
envoyproxy/api-shepherds assignee is @abeyad
CC @envoyproxy/api-watchers: FYI only for changes made to (api/envoy/|docs/root/api-docs/).

🐱

Caused by: #37150 was opened by ggreenway.

see: more, trace.

@ggreenway
Copy link
Member Author

Initial questions:

  1. Is this the right way to ignore upgrades?
  2. Is it better to default the global-ignore to true or false?
  3. Do we need to handle h2/h3 specially? My understanding is that the Upgrade header doesn't apply to them at all (https://www.rfc-editor.org/rfc/rfc9113#name-the-upgrade-header-field).

@alyssawilk
Copy link
Contributor

cc @RyanTheOptimist for spec thoughts

Copy link
Contributor

@alyssawilk alyssawilk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine with this conceptually but as commented would like @RyanTheOptimist (or @DavidSchinazi but he's less likely to respond) thoughts from a spec perspective
and tests, obviously but it's still a draft so can wait for those =P

createFilterChain(FilterChainManager& manager, bool only_create_if_configured = false,
const FilterChainOptions& options = EmptyFilterChainOptions{}) const PURE;

enum class UpgradeAction {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think move the comments below up here in case the enum gets used multiple places

@RyanTheOptimist
Copy link
Contributor

Yes, Upgrade is HTTP/1 only. However Extended CONNECT provides similar capabilities for H2 and H3. Do we have a similar configuration method for this?

// :ref:`upgrade documentation <arch_overview_upgrades>`.
google.protobuf.BoolValue enabled = 3;

// If enabled, Envoy will ignore upgrade requests of this type. It is invalid to set both this option and
Copy link

@chlunde chlunde Nov 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice if you could explicitly describe what this means.

Ignore could mean pass through or the header could be discarded. Also, there are two headers involved, connection and upgrade. The user should understand the implication for both of them, without reading the source code.

Signed-off-by: Greg Greenway <ggreenway@apple.com>
@ggreenway
Copy link
Member Author

As mentioned by @chlunde above, we also need to remove the parts of the Connection header for upgrades. When looking at that, I found other code that removes h2c upgrades, and found that there is another portion for h2c that needs to be removed (http2-settings). Are there similar bits for other types of upgrades? And if there are, is there any risk if they are not removed?

@DavidSchinazi
Copy link
Contributor

There's an important distinction between HTTP versions here:

(As a quick side note, RFC 7230 has been obsoleted by RFC 9110 and RFC 9112, please do not refer to it as some parts of it are incorrect).

They behave differently: in particular, in HTTP/1.1 the server can "ignore" the Upgrade and still send a successful HTTP/1.1 response without upgrading to a different protocol. In HTTP/2 and 3 however, that is not possible. If the server does not wish to use the other protocol, it has no choice but to reject the request.

This gets particularly tricky because Envoy normalizes every Extended CONNECT internally to look like Upgrade. So the information of whether ignoring is allowed or not gets somewhat hard to track down inside Envoy.

I worry that this will cause protocol confusion or request smuggling attacks, unless there are strong safeguards in place to ensure that this cannot happen in HTTP/2 or HTTP/3.

Signed-off-by: Greg Greenway <ggreenway@apple.com>
@ggreenway
Copy link
Member Author

@DavidSchinazi thanks for the clarification on this. I added a check, and renamed the config fields, to document and ensure that ignoring upgrades only happens on http 1.1.

@DavidSchinazi
Copy link
Contributor

Thanks @ggreenway ! As far as I can tell, this looks safe from a spec perspective. But I'll let folks more familiar with Envoy internals do the detailed code review.

Signed-off-by: Greg Greenway <ggreenway@apple.com>
@ipoval
Copy link

ipoval commented Nov 19, 2024

@ggreenway 👋 , hi, what is going to be the expected behavior after this fix for the HTTP2 upstreams? Is it going to be safe to use HTTP2 clusters when clients supply -H "Connection: Upgrade" -H "Upgrade: TLS/1.3" headers for example? Just want to double check expectations after reading (https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto#extensions-filters-network-http-connection-manager-v3-httpconnectionmanager-upgradeconfig) that upgrade config does not work with HTTP2

@ggreenway
Copy link
Member Author

@ipoval when Envoy ignores a downstream http/1.1 upgrade request, it will remove the upgrade headers from the request, so the request should be fine for any upstream http version because it no longer requests an upgrade.

Signed-off-by: Greg Greenway <ggreenway@apple.com>
@ggreenway
Copy link
Member Author

Integration tests reveal that this doesn't work. The http1 codec handles request processing differently if it thinks an upgrade is happening; see handling_upgrade_ in http1/codec_impl.cc.

@ggreenway
Copy link
Member Author

A fix for this would probably have to be in the http1 codec_impl, but that doesn't have access to the configured upgrades which are processed later, so it would probably need to be a change that specifically ignores TLS upgrades.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

HTTP/1.1 TLS Upgrade (RFC-2817) causes upgrade_failed

7 participants