Subject: [hybi] A WebSocket handshake

From: Adam Barth <[email-masked]>
Date: Tue, 5 Oct 2010 15:15:22 -0700

Please find below a proposal for a new WebSocket handshake.  The
handshake attempts to combine the benefits of the HTTP handshake with
the benefits of a TLS-based handshake.  The handshake incorporates
ideas from a number of the other handshakes discussed previously,
including those from Maciej Stachowiak, Ian Hickson, and Greg Wilkins.
 In addition to proposing a handshake, the document also contains a
threat model and a security analysis.  Feedback appreciated.

Kind regards,
Adam

Pretty HTML version:

https://docs0.google.com/document/edit?id=1hRLcVc8FHsXOQvaulG2KmvGKepgFffcevyJn-dAEsrI&hl=en&authkey=COOWhaAD&pli=1

Not-so-pretty text version:

= A WebSocket Handshake =

Adam Barth
Eric Rescorla
October 5, 2010

== Introduction ==

This document describes a handshake for the WebSocket protocol that
resists cross-protocol attacks.  The handshake sends a fixed sequence
of bytes and a random nonce from the client to the server to establish
two keys for a bidirectional encrypted tunnel, which the parties then
use for further communication.  Although an eavesdropper can determine
the encryption keys, computing the keys requires knowledge of a
globally unique identifier, making it unlikely that an observer
unfamiliar with the the WebSocket protocol will interpret the
encrypted bytes on the wire as anything other than random bytes.
Before explaining the handshake, we present a model of the threats
posed by exposing a new network protocol to untrusted content running
in a web browser.  We then work through some simple handshake designs
to build intuition for what can go wrong in a flawed design.

== Threats ==

In this document, we evaluate the risks posed by exposing the
WebSocket protocol to untrusted web content in a standard web browser.
 We make the usual assumption in web security that the user visits the
attacker’s web site.

Web browsers already expose an HTTP-based networking facility to
untrusted web content.  In designing WebSockets, we are concerned with
the additional risks incurred by granting the attacker additional
network privileges.  We are chiefly concerned with three scenarios:

1) The attacker uses the WebSocket protocol to attack a server that
does not support the WebSocket protocol.  In this scenario, we are
concerned with protecting a wide variety of servers that implement a
wide variety of protocols.

    a) We do not assume the server implements any particular protocol
exactly according to its specification.  Instead, we aim for “real
world” security in which servers might have a number of common bugs.

    b) We do not assume the server uses a strong authentication
scheme.  In particular, we are concerned with protecting servers that
rely on connectivity alone for authentication (e.g., inside a
corporate intranet).  Although using strong authentication is a best
practice, strong authentication is far from universal in deployments.

2) The attacker uses other network facilities in the browser to attack
a WebSocket server.  For example, the attacker might use and HTML form
element to generate an HTTP message targeted at a WebSocket server.
In this scenario, do not assume the WebSocket server follows the
WebSocket protocol specification in every detail.  Instead, we seek to
protect WebSocket servers that contain some implementation errors.  Of
course, we cannot hope to protect servers with arbitrary
implementation errors (e.g., memory safety errors), but, when given a
choice, we prefer protocols whose security is robust to sloppy
implementation.  We are concern with two kinds of attacks in this
model:

    a) The attacker crafts an HTTP request that confuses the WebSocket
server into performing an undesirable mutation to its internal state.

    b) The attacker crafts an HTTP request that confuses the WebSocket
server into responding with content that the browser then interprets
to the detriment of the server (e.g., allows the attacker to mount a
cross-site scripting attack against the server’s origin).

3) The attacker communicates with a WebSocket server, but the ensuing
traffic confuses a network intermediary.  Without loss of generality,
we can assume that the WebSocket server colludes with the attacker to
aid him or her in confusing the intermediary.  In particular, we are
especially concerned with transparent HTTP proxies in corporate
intranets because these proxies are common and confusing such as proxy
could let the attacker extract confidential information from the
corporation.

== Strawmen ==

One natural approach is to design the handshake to mimic an HTTP POST
request.  Using a POST request as a template is attractive because an
attacker can already generate POST requests to many network locations
using the HTML form element.  If WebSockets are less generative than
the form element, then we can argue by reduction the WebSockets does
not increase the attack surface for cross-protocol attacks.  Here’s an
example WebSocket handshake templated on a POST request:

Client -> Server:
POST /path/of/attackers/choice HTTP/1.1
Host: host-of-attackers-choice.com
Sec-WebSocket-Key: <connection-key>

Server -> Client:
HTTP/1.1 200 OK
Sec-WebSocket-Accept: <connection-key>

The idea behind this protocol is that by echoing back the
connection-key, the server has agreed to establish a WebSocket
connection.  Unfortunately, this handshake has serious problems.  If
the attacker can host an htaccess file at any location a target HTTP
server, the attacker can opt the server into using WebSockets.  The
server will believe the first HTTP request is complete and is
expecting another HTTP request on the socket.  However, the attacker
can now send (roughly) arbitrary bytes on the socket, spoofing HTTP
requests and reading back the response.

To repair this vulnerability, we replace value of the
Sec-WebSocket-Accept response header with HMAC-SHA1(<connection-key>,
<uuid>), on the assumption that a simple configuration file will be
unable compute an HMAC.  However, this modification is insufficient.

Consider, for example, a virtual hosting environment in which the
attacker can place PHP scripts on the server.  For example, such
hosting environments are widely available commercially, such as from
1and1.com.  Now, the attacker can complete the WebSocket handshake
because the PHP script can compute the HMAC and send the appropriate
response header.  The attacker has now opted into the WebSocket
protocol on behalf of the rest of the entire socket.  Unfortunately,
the attacker is only empowered to speak on behalf his own virtual
host.  This privilege escalation is likely to be exploitable by
spoofing further HTTP requests in WebSocket message frames.  In these
spoofed messages, the attacker can spoof the Host header and interact
with other virtual hosts reachable on the same socket.

To attempt to repair this vulnerability, we remove the attacker’s
ability to designate a PHP script on the server:

Client -> Server:
OPTIONS * HTTP/1.1
Host: host-of-attackers-choice.com
Sec-WebSocket-Key: <connection-key>

Server -> Client:
HTTP/1.1 200 OK
Sec-WebSocket-Accept: HMAC(<connection-key>, “...”)

This handshake still has problems in more sophisticated virtual
hosting scenarios, but let’s put those aside for the moment to
consider how this handshake interacts with transparent HTTP proxies.
Recall that the browser will not use the proxy version of the
handshake because the proxy is transparent.

Unfortunately, this handshake is likely to confuse a transparent
proxy.  After seeing these messages exchanged, a transparent proxy
will likely believe that the next bytes emitted by the browser will be
another HTTP request.  However, the browser believes it has
established a WebSocket connection and will let the attacker send
WebSocket frames to the transparent proxy.  The attacker can likely
use these frames to spoof HTTP requests for intranet resources (again,
by spoofing the Host header) and read back the response, stealing
confidential information from the corporation’s intranet.

To attempt to repair this vulnerability, we add the Upgrade header to
inform the transparent proxy that the socket is switching protocols:

Client -> Server:
OPTIONS * HTTP/1.1
Host: host-of-attackers-choice.com
Connection: Upgrade
Sec-WebSocket-Key: <connection-key>
Upgrade: WebSocket

Server -> Client:
HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: WebSocket
Sec-WebSocket-Accept: HMAC(<connection-key>, “...”)

Unfortunately, the RFC 2817 HTTP upgrade mechanism is virtually unused
in practice.  If you search the web for references to upgrade, you
either find links to RFC 2817 or discussion of the WebSocket protocol.
 It seems entirely likely that some number of transparent proxies will
be oblivious to the HTTP upgrade mechanism.  Organizations could
easily deploy such proxies and never have any operational issues with
them.  For this reason, assuming that transparent proxies the HTTP
upgrade mechanism is a dangerous assumption.  If the proxy is
oblivious to HTTP upgrade, the proxy could easily treat this handshake
the same way it would treat the previous iteration, which allows the
attacker to steal confidential information from corporate intranets.

Rather than relying upon the rarely used HTTP upgrade mechanism to
inform network intermediaries that the remainder of the socket is not
HTTP, we propose using the RFC 2817 CONNECT mechanism.  This mechanism
is widely used on the Internet to tunnel TLS connections through
proxies.  Proxy implementations that lack support for the CONNECT
mechanism will likely discover and repair that oversight quickly.

== Proposal ==

In this section, we present our proposal for a WebSocket handshake and
tunnel.  The handshake established a shared “secret” between the
client and the server, which they use to encrypt subsequent traffic.
This handshake lacks a number of endpoint and extension negotiation
features of the current handshake.  We expect the working group to add
these features inside the encrypted tunnel.

=== Handshake Request ===

To establish a WebSocket connection, the browser sends an RFC 2817
CONNECT request:

Client -> Server:
CONNECT 1C1BCE63-1DF8-455C-8235-08C2646A4F21.invalid:443 HTTP/1.1
Host: 1C1BCE63-1DF8-455C-8235-08C2646A4F21.invalid:443
Sec-WebSocket-Key: <connection-key1>

where <connection-key1> is a 128-bit random number encoded in base64.
This initial message has several desirable properties:

1) The attacker cannot influence any of the bytes included in the
message.  Instead of using the attacker’s host name, we use an invalid
host name (per RFC 2606).  Although we could use any invalid host
name, we use this host name as a globally unique identifier for the
WebSocket protocol.

2) Any intermediaries that understand this message according to its
HTTP semantics with route the request to a non-existent domain and
fail the request.  In particular, they will not route the
Sec-WebSocket-Key to the attacker, making it difficult for the
attacker to perform actions based on the key.

3) Transparent proxies are likely to interpret this request as an
HTTPS connect request and assume the remainder of the socket is
unintelligible.  Because the remainder of the bytes on the socket are
encrypted (see below), the attacker is unlikely to be able to trick
the transparent proxy into taking further action.

4) This message cannot be generated by a web attacker in today’s browsers.

5) A server that wishes to multiplex HTTP and WebSockets on the same
port can use the request-line to distinguish the two protocols.

The client can also include additional information in the first
handshake message by encrypting that information in AES-128-CTR using
the key HMAC-SHA1(<connection-key1>,
“C1BA787A-0556-49F3-B6AE-32E5376F992B”) and a counter block that is
the byte number represented in 128-bit network byte order
(big-endian).  We expect browsers to use this additional information
to include additional meta-data about the connection (e.g., the origin
of the web site that created the WebSocket) rather than
application-layer messages.

Encrypting the additional information makes it difficult for the
attacker to predict the bytes that appear on the wire.  Without the
ability to predict on-the-wire bytes, the attacker will have
difficulty crafting a network message that confuses a non-WebSocket
server or an intermediary.  Effectively, the attacker is limited to
sending random traffic to a chosen server.  To limit opportunities for
abuse, the browser should limit the amount of unsolicited data the
attacker can send (500 bytes?) before the server accepts the WebSocket
connection to avoid spamming unwitting servers with too much traffic.

=== Handshake Response ===

To accept the request, the server replies with the following message:

Server -> Client:
HTTP/1.1 200 OK
Sec-WebSocket-Accept: <hmac>
Sec-WebSocket-Key: <connection-key2>

where <hmac> is HMAC-SHA1(<connection-key1>,
“258EAFA5-E914-47DA-95CA-C5AB0DC85B11”) encoded in base64 and
<connection-key2> is a 128-bit random number encoded in base64.  If
<connection-key2> is identical to <connection-key1>, the client aborts
the handshake.  This message completes the CONNECT mechanism.

The entity that generated the HMAC has demonstrated understanding of
the WebSocket protocol by including the UUID in the HMAC.  Because the
original network message did not designate any particular host, we can
have reasonable assurance that the entity that generated the HMAC
speaks on behalf of the entire socket (and not just on behalf of one
virtual host).  Because the HMAC occurs near the beginning of the
socket (and is proceeded by a fixed string), we mitigate the risk that
the replying entity is actually speaking a non-HTTP, non-WebSocket
protocol.

After sending the handshake response, the server can begin sending
information over the encrypted tunnel described in the following
section.  We expect that the first message sent by the server will
contain meta-data about the connection and that subsequent messages
will contain application-layer messages.

=== Tunnel ===

The handshake establishes two keys, which the client and server use to
form an encrypted tunnel for further communication:

Client -> Server Key:
HMAC-SHA1(<connection-key1> || <connection-key2>,
                       “363A6078-74D2-4C0B-8CBC-1E6A36E83442”)

Server -> Client Key:
HMAC-SHA1(<connection-key1> || <connection-key2>,
                       “2306C3BE-0ACF-42C0-B69E-DFFE02CFA346”)

All subsequent bytes are encrypted using AES-128-CTR with the
appropriate directional key and a counter block that is the byte
number represented in 128-bit network byte order (big-endian).

Encrypting the tunnel makes it difficult for an attacker to use the
browser’s HTTP network facilities to attack a poorly implemented
WebSocket server.  Because the attacker is unable to learn the
<connection-key2> chosen by the server, the attacker will have
difficulty crafting an HTTP request that the WebSocket server will
decrypt to something sensible.

Encrypting the traffic from the server to the client makes it
difficult for the attacker to generate an HTTP request to an honest by
poorly implemented WebSocket server that causes its response to be
interpreted to its detriment by the browser.  In particular, it is
unlikely that the server’s response will be treated as an HTML
document by the browser, preventing the attacker from leveraging the
WebSocket server to mount a cross-site scripting attack against the
server’s origin.

== Analysis ==

We analyze the risks of this protocol in the three scenarios of interest:

1) The attacker uses the WebSocket protocol to attack a server that
does not support the WebSocket protocol.  There are two cases to
consider: the server is familiar with HTTP semantics or the server is
oblivious of HTTP:

    a) The attacker will find it difficult to attacker a server that
is familiar with HTTP semantics with this handshake because the HTTP
semantics of the handshake point to routing the request to a
non-existent network location.  If the request somehow routes to the
attacker, the HTTP semantics then point to transporting opaque data
over the socket.

    b) The attacker will find it difficult to attack an HTTP-oblivious
server with this handshake because the attacker can send only a fixed
message followed by seemingly random bytes.  None of the bytes sent to
the server can be controlled directly by the attacker.  It seems
unlikely that the attacker will be able to advance the non-WebSocket
server very far down its state machine.

2) The attacker uses other network facilities in the browser to attack
a WebSocket server.  There are two cases to consider: the server
implements the WebSocket protocol correctly or the server implements
an imperfect version of the WebSocket protocol:

    a) If the server correctly implements the WebSocket protocol, the
attacker will be unable to use the other network facilities of the
browser to complete the handshake with the server because the attacker
is unable to generate the first network message.

    b) If the server implements an imperfect version of the WebSocket
protocol, the attacker will be unable to learn the value of either of
the directional keys for the tunnel.  Without knowledge of these keys,
the attacker will find it difficult (i) to craft a message that
decrypts to something meaningful to the WebSocket server and (ii) to
trick the WebSocket server into responding with something meaningful
to the browser.

3) The attacker communicates with a WebSocket server, but the ensuing
traffic confuses a network intermediary.  If the intermediary attempts
to route the request (e.g., because the intermediary is an HTTP
proxy), the handshake will fail because the request does not contain
any routing information for the target server.  If the handshake
completes and the intermediary understands HTTP semantics (as widely
used), the intermediary will likely reason that the remainder of the
socket is an opaque TLS connection.  In either case, the intermediary
is unlikely to take undesirable actions as a result of the WebSocket
connection.

== Conclusion ==

We believe this handshake is superior to the current handshake because
this handshake has a stronger argument for security.  Because the
attacker cannot control any of the bytes sent by the browser, the
attacker will have difficulty mounting a cross-protocol attack using
this handshake.

That said, there is no guarantee that this handshake resists
cross-protocol attacks.  These security properties are not very well
studied, making designing protocols that achieve these properties more
art than science.  However, the handshake we propose has a number of
heuristic properties that suggest it might stand up to further
scrutiny.

---

From: Willy Tarreau <[email-masked]>
Date: Wed, 6 Oct 2010 07:34:00 +0200

Hello Adam,

First, thanks for your work on this handshake. I found several interesting
points and a few concerning ones in your proposal.

Comments :
1) subsequent HTTP requests.

> requests and reading back the response.

That's exactly why I've been advocating for several months to add
"Connection: close" in requests and responses. It's simple, efficient,
well defined by the HTTP protocol to achieve exactly what we want, which
is :
  - for the client to tell the next point (intermediaries or server)
    that it is the last request and that it expects the server to do
    so in response ;

  - for the server to tell the previous intermediary or client that
    this is the last response over this connection and that it will
    not process any other one.

Additionally, I suggested that we add "Content-length: 0" in the
response so that intermediaries that don't understand the upgrade
won't blindly dump all the bytes on the connection until the close.

These points are really important, because without the connection: close,
we're actively telling the other side that we expect to reuse the connection
for sending other requests. Thus we must not be surprized by the nasty side
effects of our wrong use of the protocol !

(...)
> To attempt to repair this vulnerability, we remove the attacker?s
> Sec-WebSocket-Accept: HMAC(<connection-key>, ?...?)
> 
> hosting scenarios, but let?s put those aside for the moment to
> another HTTP request.

Same here, this would not be the case with "connection: close".
However, the "OPTIONS *" request may fail on a number of intermediaries,
some of which will take it for them and reply with their own options
instead of forwarding it. Well, at least the response will not contain
the WS headers so that might be a clean failure we may want to exploit
in the end.

> be oblivious to the HTTP upgrade mechanism.

The two types of incorrect handling of the Upgrade mechanism I've already
seen (and naively implemented myself) :

  - 101 is considered as any valid response (such as 200). Data flow
    back until the connection closes. Most of the time nothing flows
    from the client to the server, but that may work depending on the
    implementation. Advertising "connection: close" and "content-length: 0"
    in the response will definitely help making them fail cleanly if we
    don't want to rely on them.

  - 101 is considered as any 1xx response and is handled by default as
    a "100 Continue", which means the response is skipped and the
    intermediary waits for another response from the server. The "next"
    response does not exist here, it's just raw data. Some will consider
    those data as an invalid response (does not look like HTTP), others
    may consider those data as an HTTP/0.9 response and forward them to
    the client until the close.

2) use of CONNECT

> mechanism will likely discover and repair that oversight quickly.

That's interesting that you suggest using CONNECT. When I did so in
january or february, I got some negative responses concerning the fear
that some servers also contain proxy parts and that for this reason the
CONNECT method could be dangerous. I don't completely agree with that
because in my opinion, it's no different than sending a proxy-like
request to those servers. And the CONNECT has all the semantics we're
looking for, since it establishes a tunnel the intermediaries should
not look into.

> message.  Instead of using the attacker?s host name, we use an invalid

I have a problem with the invalid host name here. It breaks the ability
to support virtual hosting, which really is critical to web hosting
companies. If we used the correct target host's name, 4 possible things
could happen :

  - a transparent intermediary simply forwards it to the original destination
    IP without interpreting it. That's what we expect from a client point of
    view, so the intermediary does not cause any issue.

  - a transparent intermediary interprets it and forwards it to the
    requested host : great, that's precisely what we're looking for, so
    the intermediary does not cause any issue either.

  - the target receives it and handles it correctly. It finds its host
    name and knows what internal component to forward it to. That's
    what we're looking for.

  - the target mis-interprets it as a proxy request and forwards it to
    itself in loops. After a few hundreds to thousands iterations, the
    target is deadlocked and the issue is spotted by the admin. Anyway,
    such broken targets on the net (if they exist) are already vulnerable
    so we can't rely on a new protocol to protect them.

> attacker to perform actions based on the key.

If we had the proper URL in the request, it would not be routed to the
attacker either.

> 4) This message cannot be generated by a web attacker in today?s browsers.

I wholeheartly agree with that. That's also why I preferred the CONNECT
or OPTIONS request vs the GET.

> ?C1BA787A-0556-49F3-B6AE-32E5376F992B?) and a counter block that is

This possibly reduces the number of round trips during the handshake,
which is good.

> server or an intermediary.

What I like with a payload-only encryption vs a connection encryption
is that it still maintains the ability to install dedicated filtering
components in schools. Such components will technically work as transparent
proxies and will just be MITM. They will have two encrypted channels,
one with the browser and one with the server and they'll be able to
see the exchanged data in clear text and be able to filter based on
that.

Adam, could you please recheck the importance for this handshake to
have the invalid hostname ? It really is the only blocking issue I
can think of. If it is absolutely needed, maybe we could use something
like "<valid-hostname>.websocket.invalid" instead so that at least the
server-side components can route the request to the proper location ?

Thanks,
Willy

---

From: Eric Rescorla <[email-masked]>
Date: Tue, 5 Oct 2010 23:40:19 -0700

On Tue, Oct 5, 2010 at 10:34 PM, Willy Tarreau <[email-masked]> wrote
> see the exchanged data in clear text and be able to filter based on

I don't believe there is an issue here. This isn't a DH exchange--the keys
are in the
clear. A filtering appliance can passively decrypt the traffic.

-Ekr

---

From: Willy Tarreau <[email-masked]>
Date: Wed, 6 Oct 2010 08:56:24 +0200

> clear. A filtering appliance can passively decrypt the traffic.

indeed that's what I was saying, and that's what I like in this handshake
WRT a TLS handshake.

Regards,
Willy

---

From: Adam Barth <[email-masked]>
Date: Tue, 5 Oct 2010 23:57:40 -0700

> server-side components can route the request to the proper location ?

Using an invalid host name is important because we don't want the
attacker to be able to choose any of the bytes in the initial message.
 Of course, virtual hosting is important.  We'll probably want to
include the real Host header in the encrypted "additional information"
sent with the initial handshake message so that the WebSocket server
can dispatch the connection to the appropriate virtual host.

Adam

---

From: Willy Tarreau <[email-masked]>
Date: Wed, 6 Oct 2010 10:20:37 +0200

> attacker to be able to choose any of the bytes in the initial message.

OK I understand your point, but this is no different from what the
attacker can already do with plain HTTP.

> can dispatch the connection to the appropriate virtual host.

Except that right now the virtual hosting it handled at the boundary
and the websocket will be handled at the internals. That said, the
host part of a URL must at least respect the limited charset of the
DNS system. We don't have the %-encoding of the plain URLs.

Regards,
Willy

---

From: Adam Barth <[email-masked]>
Date: Wed, 6 Oct 2010 07:21:46 -0700

On Wed, Oct 6, 2010 at 4:49 AM, Micheil Smith <[email-masked]> wrote:
> Question One:
> In the section of the handshake for the client -> server:
>
> Is the string of "1C1BCE63-1DF8-455C-8235-08C2646A4F21.invalid:443" be intended
> to be changed with each request, or is it always going to be the same string?

It's always the same string.  The thing that varies is the
<connection-key1> part.

> Question Two:
> A common pattern that I have seen used in websocket communicate is to use the
> resource requested as a way of routing connections, such that a request to:
>
>        GET /abc HTTP/1.1
>        Connection: Upgrade
>        Upgrade: WebSocket
>
> is different to:
>
>        GET /def HTTP/1.1
>        Connection: Upgrade
>        Upgrade: WebSocket
>
> How would this handshake proposal do similar, considering you aren't requesting a
> resource on a server any more. Would this perhaps be done by a header extension
> or something similar instead?

We'll put the WebSocket URL in the additional information that comes
with the initial message.  We can either break that up into a request
line and a Host header, or we can just include the whole URL as such.
The point of putting in the additional information is so that it can
be encrypted, preventing the attacker from choosing any of the bytes
on the wire.

Adam

---

From: Adam Barth <[email-masked]>
Date: Wed, 6 Oct 2010 07:24:18 -0700

> attacker can already do with plain HTTP.

Please read the document.  If that were true, we could just use the
initial POST strawman.

> DNS system. We don't have the %-encoding of the plain URLs.

Please read the document.  That's true and intentional.  We want the
server to understand that it's talking WebSockets before it dispatches
the request to a particular virtual host.  That prevents a single
virtual host from opting into a WebSocket connection on behalf of the
entire host.  If the real host doesn't understand what's going on, it
could get confused and let the attacker do nasty things.

Adam

---

From: Willy Tarreau <[email-masked]>
Date: Wed, 6 Oct 2010 16:37:17 +0200

> Please read the document.  If that were true, we could just use the

Adam, please, I took 30 minutes this morning to read it carefully. All
I saw against the POST was the risk of using it to post a second request
after the first one, and I explained that that's precisely why the
"Connection: close" statement must be used.

> could get confused and let the attacker do nasty things.

I don't agree, at worst it would forward the request as-is, exactly
as any intermediary will do, and it will either reach a real WS server
or a normal HTTP server. And since your proposal protects against
cross-protocol attacks, the attacker won't be able to do nasty things.

Willy

---

From: Greg Wilkins <[email-masked]>
Date: Thu, 7 Oct 2010 13:33:25 +1100

On 6 October 2010 09:15, Adam Barth <[email-masked]> wrote:

> == Strawmen ==
> If  the attacker can host an htaccess file at any location a target HTTP server,

This is indeed a strawman.

If the attacker can host an htaccess file in any location, then the
attacker already owns the server!

> Consider, for example, a virtual hosting environment in which the attacker can place PHP scripts on the server.

Then again, the attacker already owns the server. They can write a
script to echo back any cookie or content from any script or XHR, so
the clients cookies are already been exposed.  This has nothing to do
with websockets.

> message.

If the attacker cannot influence any of the bytes in the handshake,
then an extra round trip will be needed to communicate the WebSocket
URL and subprotocol. Ideally these need to be known before a server
proceeds with accepting a websocket connection.

Thus I think it is unrealistic to propose a content free handshake.

Unfortunately, once you allow content (which I think we must), then a
CONNECT handshake is just as vulnerable to cross protocol attacks to
DNS servers as HTTP is.  If those servers are going to interpret the
method as a frame header and then scan forward to the arbitrary
content provided by the attacker, then they will be equally vulnerable
to POST, GET or CONNECT (with perhaps some variance due to the happen
stance of the actual ascii values of those names).   But luckily, you
have already demonstrated that DNS like servers are not vulnerable to
HTTP with GET and POST, so they are thus not vulnerable to CONNECT.
But this proposal still does not represent any real change of
substance.

> attacker to perform actions based on the key.

So that would mean that an intermediary that correctly implements both
CONNECT and
upgrade headers would not be able to work with websockets using this
handshake, while it could with the currently proposed handshake.

I don't think we should have a handshake that punishes correctly
implemented intermediaries.

> 4) This message cannot be generated by a web attacker in today’s browsers.

I expect this is true, although I would like to review the various
auto proxy configuration mechanisms that are available, as they may
allow a compromised CONNECT request.

> attacker will have difficulty mounting a cross-protocol attack using

The strawman analysis of the threat to the upgrade handshake is indeed
a strawman and thus can't be used to justify any claims of
superiority.

Also the main security aspect of this handshake is that it does not
allow attacker supplied content.  This provides a secure but
non-functional handshake.

---

From: Greg Wilkins <[email-masked]>
Date: Thu, 7 Oct 2010 13:42:35 +1100

> line and a Host header, or we can just include the whole URL as such.

I think you make the server more vulnerable to DOS attacks by delaying
consideration of the URL and subprotocol.

Frequently servers will run many applications on many virtual hosts,
real hosts and context paths.  Only a subset of these may support
websockets.  This proposal would mean that the server would need to
accept the connection and thus cause the client onOpen even to first,
before it had validated the connection was to an application that can
handle websocket.  While I don't see any new vulnerability flowing
directly from this, I believe that it is not a desirable state of
affairs from either a security or resource allocation point of view.

> be encrypted, preventing the attacker from choosing any of the bytes

If we really are going to have a content free handshake that exchanges
keys so that the rest of the connection can be encrypted - then we
should just use TLS.

I see little value and significant risks in inventing some TLS-lite handshake.

I think that we should improve the upgrade proposal to the best we
can, and consider a concrete TLS proposal, and then we can consider if
we support one or  the other or both.

regards

---

From: Willy Tarreau <[email-masked]>
Date: Thu, 7 Oct 2010 07:19:55 +0200

> I see little value and significant risks in inventing some TLS-lite handshake.

In my opinion, both are unusable for most sites due to their
incompatibility with deployed virtual hosting architectures.
If we had to go that route, I don't expect a massive migration
from existing technos to WS. That said, in such a case, there
still is a small advantage of this handshake vs a TLS-based one,
it's that it's possible to plug an intermediary that deciphers
and reciphers for content analysis. We could say that differently,
the TLS handshake does not even permit that which is even worse
for most uses.

> we support one or  the other or both.

In my opinion, we should be able to come up with an update of this
proposal that supports virtual hosting and maybe some path somewhere.
But I don't think we need to choose between TLS and HTTP, really both
have their uses and the intersection between both is not that large.

Regards,
Willy

---

From: Adam Barth <[email-masked]>
Date: Wed, 6 Oct 2010 22:23:04 -0700

> This is indeed a strawman.

Hence the title.  :)

> the clients cookies are already been exposed.  This has nothing to do

That's not correct.  As cited in the paper, there are many folks who
will virtually host my PHP scripts with other customers.  The security
architecture of the web makes that safe.  Resources are allocated by
origin.  The virtual hosts have different origins.

> proceeds with accepting a websocket connection.

That's factually inaccurate.  The URL and subprotocol information is
included in the initial encrypted.

> Thus I think it is unrealistic to propose a content free handshake.

Fortunately, that's not what we proposed.

> DNS servers as HTTP is.

That is factually inaccurate.  Please see the protocol described above
as a counter-example.

> If those servers are going to interpret the
> stance of the actual ascii values of those names).

That is factually inaccurate.  Please see the protocol described above
as a counter-example.

> But luckily, you

That is factually inaccurate.  I made no such demonstration.

> handshake, while it could with the currently proposed handshake.

No.

> implemented intermediaries.

Fortunately, this handshake does not punish correctly implemented
intermediaries.

> allow a compromised CONNECT request.

The attacker in our threat model is not allowed to provide a proxy
autoconfig file.

> a strawman and thus can't be used to justify any claims of

I disagree.

> non-functional handshake.

That is factually inaccurate because you do not understand the
handshake as described.  Please read the paragraph about the encrypted
additional information included in the initial message.

> consideration of the URL and subprotocol.

That is factually inaccurate.  I did not delay the consideration of
the URL or the subprotocol.

> affairs from either a security or resource allocation point of view.

That is factually inaccurate, for the reasons described above.

> keys so that the rest of the connection can be encrypted - then we

I agree that we should use TLS, but the premise of your statement is
misinformed.  The handshake is not content free.

> we support one or  the other or both.

The handshake in this document is an improvement on the upgrade
handshake.  Given that you didn't understand how this handshake works,
I'd encourage you to reconsider your position.

Adam

---

From: Greg Wilkins <[email-masked]>
Date: Thu, 7 Oct 2010 17:42:10 +1100

>> This is indeed a strawman.

You do know what a strawman is right?

   http://en.wikipedia.org/wiki/Straw_man

Strawmen have no place in a reasoned discussion.

> origin.

Exactly - the security architecture of the web makes that safe.
No cookies or credentials for goodguy.somehost.com/secret/ are going
to be sent to
evilgenius.somehost.com/attack.

Also hosting PHP is not sufficient to be able to accept a websocket handshake.
It must be able to send a 101 response and then generate a valid ping
message (or the
correct random bytes in the -02 draft).

You are only revealing vulnerabilities in a strawman server that
you've hypothesised to be vulnerable.

> included in the initial encrypted.

I'm sorry - I was confused by your statement that "The attacker cannot
influence
any of the bytes included in the message".   Your proposal read like
this information was
sent in a subsequent request.

So an attacker can influence the bytes in the handshake.

> [...]

Care to explain?

You say that an intermediary that understands CONNECT will route to a
non-existent domain.
How will such an intermediary be able to work with websocket?

> The attacker in our threat model is not allowed to provide a proxy

again - probably true... but I'd like to see the detailed anaysis as
to why that is so.

> Given that you didn't understand how this handshake works,

I did misunderstand your statement that the attacker cannot influence
any of the bytes included in the handshake, but have now reread the
proposal and think that I've got the nuts of it.

There are basically two elements to it, that I actually should be
considered separately and as incremental proposal to the current
draft.

1) Encrypt the user/attacker supplied data.    There may be some merit
in this, but it can be equally applied to the upgrade approach as it
can to a CONNECT approach.   But you analysis of the threat is based
on a strawman and I do not believe that you have substantiated any
significant vulnerability where a URL or field value of a HTTP request
may be interpreted as content in another protocol - that is not
already vulnerable to HTTP clients.  Without an real threat, I do not
believe that encryption is worth while.

2) Use of CONNECT rather than upgrade.  Again, there is some merit in
considering this, but I believe it has been discussed before and
eventually rejected.  There is the issue that an intermediary that
correctly implements CONNECT will not pass such a hand shake.  If that
concern can be addressed, and if we can do some real world testing of
how CONNECT performs, then maybe it is a candidate.

regards

---

From: Willy Tarreau <[email-masked]>
Date: Thu, 7 Oct 2010 09:05:04 +0200

On Thu, Oct 07, 2010 at 05:42:10PM +1100, Greg Wilkins wrote:
> to be sent to evilgenius.somehost.com/attack.

That's a good point that you're talking about cookies, Greg, because
that's precisely one element which we will definitely need, and which
will imply that some parts of the handshake will be variable. Also, I
don't see why we should make the handshake stricter than whatever an
attacker already has control over in a browser. We just need the
handshake to be as robust as any HTTP handshake, not more. If an
attacker has control over the browser and the WS handshake does not
permit anything, he will still be able to use plain HTTP and have much
more control. So we can relax the rules a bit without turning browsers
into massive attack sources.

Regards,
Willy

---

From: Adam Barth <[email-masked]>
Date: Thu, 7 Oct 2010 09:48:44 -0700

> sent in a subsequent request.

Perhaps a better wording would have been "The attacker cannot choose
any of the bytes sent on the wire."  I've updated the document.

> So an attacker can influence the bytes in the handshake.

Yes, but the attacker cannot choose any of the bytes sent on the wire,
which is one of the essential security properties of the handshake.
That makes it quite difficult for the attacker to confuse
non-WebSocket servers (which won't decrypt the additional information
because they lack the UUID).

> How will such an intermediary be able to work with websocket?

Such an intermediary is not correctly implemented.

> again - probably true... but I'd like to see the detailed anaysis as

This is standard stuff in web security.  An attacker who controls your
proxy autoconfig is equivalent to an active network attacker.

> how CONNECT performs, then maybe it is a candidate.

Yes.  Both those aspects are important to the security of the
handshake.  I don't believe the handshake is secure without them.

Adam

---

From: S Moonesamy <[email-masked]>
Date: Thu, 07 Oct 2010 13:43:26 -0700

>Strawmen have no place in a reasoned discussion.

 From RFC 1588:

   'RFC 1107 offered a "strawman" proposal for an Internet Directory
    Service.  The next step after strawman is sometimes called "clayman",
    and here a clayman proposal is presented.'

There are Internet-Drafts that start as a strawman proposal to get 
the discussion going.

Regards,
S. Moonesamy

---

From: Maciej Stachowiak <[email-masked]>
Date: Fri, 08 Oct 2010 14:10:13 -0700

The following comments are not informed by the follow-ups to this thread (I haven't had a chance to read them yet) but I wanted to give my comments ASAP.

Here's some issues (mostly non-security, but still important IMO):

1) There doesn't seem to be a provision for passing a resource path from the client to the server, since the CONNECT method does not include a path. This is a problem because:

   a) It precludes having multiple independent WebSocket services on the same host and port. That seems like a problem, since most ports are effectively unavailable on the public internet.
   b) The WebSocket client API and the ws: URI scheme are based on the premise of identifying a specific WebSocket resource on a server.

This could be addressed by exchanging further messages after the handshake to identify the resource, or using the provision for metadata, but:

   i. This potentially adds round trips.
   ii. It would make life harder for meta-servers that serve both HTTP and multiple WebSocket services and dispatch internally - they would have to actually understand WebSocket protocol enough to read message frames before they could do the dispatch.

2) Is there a way for this handshake to pass through non-transparent intermediaries (i.e. an explicitly set proxy server)? At least as specified, it seems like it would always fail, which is unfortunate if the non-transparent intermediary could work.

3) Is there a way for this handshake to pass through transparent intermediaries that are aware of the WebSocket protocol? Doesn't seem like it. It would be unfortunate to cause a hard failure in all such cases.

4) Nothing in the handshake identifies the target host. This seems like a problem because:

   a) It makes it effectively impossible to offer a WebSocket service on a shared virtual host. I gather that virtual hosting scenarios were one of the attack vectors considered, but failing to address this use case doesn't seem like a good solution.
   b) It exacerbates the risk of DNS rebinding attacks. I don't know offhand if a DNS rebinding attack against WebSocket would do anything bad, but sending and checking an explicit host identifier would be a total defense, so it seems unfortunate that this is missing.

(Maybe it is intended that the host is identified e.g. via a header specifying the target Origin, but this is not spelled out).

I like the general approach (based on CONNECT and encrypting the data stream), it seems more robust than depending on the details of error handling code.

Regards,
Maciej

---

From: Adam Barth <[email-masked]>
Date: Fri, 8 Oct 2010 14:28:59 -0700

>   ii. It would make life harder for meta-servers that serve both HTTP and multiple WebSocket services and dispatch internally - they would have to actually understand WebSocket protocol enough to r…

I'm sorry the document isn't as clear on this topic as it should have
been.  We can send resource path / host name is sent to the server in
the first message.  We just need to include it in the encrypted
additional information.  This does not add round trips.  A hybrid
HTTP/WebSocket server does not need to read any message frames to
dispatch WebSocket connections to the correct virtual host / path.

> 2) Is there a way for this handshake to pass through non-transparent intermediaries (i.e. an explicitly set proxy server)? At least as specified, it seems like it would always fail, which is unfort…

Yes.  We can use a CONNECT request, just as in the current draft.
This is not described in the protocol, but it works exactly the same
as in step 3 of Section 5.1 of the current draft (including proxy
authorization).

> 3) Is there a way for this handshake to pass through transparent intermediaries that are aware of the WebSocket protocol? Doesn't seem like it. It would be unfortunate to cause a hard failure in al…

Yes.  These intermediaries should forward the bytes to the IP address
to which the client opened the socket.  They already need to do this
kind of thing today to handle TLS without SNI.

> (Maybe it is intended that the host is identified e.g. via a header specifying the target Origin, but this is not spelled out).

The target host is identified in the additional information, where it
can be used by WebSocket-aware folks, but it can't confuse
non-WebSocket aware folks.

> I like the general approach (based on CONNECT and encrypting the data stream), it seems more robust than depending on the details of error handling code.

Thanks.  I think we can use the encrypted additional information sent
with the initial handshake to address the concerns you express above.

Adam

---

From: Maciej Stachowiak <[email-masked]>
Date: Fri, 08 Oct 2010 14:41:39 -0700

> with the initial handshake to address the concerns you express above.

It would be good to spell out the details of what additional information is sent and how. Then we could evaluate how much of a burden it would be for multiplexing servers to dispatch between HTTP and WebSocket, to dispatch to the right virtual host for WebSocket connections, and to dispatch among the "servlets" (or equivalent) that implement individual WebSocket resources.

It seems like they would have to handle this differently than how it's currently done for HTTP, it would be useful to understand how different.

Regards,
Maciej

---

From: Adam Barth <[email-masked]>
Date: Fri, 8 Oct 2010 14:50:09 -0700

On Fri, Oct 8, 2010 at 2:41 PM, Maciej Stachowiak <[email-masked]> wrote:
> > > I like the general approach (based on CONNECT and encrypting the data
> > > stream), it seems more robust than depending on the details of error
> > > handling code.
> >
> It would be good to spell out the details of what additional information is
> sent and how. Then we could evaluate how much of a burden it would be for
> multiplexing servers to dispatch between HTTP and WebSocket, to dispatch to
> the right virtual host for WebSocket connections, and to dispatch among the
> "servlets" (or equivalent) that implement individual WebSocket resources.
> It seems like they would have to handle this differently than how it's
> currently done for HTTP, it would be useful to understand how different.

Ok.  We have a lot of flexibility in this regard.  If you like the
format of the current handshake, you could include the following in
the additional information (encrypted as described in the document):

        GET /demo HTTP/1.1
        Host: example.com
        Sec-WebSocket-Protocol: sample
        Origin: http://example.com

You can also include cookies or whatever else you like.  There are
only two constraints:

1) You don't want to include too many bytes to avoid spamming servers
with too much traffic before they've agreed to the connection.

2) You probably don't want to send message frames until the server
accepts the connection.  The reason for this is to let simple servers
just spam back the one-and-only origin they want to accept connections
from.  If we hold off on message frames until the handshake finishes,
the browser stops the attacker from sending them messages.  Otherwise,
they have to actively ignore messages from origins they don't like.

Adam

---

From: Maciej Stachowiak <[email-masked]>
Date: Fri, 08 Oct 2010 15:07:23 -0700

> they have to actively ignore messages from origins they don't like.

Sounds reasonable. What's interesting about this kind of approach is that it would let servers feed back the second set of headers into their usual host/resource dispatch code. This may make modifications for WebSocket-awareness somewhat simpler.

REgards,
Maciej

---

From: Adam Barth <[email-masked]>
Date: Fri, 8 Oct 2010 15:18:00 -0700

> Sounds reasonable. What's interesting about this kind of approach is that it would let servers feed back the second set of headers into their usual host/resource dispatch code. This may make modifi…

Yes.  We also get around the rigidity/HTTP-compliance trade-off
between security and code reuse.

Adam