w3c / webtransport

WebTransport is a web API for flexible data transport
https://w3c.github.io/webtransport/
Other
820 stars 51 forks source link

Do we want to allow web developers to add headers of the CONNECT request? #263

Open yutakahirano opened 3 years ago

yutakahirano commented 3 years ago

Web developers may want to attach some information to the request, and encoding everything into the URL is tiresome.

The simplest form is something like this.

const wt = new WebTransport(url, {headers: {foo: 'bar'}});

This may be dangerous if web developers can specify arbitrary headers. Some examples:

new WebTransport(url, {headers: {origin: 'https://google.com/'}});
new WebTransport(url, {headers: {host: 'mozilla.org'}});

So, we need to forbid forbidden header names at least.

That may not be enough. For usual HTTP requests, if the request is cross-origin and has non-safelisted headers, CORS preflight is needed. WebSocket solves the problem by allowing web developers to control only one header (sec-websocket-protocols). We can do the same for WebTransport.

Thoughts?

yutakahirano commented 3 years ago

@annevk @mikewest in case they are interested.

annevk commented 3 years ago

I'm not sure I understand the setup. I thought WebTransport would use ALPN. It seems to me that once ALPN is okay with a specific WebTransport identifier, everything after that is okay as it would be part of the protocol?

yutakahirano commented 3 years ago

I'm not sure I understand the setup. I thought WebTransport would use ALPN. It seems to me that once ALPN is okay with a specific WebTransport identifier, everything after that is okay as it would be part of the protocol?

True, the client must not start establishing a WebTransport session before receiving SETTINGS_ENABLE_WEBTRANSPORT. With that settings, is it OK to send arbitrary headers (as long as the request makes sense in the context of WebTransport over HTTP/3)?

annevk commented 3 years ago

I think so. WebSocket and fetch() have to care about existing servers and infrastructure and therefore come with a bunch of restrictions. WebTransport only has to care about such restrictions (e.g., ports, CSP) up until the point a connection has been established as after that it should be clear to the server it's something new.

We should make this clear in the WebTransport specification (e.g., in a considerations for server implementers section) and hopefully devrel will also cover this extensively.

ricea commented 3 years ago

I think from a privacy and security perspective this looks okay. We probably want to block request-body-header names too since although they wouldn't create security problems they'd be very confusing if set.

I assume extensions will be able to read and modify the headers?

I'm not sure what I feel about this from a design perspective. Is this something we're going to regret later?

vasilvv commented 3 years ago

My personal intuition on this:

annevk commented 3 years ago

I guess this is about about session establishment as written down in https://datatracker.ietf.org/doc/html/draft-ietf-webtrans-http3#section-3.3? So in theory that is post-ALPN so the server should know what is going on. However, I guess there is the concern servers might agree to the ALPN handshake but then handle the request in a normal endpoint (for authentication purposes and such), similar to what has been happening with WebSocket.

I suspect we would never include cookies or HTTP authentication in this CONNECT request, unlike WebSocket?

vasilvv commented 3 years ago

I'm not sure what ALPN specifically has to do here, since they both have ALPN of h3.

The CONNECT requests are supposed to be fully uncredentialed, that is to say, no cookies, no HTTP auth, no TLS client certificates.

annevk commented 3 years ago

Sorry, I meant that the TLS handshake indicates it's a WebTransport connection and not a "normal" HTTP connection. I see that's covered through SETTINGS_ENABLE_WEBTRANSPORT as @yutakahirano already mentioned above.

vasilvv commented 3 years ago

Just to clarify, WebTransport support is an additive property; normal HTTP traffic can occur on WebTransport-supporting connections, though by default a WebTransport object will create a new connection.

annevk commented 3 years ago

Thanks! That does argue for being conservative with the handshake as servers will be incentivized to flip the WebTransport setting and are not at all incentivized to audit all their "legacy" paths at the same time.

yutakahirano commented 3 years ago

Given the discussion above, do the followings make sense?

annevk commented 3 years ago

I think to be on the safe side you probably want to match WebSocket or "no-cors". Other headers would only come after a CORS preflight normally, after all.

yutakahirano commented 3 years ago

Ah sorry I overlooked the last comment.

jan-ivar commented 3 years ago

Meeting:

kixelated commented 3 years ago

Oh sorry I thought I hit the comment button.

My application needs to negotiate a video codec on connect. The client sends a list of supported codecs and the server responds with the chosen one. TLS does something similar.

There's how you could implement this:

  1. Implement a custom RPC using streams and buffer streams until both sides receive some sort of INIT message.
  2. Send supported codecs in a custom request header and the chosen codec in a custom response header.

You could marshal the supported codecs into the request path, but it's a pain. The server still needs to respond with the chosen codec and that's not possible.

I would definitely use custom request+response headers if they were available. Only supporting custom request headers would be a marginal improvement.

annevk commented 3 years ago

We don't need CORS pref-light (bad for performance) since we have settings

What settings is this referring to? If it's the settings set during ALPN I think that is negated (as also stated in prior comments) by the fact that this handshake ends up intermixed with normal HTTP traffic.

yutakahirano commented 3 years ago

@kixelated

Thank you for your opinion!

@annevk What settings is this referring to? If it's the settings set during ALPN I think that is negated (as also stated in prior comments) by the fact that this handshake ends up intermixed with normal HTTP traffic.

I believe it's a new setting - we can define a new setting listing headers which the server accepts for the CONNECT request for webtransport over HTTP/3, for example (let's call it SETTINGS_WEBTRANSPORT_REQUEST_HEADERS for now). Just like SETTINGS_ENABLE_WEBTRANSPORT, if the server supports WebTransport over HTTP/3 and accepts custom headers for the CONNECT request, it should include SETTINGS_WEBTRANSPORT_REQUEST_HEADERS in the initial SETTINGS frame.

This is less flexible than CORS preflight but more efficient.

annevk commented 3 years ago

I see, that would be acceptable (to me, at least). I wonder though, could we generalize that to SETTINGS_BYPASS_CORS_PREFLIGHT or some such so we solve that thorny problem at the same time? See https://github.com/quicwg/base-drafts/issues/1993. Folks (I recall @mnot?) did raise similar concerns in that the person configuring TLS might not be aware of all the HTTP services on the server, but I think we'll always have that problem for any kind of centralized solution. I would hope that documentation would go a long way towards addressing that.

(I could also see trying this more limited thing out first and if it works going for the generalized solution later. Dunno how cheap these bits are.)

mnot commented 3 years ago

Flipping this bit in a SETTING (h2 or h3) has significant performance / race avoidance advantages, so I'm interested. Yes, there are deployments where server administration isn't done by the same people, but I think we can address that risk by:

  1. Requiring implementations to ship with this off (and explaining why that is)
  2. Recommending documentation to put next to the control for the setting, so that users have that information at hand

It might also be interesting to define a companion well-known resource (or Origin Policy property, if that gets off the ground), which would allow control over the SETTING through a resource that's available to the server's content folks (provided that server implementations link the two).

I'm happy to write up a draft for the SETTING, but first it'd be great to hear what people like @mikewest think about this.

yutakahirano commented 3 years ago

cc: @martinthomson

martinthomson commented 3 years ago

I'm not seeing any significant new information: yes, this sort of capability might be nice, but it also costs a fair bit to add. It can be added later.

jan-ivar commented 3 years ago

Meeting:

jlpettersson commented 2 years ago

It would be useful to pass a JWT token for authentication / authorization in the connect request. On the server-side, TLS connections are typically terminated by a load balancer, but it would be useful if an JWT token could be passed through to the server instance behind the load balancer.

the fetch api has "authentication entries" for this.

annevk commented 2 years ago

Authentication entries is explicitly not web developer controlled though.

jlpettersson commented 2 years ago

What I meant was support for the corresponding to:

fetch(url, {
        headers: {
            'Authorization': `Bearer ${token}`,
        },
    })

this could perhaps be something like

const transport = new WebTransport(url, {
        headers: {
            'Authorization': `Bearer ${token}`,
        },
    });
jan-ivar commented 2 years ago

@annevk ^

annevk commented 2 years ago

Yeah, that's the same kind of use case people have for including headers in the WebSocket handshake. As discussed many months ago upthread the conservative option would be requiring a CORS preflight for that, along with the necessary infrastructure. That doesn't seem like the kind of thing that should go into v1.

jan-ivar commented 2 years ago

Meeting:

randomstuff commented 6 months ago

See the related bug entry about the lack of support for HTTP authentication in the WebSocket API.

matthewp commented 2 weeks ago

How do we implement authentication with Web Transport? Do we need to store the session token in a non-HTTPOnly cookie or localStorage or something and send it (from the client) as the first message of a session?