Subject: Re: [hybi] WebSocket handshake (HTTP and SSO)

From: Greg Wilkins <[email-masked]>
Date: Wed, 1 Sep 2010 19:28:38 +1000

2010/9/1 Ian Fette (イアンフェッティ) <[email-masked]>:
> On Tue, Aug 31, 2010 at 6:39 PM, Scott Ferguson <[email-masked]> wrote:
>> Or at least, I think that's what the protocol is trying to do. To me, it
>> looks like a security -through-confusion protocol hacked together by someone
>> with little security experience, who believes that a complicated, confusing
>> protocol is more secure than a straightforward one. If no one can understand
>> it, no one can attack it, I guess. That's just what it looks like to me.
>
> While I can appreciate that you may not care for the complexity of the
> handshake, I would ask that you please not attack the experience of the
> people involved in its design. Critiques of the protocol are certainly
> welcome, but I don't think personal attacks are appropriate.

Ian,

I think I can rephrase Scott's concerns as a non personal attack.

The current handshake contains a number of unusual security features
that I do not think have had the rigorous analysis that such security
algorithms deserve.

The algorithm encodes 2 random integers as decimal digits randomly
interspersed with other characters and spaces.  The algorithm requires
the characters to be ignored, the spaces to be counted and the number
to be divided by the number of spaces.

Dividing a random number by another random number generated from the
same random number generator can have unexpected numeric effects. I
have previously experienced a problem with a random session ID where
an attempt to "improve" a 32 bit random number by mixing in some salt
and applying another random number from the same generator actually
significantly reduced the search space.  An exploit was developed that
give 3 session ID, a bit of brute force calculation and you could
predict the next session with 1 in 48 accuracy. I fear that this
algorithm, combined with a poor random number generator, may similarly
be vulnerable, specially as the random characters and spaces will
reveal more information about the internal state of the generator.

The space counting is to protect against injection, but is not
required if the nonce is generated after the path is passed to the
websocket client. I simply don't understand the justification given in
the specification for the random characters interspersed with the
numbers.

My counter proposal is that the nonce is sent simply as hex number in
the header.  Since these numbers are generated after the path is
passed to the websocket client, they cannot be predicted and thus
cannot be injected.

Are there any problems with this simpler approach?

regards

---

From: Scott Ferguson <[email-masked]>
Date: Wed, 01 Sep 2010 09:19:16 -0700

Adam Barth wrote:
>> a) To validate the server as websocket server (as opposed to a SMTP server),
>> the client creates a securely-generated random nonce, c_nonce and sends it
>> in C1. The server sends back a hash in S2, like H(c_nonce, "WebSocket").
>> Since no server other than a websocket server will generate that hash,
>> you've verified that the server is a websocket server.
>>     
>
> This assumption is not correct.  Consider, for example, a protocol
> like DNS or an HTTP proxy where the attacker is given some control
> over the server's response.  We have no guarantee that S2 was actually
> generated by the server and not by some other entity and just relayed
> by the server.
>   

Yes, and that's a very important point.

If the hijacker has access to c_nonce or can predict it (like a 
non-securely random c_nonce), then the hijacker can generate the hash 
and trick a non-websocket server into returning it. The browser must 
absolutely keep the c_nonce secret from the hijacker and prevent the 
hijacker from computing H(c_nonce, "WebSocket") for the hash validation 
of the server to work.

But if the hijacker can't generate H(c_nonce, "WebSocket") himself, 
though, he can't trick some non-websocket server into computing that 
hash. Tricking a server into echoing or simple manipulation, sure, but 
not forcing a computation of a hash foreign to the server's protocol.

(The same issue applies to the current protocol, even though the hash 
function is different.)

-- Scott
> Adam

---

From: Ian Fette (イアンフェッティ) <[email-masked]>
Date: Wed, 1 Sep 2010 09:36:18 -0700

> Are there any problems with this simpler approach?
Greg, thanks for the rephrasing. I wasn't as involved with the handshake
design, so apologies in advance if I misstate something. However, I'd like
to share what I believe was the intent of the scheme, in the hopes it may
clear up some of the confusion.

First, I'm not sure how important it is that the numbers are _strongly_
random, so long as they come from a sufficiently large pool of options (e.g.
from 0 to INT_MAX). The point of the handshake is not to establish e.g. key
material that will be used for securing the connection. Rather, the point of
the handshake is to ensure that each end is actually a WebSocket
server/client. Using the same number all the time could mean that the server
could always give back the same response, which would not be desirable as
that would imply that the server might not actually be parsing the entire
handshake, but rather just echoing things back. Using a different number
each time ensures that the server is actually parsing the handshake and not
just returning a predefined value. How strong the RNG is doesn't seem to be
critical for this, unless I've missed something.

As for the spaces, it's to protect against injection as you say. The goal is
to prevent it from being smuggled in the PATH in such a way that that e.g. a
HTTP request could be misinterpreted as a WS handshake request. As spaces
must be encoded in the path (%20) this is designed to prevent against that,
ditto with CRLF.

I think the worry is that a hex number in the header could be potentially
confused, and not offer the same protections.

I think some of the confusion is that this handshake isn't really designed
to provide a secure channel (e.g. choose keys that will be used to encrypt
further data), rather the handshake is to protect against cross-protocol
attacks, and so there are slightly different criteria.

While I might agree that it could perhaps be simpler and still work, there
is also an argument for defense in depth, and frankly it is not difficult to
implement (we and others have already done it), so I'm inclined not to want
to revisit it just for the sake of "I would prefer something simpler" -
would really rather move forward. There are some open issues on the
handshake that I would love to discuss, e.g. #4 - making sure that we fail
on intermediaries that won't forward data properly but at the same time not
hang on intermediaries - but redoing the whole thing based on preference
without any real demonstrated problems (and having people already
implemented it makes me confident it's possible to implement) isn't really
that enticing.

---

From: Adam Barth <[email-masked]>
Date: Wed, 1 Sep 2010 10:16:15 -0700

On Wed, Sep 1, 2010 at 9:19 AM, Scott Ferguson <[email-masked]> wrote:
> If the hijacker has access to c_nonce or can predict it (like a non-securely
> random c_nonce), then the hijacker can generate the hash and trick a
> non-websocket server into returning it. The browser must absolutely keep the
> c_nonce secret from the hijacker and prevent the hijacker from computing
> H(c_nonce, "WebSocket") for the hash validation of the server to work.
>
> But if the hijacker can't generate H(c_nonce, "WebSocket") himself, though,
> he can't trick some non-websocket server into computing that hash. Tricking
> a server into echoing or simple manipulation, sure, but not forcing a
> computation of a hash foreign to the server's protocol.
>

Indeed.  The security argument for the non-TLS handshake then relies
not only upon the nonces but also upon the bytes of the protocol that
surround the nonces, which is one reason why its security is dodgy.

Adam

---

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

2010/9/2 Ian Fette (イアンフェッティ) <[email-masked]>:
> from 0 to INT_MAX).

True, and I expect to see many implementation that just send 1234 5678

> confused, and not offer the same protections.

How could the hex number be confused? How could it not offer the same
protection?
If we can't answer these questions, then we don't understand the
problem and thus we are unlikely to design a good solution.

> attacks, and so there are slightly different criteria.

True.   It is designed to protect against a server that can be tricked
into sending a valid 101 response and
then valuable data without authentication.   The chances of that are
already extremely remote, and if such
a server did exist it would be vulnerable to so many other exploits.
It does strike me as a lot of bother for a
vanishingly small vulnerability.

> to revisit it just for the sake of "I would prefer something simpler".

At the time this "feature" was unilaterally added to the draft, I
argued strongly against it being adopted as the ietf-00 draft because
there had been no due diligence on the proposal (and there are real
intermediary problems as a result). Now using the "it's implemented so
accept it" argument is really not very acceptable considering the
history of this.

However, I do agree it is not a hugely important technical issue
(unlike the placement of the the random bytes).   So I'll just rest my
case by saying that when I implement the Jetty client,  I think I will
use the fixed string

Sec-WebSocket-Key1: the ietf process failed 12345678

cheers

---

From: Joe Hildebrand <[email-masked]>
Date: Wed, 01 Sep 2010 17:41:30 -0600

> Sec-WebSocket-Key1: the ietf process failed 12345678

It's too early to declare that, I hope.

Let's start by understanding the requirement.  Gabriel, it looks like we
don't have anything that addresses the rationale behind this handshaking
approach in the requirements draft -- do you concur?

Assuming that my quick skim of draft-ietf-hybi-websocket-requirements-01
didn't miss anything, can someone propose language for the requirements
draft that adequately captures what we're trying to protect against?

-- 
Joe Hildebrand

---

From: Adam Barth <[email-masked]>
Date: Wed, 1 Sep 2010 16:44:50 -0700

> draft that adequately captures what we're trying to protect against?

I believe this text in the requirements draft is sufficient:

[[
   REQ. 19:  WebSocket should be designed to be robust against cross-
      protocol attacks.  The protocol design should consider and
      mitigate the risk presented by WebSocket clients to existing
      servers (including HTTP servers).  It should also consider and
      mitigate the risk to WebSocket servers presented by clients for
      other protocols (including HTTP).

   Reason: As the Web Socket protocol is expected to be mainly used in
   browsers, a careful design is necessary to mitigate the chances for
   hostile JavaScript to use WebSocket for a cross-protocol attack
   against vanilla HTTP resources or non-HTTP servers.  More the design
   should prevent the possibility for cross-site XMLHttpRequest (using
   CORS or XDomainRequest) to be used for a cross-protocol attack
   against WebSocket resources, potentially violating integrity (though
   not confidentiality).
]]

Adam

---

From: Adam Barth <[email-masked]>
Date: Wed, 1 Sep 2010 16:44:50 -0700

[[

Adam

---

From: Greg Wilkins <[email-masked]>
Date: Thu, 2 Sep 2010 10:04:15 +1000

> approach in the requirements draft -- do you concur?

Joe,

as Adam pointed out, I think we do have consensus on the general
requirement - ie that we should protect against cross protocol
attacks.
While I don't think everybody agreed about the possibility of an
injection attack, I think there were very few who did not accept that
a nonce was a good idea.

It is just that when the nonce was added to the draft, it came with a
unilaterally invented non discussed encoding of random characters and
spaces.  It was also used as part of a fast fail attempt that has
further confused the issue.
I agree with John that this is not a huge technical issue, but I think
the strangeness of the encoding causes confusion, clouds the real
issue and is a potential ongoing cause of misunderstandings.

Anyway, I've used up my message quota on this issue, so I'll let it
go.  I think the process failed letting this get into an ietf WG draft
in the first place, but it wont be the end of the world if it stays
in.

cheers

---

From: Gabriel Montenegro <[email-masked]>
Date: Thu, 2 Sep 2010 00:18:52 +0000

I would hope that a potential simplification of this is still possible, specially if it does not water down whatever guarantees it is supposed to provide. I was assuming we would revisit this in the next phase after the framing got solidified.

> -----Original Message-----
> From: [email-masked] [mailto:[email-masked]] On Behalf Of Greg
> Wilkins
> Sent: Wednesday, September 01, 2010 5:04 PM
> To: Joe Hildebrand
> Cc: hybi; Brodie Thiesfield
> Subject: Re: [hybi] WebSocket handshake (HTTP and SSO)
> 
> _______________________________________________
> hybi mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/hybi

---

From: Ian Fette (イアンフェッティ) <[email-masked]>
Date: Wed, 1 Sep 2010 17:49:18 -0700

In my mind, what would really help is a specific enumeration of attacks with
some minimal amount of information as reference, rather than only saying
"protect against cross protocol attacks." There are some experts in the
group who have much of this in their head, for the rest of us, it's really
nice to have a list that we can evaluate alternate proposals against, and
verify that "Yes, proposal X protects against attacks 1-5, while Proposal Y
misses attack 4."

Otherwise, it's really hard to have concrete discussions IMO.

On Wed, Sep 1, 2010 at 5:18 PM, Gabriel Montenegro <[email-masked]>wrote:

> I would hope that a potential simplification of this is still possible,
> specially if it does not water down whatever guarantees it is supposed to
> provide. I was assuming we would revisit this in the next phase after the
> framing got solidified.
>

---

From: Scott Ferguson <[email-masked]>
Date: Wed, 01 Sep 2010 18:36:14 -0700

Ian Fette (イアンフェッティ) wrote:
> On Wed, Sep 1, 2010 at 2:28 AM, Greg Wilkins <[email-masked] 
> <mailto:[email-masked]>> wrote:
>
>
>     same random number generator can have unexpected numeric
>     effects....I fear that this
> First, I'm not sure how important it is that the numbers are 
> _strongly_ random, so long as they come from a sufficiently large pool 
> of options (e.g. from 0 to INT_MAX). The point of the handshake is not 
> to establish e.g. key material that will be used for securing the 
> connection. Rather, the point of the handshake is to ensure that each 
> end is actually a WebSocket server/client. Using the same number all 
> the time could mean that the server could always give back the same 
> response, which would not be desirable as that would imply that the 
> server might not actually be parsing the entire handshake, but rather 
> just echoing things back. Using a different number each time ensures 
> that the server is actually parsing the handshake and not just 
> returning a predefined value. How strong the RNG is doesn't seem to be 

The randomness is important because if the hijacker can predict the next 
random number, he can pre-generate the server's response in the initial 
attack and might be able to trick the target server into echoing that 
response (as Adam pointed out earlier.)

To repeat Greg's point, randomness is a tricky business and it's very 
possible to reduce your bits of randomness by using non-cryptographic 
algorithms, like the operations in the current draft, without realizing 
the problems. You might have 64 bits of integer but only 8-12 bits of 
randomness.

That's why a plain hex-encoded nonce can be better than something 
complicated, because you know how many bits of randomness it has.
>
> As for the spaces, it's to protect against injection as you say. The 
> goal is to prevent it from being smuggled in the PATH in such a way 
> that that e.g. a HTTP request could be misinterpreted as a WS 
> handshake request. As spaces must be encoded in the path (%20) this is 
> designed to prevent against that, ditto with CRLF. 

This is one of the problems in the current handshake. The parts that are 
trying to validate the server as a websocket server and the parts that 
are trying to validate the client as a websocket client are jumbled 
together in a way that makes it hard to evaluate and appears to 
compromise both validations.

For server validation, any hijacker injection of those keys is 
irrelevant if the key/nonce is kept secret from the hijacker and if the 
hash calculation is sound. It doesn't matter if he can inject bogus 
keys, because the bogus keys will cause the server to return a bogus 
hash and a bogus hash will be rejected by the client.

What matters is keeping the key/nonce secret from the hijacker, and 
using a solid hash function, so he can't generate the real hash.

For client validation, the draft looks pretty ad hoc. I don't see any 
clear strategy for validating the client as websocket. The presence of 
spaces in the header or the random bytes after the GET are not really 
verifying the client is a websocket client. They're just trying to break 
HTTP, which isn't the same thing.

> I think the worry is that a hex number in the header could be 
> potentially confused, and not offer the same protections.

That's one of the dangers of the current spec. Because it's confusing 
and looks like it does a lot, it appears more secure than a 
straightforward, standard security design.

> I think some of the confusion is that this handshake isn't really 
> designed to provide a secure channel (e.g. choose keys that will be 
> used to encrypt further data), rather the handshake is to protect 
> against cross-protocol attacks, and so there are slightly different 
> criteria.

I don't think anyone has suggested that.
>
> While I might agree that it could perhaps be simpler and still work, 
> there is also an argument for defense in depth, and frankly it is not 
> difficult to implement (we and others have already done it), so I'm 
> inclined not to want to revisit it just for the sake of "I would 
> prefer something simpler" - would really rather move forward. There 
> are some open issues on the handshake that I would love to discuss, 
> e.g. #4 - making sure that we fail on intermediaries that won't 
> forward data properly but at the same time not hang on intermediaries 
> - but redoing the whole thing based on preference without any real 
> demonstrated problems (and having people already implemented it makes 
> me confident it's possible to implement) isn't really that enticing.

Even with a defense in depth strategy, each security layer needs to 
solve its intended problem correctly.

-- Scott

---

From: Willy Tarreau <[email-masked]>
Date: Thu, 2 Sep 2010 07:38:36 +0200

> critical for this, unless I've missed something.

While not *that* important, it should be at least a little bit. The example
that Greg gave (1/48 to guess the random) means that blind attacks targetting
browsers that have that poor RNGs may still have a massive impact if the
request can be forged so that a victim server's response matches one of these
random numbers.

> must be encoded in the path (%20) this is designed to prevent against that,

In my opinion this was only necessary because of the HTTP-like imitation
which was an incomplete implementation. With real HTTP, you can't make the
req-uri slip into the headers, because the CRLF terminates the request line.

> confused, and not offer the same protections.

Well, we already have Content-MD5 in HTTP and it does not cause such a mess.
Once again, I think *some* of the defenses were implemented because the
protocol was redesigned from scratch and needed to have at least some
intrinsic protections that HTTP offers by default but this one could not
benefit from. That's exactly where relying on proven stable protocols is
a lot better than trying to reinvent the wheel.

Regards,
Willy