ietf-wg-webtrans / draft-ietf-webtrans-http3

Internet Drafts for WebTransport
Other
40 stars 12 forks source link

Request forgery #63

Closed martinthomson closed 2 years ago

martinthomson commented 2 years ago

When we built thewebsocketprotocol, masking was added to protect intermediaries from carefully crafted messages that were controlled by web sites. No such mechanism exists in this protocol and we should be certain that this is the right answer.

The threat model here is similar to websockets. The attacker is given complete control over the server and the ability to determine the content of QUIC datagrams or streams that are sent by the client. This doesn't give the attacker complete control over the content of UDP datagrams, but the level of control can be very good. As the attacker knows the keys that will be used and they can probably guess the offset into the packet at which data will be placed, they have fine control over the resulting ciphertext.

The result being than an attacker controls most of the content of the UDP datagrams sent by the browser. They choose connection IDs and with the exception of a small number of bytes toward the start of a packet and the authentication tag at the end of a packet, they have nearly complete control over the payload of UDP datagrams.

An attacker might also control the destination address if the client supports the use of preferred addresses. (Though they need to control this address if the client is going to send any meaningful data toward it.)

What an attacker can do with this control is hard to estimate. The attacks that used thewebsocketprotocol relied on having an intermediary that looked at TCP segments and applied some fairly loose parsing. Attackers could then exploit that intermediary. Cache poisoning was the demonstrated example, but we've since seen how bad logic in other intermediaries can be exploited in other ways.

How much intermediaries make decisions based on the content of random UDP packets they see is still unclear. There are a few protocols for which we might want to avoid the risk. For that, blocking traffic to a destination port of 68, 69 or 53 seems like it might provide an easy win. The fetch port blocklist is TCP-specific, but we could just use that for now and work on a UDP version.

Adding something like masking is possible, but far more disruptive. We do not apply masking to HTTP requests, but we allow sites similar levels of control over the content of packets. In a sense we're already accepting some risk of request forgery.

No matter what we decide, the specification needs to address this risk.

martinthomson commented 2 years ago

See w3c/webtransport#175 for more context.

DavidSchinazi commented 2 years ago

@martinthomson is this specific to WebTransport-over-h3 or is it general to QUIC? RFC 9000 already discusses the implications of request forgery, and I'm not sure what WebTransport-over-h3 needs to say on top of that. In your description, it sounds like the attacker is the WebTransport-over-h3 server, but I'm not seeing that this server can do that can't be done by any QUIC server.

martinthomson commented 2 years ago

The text in RFC 9000 is generic. Anything that is deployed to the web context needs to consider this and determine whether generic mitigations are sufficient. WebTransport is - perhaps - special in the sense that it allows for nearly arbitrary control over the content of QUIC packets, so I believe that it is important to directly address this case. thewebsocketprotocol did.

DavidSchinazi commented 2 years ago

Apologies, I don't know the history of WebSocket too well. What's the threat model here? Who's the attacker and who's the victim?

martinthomson commented 2 years ago

The paper you might want to read "Talking to yourself for fun and profit".

The short synopsis is that there are intermediaries that try to do smart things by looking at the traffic that goes past them. Emphasis on "try" there, because some of these are colossally stupid. A small study found that passing arbitrary TCP under the noses of some intermediaries caused them to do unsafe things. Even though there was a whole lot of garbage on the connection, the intermediaries would scrub through looking for things that seemed to be HTTP requests and responses. They would then take whatever junk they saw, put it in a cache, and serve it as authoritative to other network users.

The way thewebsocketprotocol dealt with this was to make the content of frames unpredictable to websites. That's the masking trick.

There are a bunch of reasons why this is less interesting today. I'm only asking that this be considered and either deal with or deliberately acknowledged.

The other paper that is relevant here is the "NAT slipstreaming" attack, which also relies on intermediaries doing stupid things based on what they think they see on the wire. That's far more recent and relevant.

DavidSchinazi commented 2 years ago

I see, thanks for the interesting reads. Here's my understanding of the threat model: the user is served a malicious ad with malicious JavaScript. That JavaScript opens up a WebSocket/WebTransport connection to an attacker-controlled WebSocket/WebTransport server. The JavaScript then crafts WebSocket/WebTransport messages such that they send a chosen blob directly over TCP/UDP. A victim middlebox (NAT or intermediary) then interprets that blob as a command from the user and takes action.

In the WebSocket strawman proposals, the attack was very simple since the JavaScript could directly control the bytes that were sent over TCP. The fix was to have each client-to-server WebSocket message be masked using a random per-message nonce that the JavaScript has no control over.

In WebTransport, this isn't quite as bad because the application data is encrypted by the QUIC or TLS layer before being sent on the wire. However, because the WebTransport server is controlled by the attacker, it can share the TLS secrets and the packet numbers with the JavaScript, and then the JavaScript can probabilistically deduce the keymat and therefore control what ends up being sent on the wire. The attack is harder to pull off than the original WebSocket one, but not impossible. Though you could conceivably perform the same attack over HTTP/3 and HTTP/2 by sending a set of POSTs over a shared connection. WebTransport doesn't seem to open up a new attack vector, but it does make the probability of attacker success higher by giving the attacker more control over individual plaintext bytes.

I'm not seeing a port-agnostic WebTransport-layer mitigation apart from adding a random nonce to every single QUIC packet, and that would chew into the MTU and reduce performance. This becomes a tradeoff between probability of attack success and user-facing performance.

Re-reading you first message, I'm realizing that I agree with you, just that it took me a second to get there :-) Our best bet sounds like we need a UDP fetch port blocklist for HTTP/3 in general.

yutakahirano commented 2 years ago

A difference between websocket and webtransport-over-h3 (other than mandatory encryption) is the latter requires intermediaries to state their support of webtransport-over-h3 via ALPN and SETTINGS. We don't have such a mechanism for websocket - A proxy that doesn't know websocket at all could be a websocket proxy. This reduces the risk of sending webtransport-over-h3 traffic to intermediaries that misinterpret the bytes.

martinthomson commented 2 years ago

I don't think that is a meaningful difference. The attacks described are against an intermediary that doesn't care about the content of the stream unless it fits a particular pattern, with that pattern appearing anywhere.

The endpoints might agree on what the protocol is, but the intermediary is oblivious to that. In that setting, ALPN and SETTINGS do nothing to improve things. Encryption doesn't help either.

DavidSchinazi commented 2 years ago

Chair notes from IETF 112 meeting: let's punt this to the W3C: https://github.com/w3c/webtransport/issues/229