Subject: [hybi] Counter-proposal for initial HTTP handshake

From: Dave Cridland <[email-masked]>
Date: Fri, 03 Dec 2010 12:53:05 +0000

I've finally found the time to read Adam et al's paper. It's pretty  
compelling, but I think an alternate proposal can be formed which  
provides the same properties, but does not break HTTP semantics - at  
least not quite as much.

So the primary problem is that intermediaries do fairly stupid  
things, potentially routing (or not routing) requests that aren't  
actually requests, and treating whatever replies they get as gospel.

Adam et al's assumption is that such non-requests may be interpreted  
from Websocket data flows, depending on framing characteristics. I'm  
willing to believe that this is possible, since although an  
understood framing will prevent this, it's unclear if a framing could  
be devised with reasonable properties that would also be safe against  
proxies which are not aware of the framing. (Noting that I don't  
consder "encrypt everything" to be acceptable here).

There is also a secondary problem which is that as much fun as it is  
to devise handshakes that will entirely break proxies that are not  
fully aware of websockets, the goal is to actually set up a  
functional data flow. (And, moreover, one which is proof against  
cross-protocol attacks).

The primary solutions advanced thus far appear to be either to ensure  
that the handshake itself doesn't look like an HTTP request - and  
therefore will fail to route on non-IP-based proxies - or else to  
assume that the Websocket data flows themselves cannot be so  
intrepreted.

I was wondering what happened if you reversed this logic. Let's  
assume that we have a proxy which may route based on either Host or  
IP, and that may or may not interpret data subsequent to an Upgrade,  
successful or otherwise. Combining both an Upgrade approach and Adam  
et al's CONNECT approach seemed to be an option.

Supposing our handshake looked similar to two pipelined HTTP  
requests, the first being a genuine Websocket Upgrade, and the second  
being an intentionally broken request which was actually a mechanism  
to validate the Websocket upgrade itself. So, client sends:

POST /websocket/application/url HTTP/1.1
Connection: Upgrade
Upgrade: Websocket
Sec-Websocket-Hashfn: SHA-1
Sec-Websocket-Nonce: blablahblah
Other-Headers: Also Present, but note lack of Expect: 100-continue.
Content-Type: text/xml
Content-Length: 104

<body content='text/xml; charset=utf-8'
      from=[email-masked]'
      hold='1'
      rid='1573741820'
      to='example.com'
      route='xmpp:example.com:9999'
      ver='1.6'
      wait='60'
      ack='1'
      xml:lang='en'
      xmlns='http://jabber.org/protocol/httpbind'/>

CONNECT websocket.invalid:80 HTTP/1.1
Host: websocket.invalid
Connection: close
Sec-Websocket-Result: <<base 64 of hashfn of properties above,  
suitably canonicalized>>

Now, a Host-routing proxy or an IP routing proxy that fails to  
understand Upgrade will route the first request and choke on the  
second. An attacker trying to establish a websocket for the purposes  
of proxy poisoning etc won't be able to use that, because the proxy  
will have (presumably) choked horribly on the bogus CONNECT, as with  
Adam et al's proposal.

Roy should, however, be happier since the CONNECT is no longer an  
HTTP request at all in the success case - it's the first pipelined  
phase of the Websocket. (I admit this is still bending rules quite  
considerably...)

So a server will receive one of three things, and themselves are  
either a genuine websocket server (a), or else the POSTed resource is  
not a Websocket (b).

1) a) It gets a POST+Upgrade that it understands, and also gets the  
CONNECT pseudo-request so it can validate it's really a websocket. A  
101 response and switch to Websocket framing follows.

1) b) Receives both and chokes on the CONNECT pseduo-request itself.  
Note that it'll treat the first POST as a traditional POST request.

2) a) It gets a POST+Upgrade it understands, but after a short  
timeout it gives up waiting for the CONNECT (or, more likely, has a  
TCP disconnect). It therefore responds with a BOSH session creation  
response (if the socket remains open). (You all saw that one coming,  
right? I did copy the payload directly from XEP-0124).

2) b) It gets a POST+Upgrade which it doesn't understand, and treats  
it as a POST.

3) a) The proxy strips the Upgrade, and the server receives a "bare"  
POST, and does a BOSH fallback instantly. (Note that if a proxy is  
involved, it seems unlikely that a CONNECT will follow, but if it  
does it'll simply have the effect of forcing a disconnect)

3) b) The proxy strips the Upgrade, and the server receives a "bare"  
POST, treating it accordingly.

By my reckoning - and I appreciate this is merely the sketch of an  
idea - this both defends against the attacks Adam et al have  
identified, and provides a strong likelyhood of obtaining a data flow  
of some kind in reasonably low latency (potentially with a short  
timeout involved in the fallback to BOSH case).

Key in this is that in all cases, a server is able to detirmine that  
a WebSocket request was made, even if the Upgrade fails, allowing it  
to either fallback to BOSH (if appropriate) or at the very least log  
and produce a sensible and helpful error, helping application  
providers to know penetration levels (and whether to use BOSH  
fallbacks and suitable payloads for that).

I suspect that one could use this today with existing BOSH servers  
and it'd work, incidentally.

Does this one look like a reasonable stab at an idea?

Dave.
-- 
Dave Cridland - mailto:[email-masked] - xmpp:[email-masked]
  - acap://acap.dave.cridland.net/byowner/user/dwd/bookmarks/
  - http://dave.cridland.net/
Infotrope Polymer - ACAP, IMAP, ESMTP, and Lemonade

---

From: Greg Wilkins <[email-masked]>
Date: Fri, 3 Dec 2010 14:57:01 +0100

On 3 December 2010 13:53, Dave Cridland <[email-masked]> wrote:

> Adam et al's assumption is that such non-requests may be interpreted from
> Websocket data flows, depending on framing characteristics.

Dave,

The paper has not  shown that intermediaries handle non-requests.  It
has only shown that intermediaries are vulnerable to real requests
that have got spoofed host values.
As far as I can tell, the test sent two real HTTP request, one after
the other.  The first was an upgrade requests, which the
intermediaries did not handle specially and then they just handled the
next request on the wire, which was a valid request with a spoofed
host header.  They then wrongly trusted the host header and thus were
tricked.

>  it's unclear if a framing could be devised with reasonable
> properties that would also be safe against proxies which are not aware of
> the framing.

It is very clear that framing can be devised.  HTTP is one example of
framing that well protects against this vulnerability.

> Supposing our handshake looked similar to two pipelined HTTP requests, the
> first being a genuine Websocket Upgrade, and the second being an
> intentionally broken request which was actually a mechanism to validate the
> Websocket upgrade itself....

Using a second HTTP request the frame the WS stream is certainly a possibility.

regards

---

From: Dave Cridland <[email-masked]>
Date: Fri, 03 Dec 2010 14:16:07 +0000

> host header.  They then wrongly trusted the host header and thus  
It shows a bit more than that - it shows that real requests made  
subsequent to a supposedly successful websocket handshake are  
interpreted, too. The combination allows WebSockets to be used as an  
attack vector, and the protective measure would be to ban WebSockets  
in corporate use. (The protective measure for the actual attack they  
used is to ban Flash and Java, as I understand it - also bad, but not  
our problem).

The assumption here is that such a pattern might be contrived to  
appear within websocket data flows. It doesn't require *all*  
websocket data to look like HTTP, although obviously leading  
non-HTTP-a-like data is likely to reduce the numbers of parsers  
willing to accept later HTTP-a-likes as valid.

I entirely agree that they have not demonstrated this particular  
attack, but they have demonstrated that it's a whole heap more  
plausable than one might imagine, and I don't think it's much of a  
stretch to accept it as a likely case.

> framing that well protects against this vulnerability.
No, it's not, you missed my point. HTTP is an example of a framing  
which is known to the proxies, whereas websocket framing would not be  
known.

Short of manipulating the data itself (for instance, by escaping CR  
and LF, or by encrypting the lot) it's very difficult to frame  
websocket payloads such that they cannot be at least potentially  
interpreted as HTTP. The kinds of data manipulation mentioned I  
categorise as unreasonable, incidentally.

To put it another way, if we are to have literal globs of data in the  
protocol - no encryption or escaping - I don't see a way of proving  
that the data could not be treated as an HTTP request by a  
sufficiently naïve parser.

Given the figures in the paper, however, I'm pretty confident that  
the "parser-block" of a CONNECT is sufficient to break that in the  
vast majority of cases. My concern with not doing Upgrade at all is  
that the fallback case is plain ugly. 
(Incidentally, I have *not* considered the use of encryption of the  
header fields - I have to confess I missed the reasoning behind that  
entirely).

Dave.

---

From: Roberto Peon <[email-masked]>
Date: Fri, 3 Dec 2010 09:12:48 -0800

On Fri, Dec 3, 2010 at 6:16 AM, Dave Cridland <[email-masked]> wrote:

>> from
> subsequent to a supposedly successful websocket handshake are interpreted,
> too. The combination allows WebSockets to be used as an attack vector, and
> the protective measure would be to ban WebSockets in corporate use. (The
> protective measure for the actual attack they used is to ban Flash and Java,
> as I understand it - also bad, but not our problem).
>
> The assumption here is that such a pattern might be contrived to appear
> within websocket data flows. It doesn't require *all* websocket data to look
> like HTTP, although obviously leading non-HTTP-a-like data is likely to
> reduce the numbers of parsers willing to accept later HTTP-a-likes as valid.
>
> I entirely agree that they have not demonstrated this particular attack,
> but they have demonstrated that it's a whole heap more plausable than one
> might imagine, and I don't think it's much of a stretch to accept it as a
> likely case.
>
>
>
>
>>  No, it's not, you missed my point. HTTP is an example of a framing which
> is known to the proxies, whereas websocket framing would not be known.
>
> Short of manipulating the data itself (for instance, by escaping CR and LF,
> or by encrypting the lot) it's very difficult to frame websocket payloads
> such that they cannot be at least potentially interpreted as HTTP. The kinds
> of data manipulation mentioned I categorise as unreasonable, incidentally.
>

Why do you think it unreasonable?
A simple XOR on the message payload with a browser provided nonce which
varies per clientside write(), and then the client can never control the
bits on the wire.
That is easy and cheap! I believe that Adam et. al are proposing more than
that, but that alone would be sufficient, I believe.
-=R

> protocol - no encryption or escaping - I don't see a way of proving that the
> data could not be treated as an HTTP request by a sufficiently naïve parser.
>
> Given the figures in the paper, however, I'm pretty confident that the
> "parser-block" of a CONNECT is sufficient to break that in the vast majority
> of cases. My concern with not doing Upgrade at all is that the fallback case
> is plain ugly.(Incidentally, I have *not* considered the use of encryption
> of the header fields - I have to confess I missed the reasoning behind that
> entirely).
>
>
> Dave.
> --
> Dave Cridland - mailto:[email-masked] - xmpp:[email-masked]<[email-masked]>
> _______________________________________________
> hybi mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/hybi
>

---

From: John Tamplin <[email-masked]>
Date: Fri, 3 Dec 2010 12:22:50 -0500

> that, but that alone would be sufficient, I believe.

The reason it is expensive is that doing any processing on the payload
data means you can't do the equivalent of sendfile() to let the OS
send a large file for you while you go and do other things.  Also,
even inexpensive processes matter when you have to worry about very
large scale -- doubling the cost of processing WebSocket payload data
on a machine serving thousands or millions of them is a problem.

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

---

From: Joe Mason <[email-masked]>
Date: Fri, 3 Dec 2010 12:37:44 -0500

> -----Original Message-----
> From: [email-masked] [mailto:[email-masked]] On Behalf Of
> Dave Cridland
> Sent: Friday, December 03, 2010 7:53 AM
> To: Server-Initiated HTTP
> Subject: [hybi] Counter-proposal for initial HTTP handshake
> 

At first glance I like this proposal, as it seems to address the objections to CONNECT, but I suggest leaving the POST body open for extension for now.  We already have enough concerns being addressed - we can discuss BOSH fallback later.

Joe

---------------------------------------------------------------------
This transmission (including any attachments) may contain confidential information, privileged material (including material protected by the solicitor-client or other applicable privileges), or constitute non-public information. Any use of this information by anyone other than the intended recipient is prohibited. If you have received this transmission in error, please immediately reply to the sender and delete this information from your system. Use, dissemination, distribution, or reproduction of this transmission by unintended recipients is not authorized and may be unlawful.

---

From: Roberto Peon <[email-masked]>
Date: Fri, 3 Dec 2010 10:05:40 -0800

> on a machine serving thousands or millions of them is a problem.

I don't see how we can easily have it all ways. A malicious server+client
can redirect to another host:port, then the client can request a websocket
to it, and possibly cause harm there if it controls the bytes of payload and
the handshake isn't enough to cause every different server and protocol to
reject it.

It would be trivial to modify sendfile() to do an xor per write(). We
already have to break things apart into packets and enqueue into the various
TCP structures. I doubt we'd notice the speed difference.
-=R

---

From: Dave Cridland <[email-masked]>
Date: Fri, 03 Dec 2010 20:39:50 +0000

> that, but that alone would be sufficient, I believe.

Usage of sendfile() has been raised before - this would prevent it.  
If you don't do this, then taking a payload and running a XOR over it  
is not free - it means walking a string in custom-written code (not a  
hand-crafted ASM function), which is not cheap.

In any case, we're talking about a possible error which Adam et al  
didn't detect in their tests over 54,534 samples.

That's not to say that one does not exist, but it's a pretty small  
chance, and hence doesn't seem to present a high enough attack  
surface to be worthwhile introducing any inefficiency or limitation  
in the protocol for. It's just one for the Security Considerations,  
and leave it at that.

Dave.

---

From: Dave Cridland <[email-masked]>
Date: Fri, 03 Dec 2010 21:20:07 +0000

On Fri Dec  3 17:37:44 2010, Joe Mason wrote:
> At first glance I like this proposal, as it seems to address the  
> objections to CONNECT, but I suggest leaving the POST body open for  
> extension for now.  We already have enough concerns being addressed  
> - we can discuss BOSH fallback later.

You're quite right.

Actually, it occurs to me that any request at all can be used as the  
Upgrade, since the request itself is a fallback, whether this is a  
GET, POST, or any other method. Obviously the existing browser API  
doesn't support that choice right now, but it could do (and it is, as  
far as I can tell from RFC 2616, how the Upgrade mechanism was meant  
to be used.

So the choice of *what* fallback to use, and if any should be  
standardized, can be deferred.

Dave.

---

From: Willy Tarreau <[email-masked]>
Date: Fri, 3 Dec 2010 22:48:20 +0100

> Using a second HTTP request the frame the WS stream is certainly a possibility.

In fact it's been the principle of the HTTP-incompatible Hello message from the
beginning : try to have something that can make intermediaries break the
connection ASAP if they don't understand it as we like.

Willy

---

From: Willy Tarreau <[email-masked]>
Date: Fri, 3 Dec 2010 22:53:52 +0100

On Fri, Dec 03, 2010 at 10:05:40AM -0800, Roberto Peon wrote:
> can redirect to another host:port,

If both sides are malicious, WS is not required, use plain normal HTTP to
attack the intermediary then.

> It would be trivial to modify sendfile() to do an xor per write().

Precisely not because sendfile() does not use write(). Its goal is to map
data files in memory, pass a few headers to the network interface and tell
it "send that" without the CPU ever touching the data. It's obviously trivial
to do a XOR on a normal read+send operation but that completely voids the
purpose of sendfile().

> TCP structures. I doubt we'd notice the speed difference.

It depends at what byte rate. At 10 Gbps of forwarding speed, a Core i3 @3 GHz
I'm currently testing reaches 100% CPU when doing recv+send, and less than 20%
when doing splice() (=sendfile).

Regards,
Willy

---

From: Maciej Stachowiak <[email-masked]>
Date: Fri, 03 Dec 2010 14:10:37 -0800

> attack the intermediary then.

The threat model in Adam & Eric's paper cannot be executed with HTTP APIs built into the browser. You can't use XHR or forms to send an Upgrade request. The flaw is based on the intermediary thinking that the initial HTTP request message is over, but client JavaScript being able to send more data down that pipe.

Regards,
Maciej

---

From: Eric Rescorla <[email-masked]>
Date: Fri, 3 Dec 2010 14:23:36 -0800

> attack the intermediary then.

that would be true under an ordinary threat model, but the threat model here
is different:

- A malicious site
- A malicious piece of HTML/JS living in the Web security sandbox

In these situations, the sandbox limits the power of the malicious script.

-Ekr

---

From: Willy Tarreau <[email-masked]>
Date: Fri, 3 Dec 2010 23:26:09 +0100

> The threat model in Adam & Eric's paper cannot be executed with HTTP APIs built into the browser. You can't use XHR or forms to send an Upgrade request. The flaw is based on the intermediary thinki…

I've not talked about using a browser. Roberto was suggesting that both the
server and the client are malicious. To me, a malicious client means a client
that is completely under control, which does not necessarily mean a browser
with limited abilities.

Regards,
Willy

---

From: Willy Tarreau <[email-masked]>
Date: Fri, 3 Dec 2010 23:26:49 +0100

> In these situations, the sandbox limits the power of the malicious script.

OK with this definition of malicious client I agree.

Cheers,
Willy

---

From: Zhong Yu <[email-masked]>
Date: Fri, 3 Dec 2010 17:14:09 -0600

> that is completely under control, which does not necessarily mean a browser

One can argue that since the attacker can use Flash/Java to open raw
sockets and send any data he chooses to confuse intermediaries,
WebSocket stream however designed will not worsen the situation. It is
intermediaries that should be fixed, since they are already vulnerable
to Flash/Java sockets, and there is no chance that Flash/Java remove
raw sockets.

I agree with this in principle. Suppose WebSocket with minimal
framing/masking is widely deployed, and it is used to do attacks
described in the paper, it's unfair to blame WebSocket.

However it's not totally in vain to guard WebSocket against these
attacks. If WebSocket is safer, unilaterally, people may choose to
disable Flash/Java sockets, to improve their security.

---

From: Maciej Stachowiak <[email-masked]>
Date: Fri, 03 Dec 2010 15:17:56 -0800

> to Flash/Java sockets, and there is no chance that Flash/Java remove

But browsers or users can remove or disable Flash and Java if they choose.

Regards,
Maciej

---

From: Bjoern Hoehrmann <[email-masked]>
Date: Sat, 04 Dec 2010 00:35:04 +0100

>to validate the Websocket upgrade itself. So, client sends:

I was wondering about the combination of pipelined requests and Upgrade
http://lists.w3.org/Archives/Public/ietf-http-wg/2010JulSep/0293.html a
while ago. Assuming you are actually saying you would send both requests
at the same time, you are creating a situation where the HTTP message
framing depends on the server's response; you can run, for instance, in-
to semantic and timing problems, for instance, a dispatcher may or may
not treat the second request as genuine new request while the handler
for the first request is still busy deciding whether to accept it. It's
not a common sight in HTTP implementations that the part that interprets
Content-Length and Transfer-Encoding and such, pays attention to Upgrade
headers.

So this is not an area I'd particularily like to explore, and I would
expect RFC2616bis to say what you propose is wrong, as indicated in the
thread mentioned above. It would be helpful if you ask for feedback in
the httpbis Working Group on this in any case.
-- 
Björn Höhrmann · mailto:[email-masked] · http://bjoern.hoehrmann.de
Am Badedeich 7 · Telefon: +49(0)160/4415681 · http://www.bjoernsworld.de
25899 Dagebüll · PGP Pub. KeyID: 0xA4357E78 · http://www.websitedev.de/

---

From: Roberto Peon <[email-masked]>
Date: Fri, 3 Dec 2010 16:23:17 -0800

> when doing splice() (=sendfile).

You have a NIC that does scatter gather. I'd forgotten these are common now.
Yes, you're right. Assuming we have scatter-gather available, the XOR will
be substantially less efficient.

-=R

---

From: Bjoern Hoehrmann <[email-masked]>
Date: Sat, 04 Dec 2010 01:38:37 +0100

>on a machine serving thousands or millions of them is a problem.

(I do note in passing that client->server and server->client do not
necessarily have to use the same message format; the two directions
differ greatly in their achievable throughputs, odds of long messages,
and security considerations in most settings. Unfortunately, as far
as security goes, server->client has not been studied all that much.)
-- 
Björn Höhrmann · mailto:[email-masked] · http://bjoern.hoehrmann.de
Am Badedeich 7 · Telefon: +49(0)160/4415681 · http://www.bjoernsworld.de
25899 Dagebüll · PGP Pub. KeyID: 0xA4357E78 · http://www.websitedev.de/

---

From: Greg Wilkins <[email-masked]>
Date: Sat, 4 Dec 2010 08:43:01 +0100

On 3 December 2010 23:10, Maciej Stachowiak <[email-masked]> wrote:

> The threat model in Adam & Eric's paper cannot be executed with HTTP APIs built into the browser. You can't use XHR or forms to send an Upgrade request.

True.

But then the bytes sent in Adam & Erics paper cannot be executed with
the WS APIs either.
The used flash to send 2 HTTP requests, the first looking like part of
a WS handshake and the second had a spoofed Host header.

> The flaw is based on the intermediary thinking that the initial HTTP request message is over, but client JavaScript being able to send more data down that pipe.

... but client JavaScript being able to send more data down that pipe
that the intermediary will interpret as another HTTP request.

Some think that CONNECT might prevent intermediaries from interpreting
data that follows as HTTP request, but have only empirical "proof" of
that.
We know that that HTTP framing of the following user data is good
enough to prevent the spoofed host header.
Some say that WS framing will also prevent it, others say that it is weak.
We think that XORing all data will prevent it, but there are concerns
with attackers being able to game the XOR.

cheers

---

From: "Simon Pieters" <[email-masked]>
Date: Mon, 06 Dec 2010 10:52:11 +0100

> as security goes, server->client has not been studied all that much.)

Indeed. Maybe there's no reason to mask the server-sent messages at all.  
It has been pointed out that masking is a performance hit for sendfile()  
use cases.

If the server is under the attacker's control, he can send whatever he  
wants, so masking doesn't help there. If the server is legitimate but the  
attacker succeeds with connecting to it with XHR or something and can read  
the bytes, then masking doesn't help since the attacker can unmask. Are  
there other scenarios where it is helpful to mask the server-sent messages?

-- 
Simon Pieters
Opera Software

---

From: Dave Cridland <[email-masked]>
Date: Tue, 07 Dec 2010 09:41:14 +0000

> the httpbis Working Group on this in any case.

I was wondering about this as well, and I think you're quite right to  
call me out on this.

The alternative is to wait for the 101 prior to sending the  
pseudo-CONNECT, which does introduce a round-trip delay (but one  
that's likely to be acceptable, and moreover useful, as we can use  
the 101 response to determine if the endpoint really is willing to  
speak websocket).

Dave.

---

From: Dave Cridland <[email-masked]>
Date: Tue, 07 Dec 2010 09:44:08 +0000

On Sat Dec  4 07:43:01 2010, Greg Wilkins wrote:
> > The threat model in Adam & Eric's paper cannot be executed with  
> HTTP APIs built into the browser. You can't use XHR or forms to  
> send an Upgrade request.
> 
> True.
> 
Right, hence the discussion a while back about parsers being  
remarkably liberal in finding HTTP requests amongst trash data.

> > The flaw is based on the intermediary thinking that the initial  
> HTTP request message is over, but client JavaScript being able to  
> send more data down that pipe.
> 

We have a hypothesis that's to be backed up by experimental data. I  
don't like the conclusion from an aesthetic standpoint any more than  
many here, but I can't find any flaw in the basic argument.

> enough to prevent the spoofed host header.

This is entirely irrelevant, I'm afraid - the intermediaries are  
assumed to understand basic HTTP framing - in fact this is to some  
extent the core of Adam et al's hypothesis, that the intermediaries  
are finding HTTP frames even when, technically, they are not present.

> with attackers being able to game the XOR.

We also know from the experimental data that there is a very small  
chance that an intermediary will attempt to interpret data after it  
sees a CONNECT. In particular, the experimental data shows that there  
are sufficiently few cases where an intermediary can be attacked (via  
cache-poisoning) that none were found.

I understand the basis of obfustcating the websocket metadata and  
data flows themselves using encryption technology, however I also  
feel that the very paper that proposes it also clearly demonstrates  
why it's not needed.

I'm fine with tackling hypothetical threats, but when they've been  
demonstrated not to be detectable in the field, I think that even if  
they do exist, they represent too small an attack surface to be worth  
more than a note or two in the security considerations section.

Dave.