Subject: [hybi] Kitchen Sink proposal

From: John Tamplin <[email-masked]>
Date: Tue, 21 Dec 2010 16:47:00 -0500

For the reasons mentioned on the other thread, I don't
personally find TLS+NPN an acceptable solution at the
present time.  Maybe by the time we actually get something
spec'd the deployment issues will no longer be an issue,
but hopefully we can do something faster than that.

In the interest of trying to find common ground, I propose
the following sketch of a compromise (bits freely stolen
from many different proposals):

- client sends a message containing a combined
  GET+Upgrade, fake CONNECT message, and a Hello frame
  - the GET+Upgrade contains the target host header and
    URL, a client nonce, subprotocol, and requested
    extensions
  - the fake CONNECT message serves only to dissuade
    transparent intermediaries from interpreting the
    remainder
    of the connection, and is sent as a verbatim sequence
    of bytes and skipped by reading the same number of
    bytes on the server
  - the Hello frame verifies the WebSocket connection is
    fully operational.  If some attacker controlled values
    are deemed too dangerous to allow in the GET+Upgrade
    message, they could be moved here instead, though it
    does complicate things to say Hello frames can't use
    extensions (such as compression) if those are moved.
    The client->server Hello frame is preceded by a
    masking key of all 0s (so the framing is compatible
- the server receives the GET+UPGRADE, and if accepted,
  skips the CONNECT message and reads the Hello frame
- the server responds with the Upgrade response, the
  CONNECT response (sent as a verbatim sequence of bytes),
  and the Hello response
- the client sends a final Hello response to let the
  server know the connection is up and running,
- client->server frames are all masked with a per-frame
  key
  - we could let the Hello frames be the sole validation
    of a WebSocket connection being successful, in which
    case the per-frame key could just be a random value
    (which would make packet inspection easier)
  - we could have the per-frame key be derived from the
    hash of the client/server nonces and the per-frame
    random value, which would make it harder for the
    attacker to control masked payload bytes, but also
    make it harder for inspectors as they have to maintain
    state for the life of the connection
  - masking is applied by XORing successive bytes of the
    per-frame key to bytes of the frame
- The per-frame random value (length TBD, probably between
  4 and 8 bytes) is written first, followed by the masked
  frame as described in -03.
- server->client frames are as described in -03
- once the client receives the server's response, it is
  free to send user-control frames.  The server MUST NOT
  send a frame until the client's Hello response has been
  received (thus incurring a second round-trip penalty if
  the server needs to send data immediately on connection).

Thoughts?

--
John A. Tamplin
Software Engineer (GWT), Google

---

From: Scott Ferguson <[email-masked]>
Date: Tue, 21 Dec 2010 14:11:56 -0800

> from many different proposals):
[snip]
> Thoughts?

Or we can accept that reusing the HTTP port/handshake is much more 
difficult than originally estimated, use a separate port with a non-HTTP 
handshake for now, and spend the time to get HTTP/TLS-NPN/whatever correct.

If we have a working non-HTTP handshake, we can even wait the few years 
for TLS+NPN without delaying implementations further if TLS+NPN is the 
only acceptable HTTP solution.

-- Scott
> _______________________________________________
> hybi mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/hybi
>

---

From: Greg Wilkins <[email-masked]>
Date: Tue, 21 Dec 2010 23:15:54 +0100

John,

None of the bits you've "freely stolen" are show stoppers .
Having said that, I do think it is a little bit of overkill:

 + Don't really need masking and the fake CONNECT
 + why must the server wait for the client hello?
 + the per frame random data should be sent as extension data of the frame

But if I had to accept all of it in order to make progress, then maybe.

cheers

---

From: Gabriel Montenegro <[email-masked]>
Date: Tue, 21 Dec 2010 22:42:00 +0000

Thanks John,

I think this is a step in the right direction, but if we have masking, we don't need the fake CONNECT message.

It seems like the client sends all that stuff in the initial message. It cannot send anything that is non http (e.g., no hellos or fake connects) in that same message.

How about the 3 messages below:

M1: client sends GET*+Upgrade (with target host header and
    URL, a client nonce issued by the browser, subprotocol, and requested
    Extensions)

M2: the server receives the GET+UPGRADE, and if accepted,
  responds with the 101 response to the Upgrade, CR LF, empty line, and now (it's already not HTTP so it's ok)
  a Hello (in websocket framing) whose content includes a server nonce followed by the hash of concatenating: 
  the client nonce, the server nonce and the string "WebSocket M2".

 Immediately following this frame (not necessarily in a different TCP message) the server can already send 
 Data WS frames to the client.

M3:  the client initiates its data transfer. All data transfer from the client is encrypted/masked with a per-frame nonce
    of size N (other sizes can be negotiated in M1, M2).

    The first such (encrypted) frame from the client is a Hello frame (in websocket framing) whose content includes
    the server nonce followed by the hash of concatenating: the client nonce, the server nonce and the string "WebSocket M3".

   Immediately following this frame (not necessarily in a different TCP message) the client can already send 
   Data WS frames to the server.

*Instead of GET, there are merits to requiring a new method WEBSOCKET (not optional, required), but that's a separate thread

Gabriel

> -----Original Message-----
> From: [email-masked] [mailto:[email-masked]] On Behalf Of
> John Tamplin
> Sent: 21 December, 2010 13:47
> To: Hybi
> Subject: [hybi] Kitchen Sink proposal
> 
> For the reasons mentioned on the other thread, I don't personally find
> TLS+NPN an acceptable solution at the present time.  Maybe by the time we
> actually get something spec'd the deployment issues will no longer be an issue,
> In the interest of trying to find common ground, I propose the following
> sketch of a compromise (bits freely stolen from many different proposals):
>

---

From: Ian Fette (イアンフェッティ) <[email-masked]>
Date: Tue, 21 Dec 2010 14:51:06 -0800

I think it's a bit early to give up on NPN. Java as a language has issues
(we've already thrown in a number of weird things for Java, such as 63-bit
lengths due to the lack of a 64-bit unsigned integer type, not to mention
its bundled SSL stack). I don't think we should let that hold us back.

As for other things (such as platforms requiring NPN support), at the end of
the day when making a new protocol there will end up being changes required
in the stack. That's why we are doing this in IETF, so that we can come up
with a protocol that is clean and sound, get consensus, standardize, and
implement.

I really don't like the idea of using GET+Upgrade, which seems to not be
well understood by intermediaries, and then throwing a bunch of mitigations
at it hoping that we avoid security issues.

I think the solution proposed on the other thread is actually rather
reasonable. Define a port(s) for WebSockets that will be expected to be
WS-only. Don't worry about a complex handshake on that port. In parallel,
make progress with NPN for 443. Not everyone will be able to implement it
right away, but that shouldn't stop us from coming up with a good solid
proposal, implementing it and getting data, refining, and pushing for a
standard.

I would find it personally tragic if we let the current limitations of e.g.
Java define what we can do for the next 10 years of web protocol
development.

-Ian

---

From: Willy Tarreau <[email-masked]>
Date: Wed, 22 Dec 2010 00:03:23 +0100

> proposal, implementing it and getting data, refining, and pushing for a

While I like the principle of working to get it to work alone first and
then see how to transport it over existing protocols, valid reasons were
raised to have the protocol work over port 80 (ease of reuse of existing
filtering components/rules in enterprise, server stickiness, IP/port
sharing between multiple hosts, etc...). That should not be forgotten
either.

> Java define what we can do for the next 10 years of web protocol

This is not the best argument. Concerns about current known implementation
bugs in <1% of deployments could hardly be seen as a valid reason for
dropping support for a standard-compliant handshake. With either the
fake CONNECT request or the payload masking, we have a way to later
simplify the handshake if we want once implementations get better.

Regards,
Willy

---

From: John Tamplin <[email-masked]>
Date: Tue, 21 Dec 2010 18:34:48 -0500

On Tue, Dec 21, 2010 at 5:51 PM, Ian Fette (イアンフェッティ) <[email-masked]> wrote:
> its bundled SSL stack).

I don't anyone realistically expects us to need the 64th length bit,
and it isn't just Java -- many OSes have 64-bit signed values where
using a 64-bit unsigned length value could prove problematic, as could
handling overflow when adding 64-bit values.  So, I don't view that as
a particularly Java-specific concession, but rather a pragmatic limit
to avoid complications in a number of places.

> I don't think we should let that hold us back.

See below.

> at it hoping that we avoid security issues.

Well, the idea was that we appear to have overlapping groups with
apparently non-negotiable requirements.  Maybe if we include all the
pieces, everyone will be happy enough they won't object, and then the
only objection we will have left is implementation complexity and
performance issues from everything thrown in, and I tried to include
mitigations for the performance concerns such as only masking in the
client->server direction and not using AES.

> proposal, implementing it and getting data, refining, and pushing for a

I proposed exactly that a few months ago and it was quickly shot down.
 Maybe that has changed, but I doubt it.

> Java define what we can do for the next 10 years of web protocol

If we specify something that nobody can actually deploy today on their
servers, why would they make the effort to rewrite their app to use
WebSockets instead of Comet?  If we specify a protocol that is great
but nobody uses it, what have we accomplished?  The past is littered
with perfectly serviceable protocols which died from disuse for
whatever reason, and we don't want WebSockets to be another one.

It isn't just the lack of TLS-NPN implementations, but there isn't
even a standard for it yet.  Before servers will implement it, it has
to be a standard, common libraries such as OpenSSL have to ship using
it (and don't forget all the servers that are running enterprise OSes
where they don't just upgrade major components and instead backport
just security fixes to them), then the implementation
language/libraries have to support it and get deployed (for
Java/python/perl/etc), then the servers have to be updated to support
it -- all of that is going to be a very slow process.

Contrast that with the current protocol, where an implementation can
be developed on exactly what is there today - a simple implementation
can be done in an afternoon, and a more complex/performant one in a
few weeks.  Jetty added support for earlier handshakes without having
to wait for any infrastructure updates.  pywebsockets was written so
Apache apps could use it, etc.  That seems like a much more likely
path to adoption than requiring something years away.

If servers can't deploy it, then clients won't be written to use it
(other than for places like Google that can afford to write all of the
infrastructure).

---

From: Greg Wilkins <[email-masked]>
Date: Wed, 22 Dec 2010 00:43:56 +0100

2010/12/21 Ian Fette (イアンフェッティ) <[email-masked]>:
> I think it's a bit early to give up on NPN.

Well I've never been an advocate of there being only 1 true handshake,
so I don't think having a mechanism that works for port 80 precludes
NPN on 443 or something direct on a dedicated port.

> well understood by intermediaries,

While this is indeed a weakness of upgrade, it is not so when compared
to NPN. Upgrade is at least a defined standard that is supported by
more that 70% of real deployments. NPN is not yet supported at all and
is not yet a standard.

> Java define what we can do for the next 10 years of web protocol

I don't think it fair to blame java for the unavailability of NPN.
There will be many environments where roll out of something like NPN
will be slow.   If there was real demand for NPN, then I'm sure JVMs
would be available in a few months with support.  Sure this is a
chicken and egg problem, but that is the nature of rolling out new
protocols and not the fault of java.

cheers

---

From: Gabriel Montenegro <[email-masked]>
Date: Tue, 21 Dec 2010 23:54:46 +0000

> > I really don't like the idea of using GET+Upgrade, which seems to not
> > be well understood by intermediaries,
> 
> While this is indeed a weakness of upgrade, it is not so when compared to
> NPN. Upgrade is at least a defined standard that is supported by more that
> 70% of real deployments. NPN is not yet supported at all and is not yet a
> standard.

Ian, what do you mean by "seems to not be well understood by intermediaries"?

Do you mean that naïve proxies are not aware of those semantics and remain "in line" instead of putting themselves in "opaque mode" thus opening up an attack vector (as shown in Adam/Eric's paper)?
With masking/encryption it no longer matters if naïve proxies insist on remaining online, they will random garbage.

Did you mean that they will now choke and the communication will fail? Fine, reduce the success rate and eliminate these false positives (if they're that brittle they're bound to fail anyways). 

Did you mean something else? And would that matter if we incorporate masking/encryption?

Gabriel

---

From: Ian Fette (イアンフェッティ) <[email-masked]>
Date: Tue, 21 Dec 2010 15:59:40 -0800

On Tue, Dec 21, 2010 at 3:54 PM, Gabriel Montenegro <[email-masked]>wrote:

> Do you mean that naïve proxies are not aware of those semantics and remain
> "in line" instead of putting themselves in "opaque mode" thus opening up an
> attack vector (as shown in Adam/Eric's paper)?
> With masking/encryption it no longer matters if naïve proxies insist on
> remaining online, they will random garbage.
>
> Did you mean that they will now choke and the communication will fail?
> Fine, reduce the success rate and eliminate these false positives (if
> they're that brittle they're bound to fail anyways).
>
I meant the former (proxies not aware of semantics). I don't particularly
want to add masking/encryption if we don't have to, as then we have an issue
where all sorts of schools etc that want to monitor traffic are unable to do
so and we face a large deployment barrier.

-Ian

---

From: Gabriel Montenegro <[email-masked]>
Date: Wed, 22 Dec 2010 00:10:07 +0000

I meant the former (proxies not aware of semantics). I don't particularly want to add masking/encryption if we don't have to, as then we have an issue where all sorts of schools etc that want to monitor traffic are unable to do so and we face a large deployment barrier.

Gab: It’s not real encryption, and derivation by observing the stream is not difficult. I guess you’re thinking that with TLS NPN you’d be using a null cypher. This assume that the naïve proxies won’t be present in that stream, but we don’t know that as the new TLS NPN code will live together with proxies and we can argue some of those may display naiveness to the degree that has been assumed in this WG discussions. Adding masking inspection capability can’t possibly be harder than standardizing, implementing and deploying TLS NPN.

---

From: Patrick McManus <[email-masked]>
Date: Tue, 21 Dec 2010 19:49:10 -0500

On Tue, 2010-12-21 at 15:59 -0800, Ian Fette (イアンフェッティ) wrote:

>  I don't particularly want to add masking/encryption if we don't have
> to, as then we have an issue where all sorts of schools etc that want
> to monitor traffic are unable to do so and we face a large deployment
> barrier.

I too want a protocol that can be websocket-intermediary friendly. HTTP
has illustrated that infrastructure owners sometimes demand that as a
condition of operating on their infrastructure - and I actually think
that HTTPs adaptiveness to this is one of its reasons for success and we
should keep that as a web socket goal.

But, I think a per frame mask maintains that property, after all the key
is transmitted with each frame. I prefer XOR to AES, but neither is a
showstopper. Is there something about masking that prohibits a websocket
intermediary from doing monitoring?

Can you help me understand your opposition to Upgrade+Mask a little
better? It isn't my preferred position either as the per frame overhead
is a bit disappointing for length sensitive messages in mobile
environments, but I don't see it as having any critical flaws.

---

From: Ian Fette (イアンフェッティ) <[email-masked]>
Date: Tue, 21 Dec 2010 17:09:37 -0800

> intermediary from doing monitoring?
If you assume people are willing to make changes to their intermediaries for
websockets and that people will actually deploy updated intermediaries, then
sure, you can do this. However, that's a big if.

> environments, but I don't see it as having any critical flaws.
I think that for all intents and purposes, even though one could
theoretically write a WS intermediary to proxy things and scan for whatever
content, in practice people won't do that any time soon, will just treat it
as opaque, and drop the connection on us.

---

From: Gabriel Montenegro <[email-masked]>
Date: Wed, 22 Dec 2010 01:43:03 +0000

I think that for all intents and purposes, even though one could theoretically write a WS intermediary to proxy things and scan for whatever content, in practice people won't do that any time soon, will just treat it as opaque, and drop the connection on us.

Gab: You may be right, but, in practice, this will also happen with NPN since it is TLS and assumed to be opaque. They won’t know you’re using the null ciphers unless they go the extra mile, which they won’t (otherwise they could also deploy the masking inspection capability).

---

From: Brian <[email-masked]>
Date: Tue, 21 Dec 2010 17:59:51 -0800

The argument might apply to encryption but not to masking.  Schools or
whatever other institutions that want to inspect the payload of the
connection will likely need to understand the websocket framing at a
minimum in order to get it right, and from there it's a very small
step indeed to unmask the content.

Brian

---

From: Ian Fette (イアンフェッティ) <[email-masked]>
Date: Tue, 21 Dec 2010 18:07:02 -0800

That depends. If you're talking an actual HTTP proxy, then yes. If you're
talking about some really dumb thing that sits at the edge of your network
and just monitors all incoming/outgoing connections and literally looks for
strings anywhere in the connection, then no, you don't necessarily have to
understand anything.

I'm not saying that I think such a thing is a good idea, but they do exist.

2010/12/21 Brian <[email-masked]>

---

From: John Tamplin <[email-masked]>
Date: Tue, 21 Dec 2010 21:31:39 -0500

> I'm not saying that I think such a thing is a good idea, but they do exist.

You can't have it both ways -- either TLS+NPN/NULL is sufficient to
keep transparent intermediaries from misinterpreting or inspecting the
content, or it isn't.

If TLS+NPN/NULL leaves attack text in the clear, then it seems it
could still be used to attack transparent intermediaries.

---

From: Maciej Stachowiak <[email-masked]>
Date: Tue, 21 Dec 2010 19:01:10 -0800

>     state for the life of the connection

This option is better. It helps defend against the threat model of attacking a possibly-buggy WebSocket server with an HTTP client, since you can't pre-generate valid-looking  frames in an HTTP body.

>   the server needs to send data immediately on connection).

Hello frames (especially the double ones from the client) are redundant given the fake CONNECT message and masking, at least from a security POV. Thus, the extra round trip penalty is unnecessary.

Regards,
Maciej

---

From: Jamie Lokier <[email-masked]>
Date: Wed, 22 Dec 2010 19:13:50 +0000

Ian Fette (イアンフェッティ) wrote:
> 
>    On Tue, Dec 21, 2010 at 3:54 PM, Gabriel Montenegro
>    <[1][email-masked]> wrote:
> 
>      Do you mean that naïve proxies are not aware of those semantics
>      and remain "in line" instead of putting themselves in "opaque mode"
>      thus opening up an attack vector (as shown in Adam/Eric's paper)?
>      With masking/encryption it no longer matters if naïve proxies
>      insist on remaining online, they will random garbage.
>      Did you mean that they will now choke and the communication will
>      fail? Fine, reduce the success rate and eliminate these false
>      positives (if they're that brittle they're bound to fail anyways).
>    I meant the former (proxies not aware of semantics). I don't
>    particularly want to add masking/encryption if we don't have to, as
>    then we have an issue where all sorts of schools etc that want to
>    monitor traffic are unable to do so and we face a large deployment
>    barrier.

If the only problem with Upgrade, in reality, is proxies treating
Upgrade like a non-Upgrade request, why do we have to mask/encrypt the
frames?  Wouldn't it be just as effective to do the opposite, and make
the subsequent stream look like *valid* HTTP, e.g. as a very large
POST, or a pipeline of requests?

For example:

  1. GET+Upgrade
  2. POST headers, Content-Length = very large
  3. The client message data stream

where intermediaries that don't do the right thing with Upgrade in
step 1 will (perhaps) interpret the remaining stream as an opaque POST
request anyway?  They might even forward it successfully.

That could also save a round trip, if it makes it safe for the client
to send messages before receiving any response.

-- Jamie

---

From: John Tamplin <[email-masked]>
Date: Wed, 22 Dec 2010 14:39:41 -0500

> to send messages before receiving any response.

I would worry that we would be DoS'ing stupid intermediaries that tried to
buffer the post before sending it on (likewise with using chunked encoding
on the POST request, though at least it is more likely to generate an error
from proxies that try and buffer it like Squid).

Also, I suspect the people complaining about CONNECT violating the HTTP spec
would likewise complain about lying about the length (though chunked
encoding would avoid that, at the expense of the lengthInHex+CRLF for each
frame (which will likely be more than the per-frame padding of the XOR
proposal).

---

From: Jamie Lokier <[email-masked]>
Date: Wed, 22 Dec 2010 19:49:48 +0000

John Tamplin wrote:
>    I would worry that we would be DoS'ing stupid intermediaries that
>    tried to buffer the post before sending it on (likewise with using
>    chunked encoding on the POST request, though at least it is more
>    likely to generate an error from proxies that try and buffer it like
>    Squid).

Does Squid buffer all POSTs?  What about PUT, is that a better choice?
Now that it's normal to upload hundred+ MB video files over HTTP,
problems with POST-buffering can't be all that common, surely?

>    Also, I suspect the people complaining about CONNECT violating the
>    HTTP spec would likewise complain about lying about the length (though
>    chunked encoding would avoid that, at the expense of the
>    lengthInHex+CRLF for each frame (which will likely be more than the
>    per-frame padding of the XOR proposal).

I'm not proposing lying about the length, actually.  I'd go for
sending a pipelined sequence of POSTs with either large (but <31-bit)
content-length, or a sequence of little ones (instead of chunks).

A sequence of little ones would avoid the potential buffering DOS, and
avoids chunked request problems, but obviously has substantial
overhead.  On the other head, is the overhead all that much if the
headers are reduced to a minimum, and WebSocket frames batched
together whenever possible?

-- Jamie