Subject: [hybi] Fwd: Gen-ART last call review of draft-ietf-hybi-thewebsocketprotocol-10

From: Peter Saint-Andre <[email-masked]>
Date: Wed, 20 Jul 2011 20:46:03 -0600

FYI, this was sent to [email-masked] but not the WG list.

-------- Original Message --------
Subject: Gen-ART  last call review of 
draft-ietf-hybi-thewebsocketprotocol-10
Date: Tue, 19 Jul 2011 23:01:53 -0400
From: Richard L. Barnes <[email-masked]>
To: General Area Review Team <[email-masked]>, 
[email-masked],	IETF Discussion 
<[email-masked]>

I am the assigned Gen-ART reviewer for this draft. For background on
Gen-ART, please see the FAQ at
<http://wiki.tools.ietf.org/area/gen/trac/wiki/GenArtfaq>.

Please resolve these comments along with any other Last Call comments
you may receive.

Document: draft-ietf-hybi-thewebsocketprotocol-10.txt
Reviewer: Richard Barnes
Review Date: 19 July 2011
IETF LC End Date: 25 July 2011
IESG Telechat date: (if known) -

Summary:
Not ready.

Major issues:

[Is GET/Upgrade appropriate?]
It seems like the use of GET here goes beyond the normal "safe" 
semantics for that method.  To quote RFC 2616:
"
    In particular, the convention has been established that the GET and
    HEAD methods SHOULD NOT have the significance of taking an action
    other than retrieval.
"
In addition, alternative protocols specified in Upgrade headers are 
generally optional, whereas in this case, the transaction fails overall 
if the server does not support the websocket protocol.  It doesn't look 
to me like any of the current methods provide much better semantics 
(except possiblyCONNECT or the use of OPTIONS as in RFC 2817), and it 
seems like defining a new method could help get around the Upgrade issue 
as well.

[Huge buffers]
The frame length can be 7, 16, or 64 bits long.  Since the client is 
expected to buffer data until the end of a frame, this is asking clients 
to buffer 128 B, 64 KB, or 16 EB.  If it were 32 bits, the max would be 
4 MB.  Why not just make this a 32-bit fixed length field?

[Why is masking necessary?]
I seriously question the necessity of the masking of data frames.  As I 
understand it, the goal is to prevent proxies that don't understand 
Upgrade from confusing WebSocket data with HTTP data.  This risk seems a 
little dubious to me; has such a poisoning attack been demonstrated?  It 
seems like there are much simpler ways of doing this, like using a 
method other than GET (either CONNECT or something new).

[Why only client-to-server masking?]
Why isn't masking required on server-to-client frames?

[Unlimited buffering with fragmentation]
Much like with the frame length issue above, the fragmentation mechanism 
here seems like it imposes a heavy burden on the receive side.  Since 
the receiving client is supposed to buffer data until the end of a 
frame, it seems like fragmentation could be used to cause a receiving 
client to buffer a frame of indefinite size.

Minor issues:

[Setting protocol]
In the NOTE in Section 1.3, the document observes that Sec- headers 
can't be set in XHRs.  But clearly the Sec-WebSocket-Protocol header can 
be set through some API that applications use to get to this protocol. 
So it seems a little misleading to imply that scripts can't set these 
headers (besides -Version and -Origin).

[Use existing Origin header]
Why is this document creating a separate Sec-WebSocket-Origin header, 
rather than using the Origin header from draft-ietf-websec-origin?

[Need a reference to CORS]
It would be helpful to have a reference to Cross-Origin Resource Sharing 
in the NOTE in this section, since the pre-request check that is 
described is exactly a CORS priming request.

[Key is over-engineered]
What is the need for the hash and GUID in the handshake processing of 
the key?  It seems like it would be sufficient for the server to do 
anything deterministic with the key, even something as simple as 
incrementing it or flipping the bits.

Nits / Editorial comments:

[Why not plain sockets?]
The introduction makes clear why this protocol is needed instead of 
HTTP, but not why this protocol improves over providing a plain socket 
interface.  Presumably this is because the HTTP header provides a space 
where the browser can inject trusted information?

[Put the handshake section first]
It would really increase readability to put all the 
negotiation/handshake parts up front, before you get to the data format 
(Section 4).  As it is, when I got to the extension data part, I didn't 
realize that there was an extension mechanism, since it hadn't been 
mentioned yet.

[Stray sections]
It seems like Section 8 (Error Handling) should be moved up to Section 
4.6, and Section 9 (Extensions) should be part of section 4.

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

---

From: David Endicott <[email-masked]>
Date: Wed, 20 Jul 2011 23:18:17 -0400

Thanks for this Peter.   I believe the reviewer actually summarized the
consensus of the dissenters rather well.

---

From: John Tamplin <[email-masked]>
Date: Wed, 20 Jul 2011 23:23:27 -0400

On Wed, Jul 20, 2011 at 10:46 PM, Peter Saint-Andre <[email-masked]> wrote:
> Subject: Gen-ART  last call review of draft-ietf-hybi-thewebsocketprotocol-10
> To: General Area Review Team <[email-masked]>, [email-masked], IETF Discussion <[email-masked]>
>
> The frame length can be 7, 16, or 64 bits long.  Since the client is expected to buffer data until the end of a frame,
> this is asking clients to buffer 128 B, 64 KB, or 16 EB.  If it were 32 bits, the max would be 4 MB.  Why not just
> make this a 32-bit fixed length field?

It is a compromise to get everyone to agree.  There were several
requirements different groups were interested in:
 - Small frames should have minimal overhead.  A chat program sending
individual keystrokes should not have to pay
   an extra 3 bytes of length, and there are small packet thresholds
to consider for mobile environments, where larger
   packets require powering up the radio to a higher power state.
 - Some people wanted to be able to use facilities like Unix's
sendfile to transmit an entire file without having to stay in
   the loop and write framing.  For future compatibility, this
requires a larger size than 4G.  Just like IPv6, it seemed
   better to use an "obviously large enough" value rather than argue
further about exactly how large it would need to be.
 - Having a variable-size length field means the cost to support the
very large buffers is small (one value wasted of the
   lead length byte), while saving a significant percentage of the
frame size for very small payloads.

As there were holdouts on both the side of wanting small headers for
small frames and wanting to send large messages without having to
fragment, this compromise was necessary to make progress.

> I seriously question the necessity of the masking of data frames.  As I understand it, the goal is to prevent
> proxies that don't understand Upgrade from confusing WebSocket data with HTTP data.  This risk seems a
> little dubious to me; has such a poisoning attack been demonstrated?  It seems like there are much simpler
> ways of doing this, like using a method other than GET (either CONNECT or something new).

There was a very long, contentious discussion about this based on
security research that found transparent proxies could be fooled into
believing the content following the WebSocket handshake was HTTP,
allowing poisoning a transparent cache -- imagine if an attacker could
replace the contents of www.google.com/ga.js on some cache serving
many users, basically it is a wildcard XSS for users of those caches.
There was no attack demonstrated using WebSocket framing, but it was
demonstrated using just the WS handshake followed by user-controlled
data.

The scenario here is that the attacker controls the server completely
and controls the JS code running in the client - what is to be
protected is transparent intermediaries which by their nature cannot
participate in the protocol so we cannot determine their compatibility
in order to proceed.  While there was some discussion of approaches to
limit the risk to currently discovered vulnerabilities (such as
sending a bogus CONNECT message as part of the handshake), a few
people were concerned that further vulnerabilities could be discovered
and that masking the client->server traffic prevented attacker control
over those bytes at an acceptable cost.

> Why isn't masking required on server-to-client frames?

In the attack scenario, the server is under complete control of the
attacker and can send any bytes it chooses anyway.

> Much like with the frame length issue above, the fragmentation mechanism here seems like it imposes a
> heavy burden on the receive side.  Since the receiving client is supposed to buffer data until the end of a
> frame, it seems like fragmentation could be used to cause a receiving client to buffer a frame of indefinite size.

Obviously, an implementation will have to have a maximum size message
that it can support.  In the spec as written, the only recourse when
this size is exceed is to terminate the connection (perhaps retrying
sending smaller messages).  There have been some proposals to allow
each side to state their maximum frame and/or message sizes in the
handshake, but there hasn't been agreement to put them in the spec.

> [Why not plain sockets?]
> The introduction makes clear why this protocol is needed instead of HTTP, but not why this protocol
> improves over providing a plain socket interface.  Presumably this is because the HTTP header provides
> a space where the browser can inject trusted information?

The browser is executing code on behalf of a potential attacker, and
would not give access to raw TCP sockets to such code as that would
allow circumvention of many protections, such as scanning machines
behind a corporate firewall, for example.  If you mean just opening a
socket subject to the same origin restrictions, you would have to have
a special handshake to validate those restrictions, and you need some
framing to delineate messages since TCP is just a stream of bytes and
the API is message-oriented.  If you do those things, then you have
essentially WebSockets (of course you could solve the same problems in
different ways, but it is the same class of solution).

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

---

From: "Thomson, Martin" <[email-masked]>
Date: Thu, 21 Jul 2011 11:37:11 +0800

> > [Why is masking necessary?]
...

To those providing responses to review comments like this, consider for a moment that perhaps the draft does not - and should - provide the answer.

You can pre-empt the question by having clear and unequivocal reasons in the document itself.  Then you need only let it talk for you.
 
For this particular question, reasoning is included in the security considerations section, but not at the point that the mechanism is first encountered.  A forward reference would resolve this.

The same applies to some of the other comments (and responses).

Information on working group consensus is probably the only thing that needs to be communicated in review responses (though as a reviewer, I find those sorts of responses deeply dissatisfactory).

--Martin

---

From: John Tamplin <[email-masked]>
Date: Wed, 20 Jul 2011 23:44:00 -0400

On Wed, Jul 20, 2011 at 11:37 PM, Thomson, Martin
<[email-masked]> wrote:
> To those providing responses to review comments like this, consider for a moment that perhaps the draft
> does not - and should - provide the answer.

There was discussion about that to, and the majority opinion (not
mine) was that rationale did not belong in the spec.  If warranted, a
separate rationale document could be written.

---

From: David Endicott <[email-masked]>
Date: Wed, 20 Jul 2011 23:44:22 -0400

Speaking as an unauthorized spokesperson for dissenters....

On Wed, Jul 20, 2011 at 11:23 PM, John Tamplin <[email-masked]> wrote:

> expected to buffer data until the end of a frame,
> > this is asking clients to buffer 128 B, 64 KB, or 16 EB.  If it were 32
> bits, the max would be 4 MB.  Why not just

> fragment, this compromise was necessary to make progress.

It was my perception that in general people were agreed on the obvious
choices (minimize overhead, be flexible), nobody had the energy/interest to
challenge the ridiculous, as we'd all just ignore it or crash in our real
world implementations.

> security research that found transparent proxies could be fooled into

I've not seen this research.

> There was no attack demonstrated using WebSocket framing, but it was

Ah.

> The scenario here is....

Giving me qualms of plausibility.  But I would challenge instead that this
is a fault of the intermediaries and not our problem.

> attacker and can send any bytes it chooses anyway.

The dissenting consensus was that half an ass of security was not a donkey
we wanted to hitch our cart to.

> here seems like it imposes a

Allowing streaming is a laudable goal, but WS comes out of the gate as a
framing protocol.

> different ways, but it is the same class of solution).

I don't believe anyone suggested raw TCP sockets.    In John's example, he
is referring strictly to browser clients.   As a programmer guy, I can write
a websocket client in whatever language I want and pretend to be a websocket
as polite or malicious as I want.

I believe there are some who were hoping websockets would be a lightweight
transport protocol (a la TCP) that could be made available in a browser with
the understanding that the browser implementation of such a client would
apply appropriate security models.     Some of us are worried that the
design has suffered from concerns outside it's problem domain.

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

---

From: David Endicott <[email-masked]>
Date: Wed, 20 Jul 2011 23:48:27 -0400

I hope you understand the anxiety around this issue.

>We're doing masking
Why?
> Because (somebody said they researched and besides we can imagine...)
Explain please.
> No.  If anyone else asks, somebody might blog some reasoning

---

From: John Tamplin <[email-masked]>
Date: Wed, 20 Jul 2011 23:57:26 -0400

> is a fault of the intermediaries and not our problem.

Sure. But the publication of the research led Safari and Firefox to
disable draft versions of WebSocket in their browsers because they
didn't want to be on the news for "Browser <xxx> led to an attack on
<yyy> thousand users ...".

By the nature of transparent intermediaries, it is hard to discern
information about them to do anything sensible with vulnerable ones,
such as disallow WebSocket operation, notify administrators, etc.

You could say users browsing to sites containing hostile code or
phishing is the fault of the user and it is their problem, but browser
vendors still want to help prevent damage to such users.

> as polite or malicious as I want.

Certainly you can write WebSocket clients other than browsers.
However, most of the security restrictions come about because it is to
be used by a browser executing potentially hostile code.  If you
aren't a browser and are running your code directly on the client
machine, then obviously you can already do whatever you want.

---

From: Willy Tarreau <[email-masked]>
Date: Thu, 21 Jul 2011 07:57:25 +0200

> vendors still want to help prevent damage to such users.

And with the current masking, even if we don't like it much, at least it
comes at very little cost and serves the purpose quite well.

> machine, then obviously you can already do whatever you want.

I would also add that in many environments, proxies are configured as
mandatory for browsers. Relying on HTTP ensures that the browser will
use the proxy and not try to scan local networks. And it's the only
way to enable WS connections to be initiated outside via proxies in
those environments.

Willy

---

From: Bruce Atherton <[email-masked]>
Date: Thu, 21 Jul 2011 14:01:38 -0700

I highly suggest that anyone with concerns around masking take a look at 
the FAQ[1]. Skip down to the section labelled "FAQS", that is where the 
useful information is to be found, particularly the odyssey involved in 
coming to a decision on masking to be found in the answer to the 
question "Why does the WebSockets protocol use masking from the client 
to the server?".

There are lots of issues, lots of solutions, and lots of objections to 
every one of the solutions. If a reviewer is going to question the 
utility of masking they should make themselves aware of that FAQ so that 
they can properly understand the context.

Should some portion of that answer be put into the spec? The WG decided 
that it was too complicated and distracted from defining the protocol. 
If a reviewer thinks some portion SHOULD be included, then my personal 
opinion is that wording should be presented to the working group to be 
considered for consensus and adoption.

[1] http://wiki.tools.ietf.org/wg/hybi/trac/wiki/FAQ

On 20/07/2011 8:48 PM, David Endicott wrote:
> On Wed, Jul 20, 2011 at 11:44 PM, John Tamplin <[email-masked] 
> <mailto:[email-masked]>> wrote:
>
>     <[email-masked]
>     <mailto:[email-masked]>> wrote:
>     > To those providing responses to review comments like this,
>     consider for a moment that perhaps the draft
>     [email-masked] <mailto:[email-masked]>