[Development] websockets (was RE: Qt 5.3 Feature freeze is coming quite soon...)

Kurt Pattyn pattyn.kurt at gmail.com
Sun Jan 26 20:23:55 CET 2014


On 26 Jan 2014, at 19:12, Konrad Rosenbaum <konrad at silmor.de> wrote:

> Hi,
>  
> [wow, I had a good laugh!]
>  
>  
> On Sunday 26 January 2014, Kurt Pattyn wrote:
> > On 26 Jan 2014, at 11:31, Konrad Rosenbaum <konrad at silmor.de> wrote:
> > > Depends. What is it used for? Is it just obfuscation or is it supposed
> > > to be real security?
> > 
> > Well, there are 2 places where random numbers are used:
> > 1. During the handshake phase
> > Client sends a handshake request containing a 128-bit random number
> > converted to a string hex representation (Sec-WebSocket-Key). The server
> > appends a well-known UUID (published in the RFC) to that number and
> > calculates a SHA-1 hash. This hash in sent to the client, which in its
> > turn appends the same UUID to the random number it sent before, and
> > calculates a SHA-1 hash. If both the server-sent hash and the client
> > calculated hash match, the handshake succeeds.
>  
> And this is sent in the open? On an unsecured connection?
This is sent in the header of an HTTP request, fully readable.
Of course, WebSockets also supports SSL.
>  
> This is the most elaborate scheme of a not-so-secret handshake that I've read so far! The only thing that is more hilarious is the Big Bang Theory scene in which Sheldon lectures his friends on the "secret knock" before Leonard's birthday party...
>  
> My personal opinion on unencrypted connections: don't sweat it. Use whatever is available. qrand is as secure as the rest of the connection (i.e. not secure at all). Using secure random does not change a thing in this case (only CPU cycles wasted on the client).
>  
> On encrypted (SSL) connections: if this covers several HTTP(S) requests and not a simple non-interrupted socket then this should better be some secure 128 bits. Although it is beyond me why you would hash them again and again - they could be used as a cookie…
It is one request/response for the handshake and, if successful, the connection stays open.

>  
> [See bottom of my response for some more elaborate argument on this.]
>  
> > 2. When sending data from client to server (not the other way)
> > The client generates a 32-bit random number.
> > This random number is stored in plain text in the header of each frame.
> > The data is XOR-ed with that 32-bit random number.
> > 
> > The server takes the 32-bit random number from the header and XORs it
> > with the payload to get to the original data.
> > 
> > I really fail to see what the intention is of this mechanism. I really
> > fail to see what could make this communication ‘secure’.
>  
> I seem to remember that a certain Julius Caesar had a similarly clever idea for securing his correspondence. Of course Julius had the excuse that advanced math-based cryptography was not available in his time...
>  
> (https://en.wikipedia.org/wiki/Caesar_cipher)

Given the time and the context, this was far better, because it least he didn’t specify how to decipher the text :-)
>  
>  
> > "The masking key needs to
> >  be unpredictable; thus, the masking key MUST be derived from a strong
> >  source of entropy, and the masking key for a given frame MUST NOT
> >  make it simple for a server/proxy to predict the masking key for a
> >  subsequent frame.  The unpredictability of the masking key is
> >  essential to prevent authors of malicious applications from selecting
> >  the bytes that appear on the wire.”
>  
> My above statement about the handshake was wrong. Enormously so.
> This statement tops all the comedy in in my sizable DVD collection!
>  
> > Why should the masking key be unpredictable if it is send unencrypted
> > along with the masked data? Why would a server/proxy predict the masking
> > key if it can just fetch it from the header? To me it looks like having
> > a locked door with the key in the keyhole. Why would a burglar use a
> > crowbar if he has the key?
>  
> Exactly. This toy-cipher and its description is equivalent to triple-ROT13 (triple for more "security"…)
I’m glad you mentioned ‘triple’...
>  
>  
> #-(
>  
> > > If the latter: is it the only way to generate security? (If so: in all
> > > likelyhood you are affixed by an inclined plane wrapped helicly around
> > > an axis. In laymans terms: screwed.)
> > > 
> > > If the former: unless it is absolutely necessary for understanding the
> > > other side of the communication channel - don't bother implementing
> > > it. Obscurity is no security.
> > 
> > Well, the standard requires the frames that go from client to server to
> > be masked. So yes, it is absolutely necessary, but in my opinion
> > complete overkill.
>  
> I agree with you. The only thing this defends against is absolutely clueless IT people (pointy haired boss types) who have read access to network logs, but whose 8 year old kids refuse to help with a simple script.
>  
> Use any source of (weak) random (e.g. qrand) and ignore this bullshit about "strong source of entropy".
>  
> If anyone asks you why you are using insecure random:
>  
> a) on unsecured connections it is pointless to get secure random and then transmit it in the open together with the data. Revealing secure random to the open makes it magically insecure. You might as well not try to conceal the data at all.
Maybe not concealing will get hackers confused. ‘Hmmm, I can read this. What do I miss?’
>  
> b) on secured (SSL) connections it is pointless to implement a toy encryption when SSL is already doing an adequate job of doing real encryption designed by real cryptographers. 
Exactly what I was thinking. XOR-ing text with a public mask… I still have the feeling I am missing something.
By the way, this is the complete text of the paragraph regarding masking:

   The masking key is contained completely within the frame, as defined
   in Section 5.2 as frame-masking-key.  It is used to mask the "Payload
   data" defined in the same section as frame-payload-data, which
   includes "Extension data" and "Application data".

   The masking key is a 32-bit value chosen at random by the client.
   When preparing a masked frame, the client MUST pick a fresh masking
   key from the set of allowed 32-bit values.  The masking key needs to
   be unpredictable; thus, the masking key MUST be derived from a strong
   source of entropy, and the masking key for a given frame MUST NOT
   make it simple for a server/proxy to predict the masking key for a
   subsequent frame.  The unpredictability of the masking key is
   essential to prevent authors of malicious applications from selecting
   the bytes that appear on the wire.  RFC 4086 [RFC4086] discusses what
   entails a suitable source of entropy for security-sensitive
   applications.

   The masking does not affect the length of the "Payload data".  To
   convert masked data into unmasked data, or vice versa, the following
   algorithm is applied.  The same algorithm applies regardless of the
   direction of the translation, e.g., the same steps are applied to
   mask the data as to unmask the data.

   Octet i of the transformed data ("transformed-octet-i") is the XOR of
   octet i of the original data ("original-octet-i") with octet at index
   i modulo 4 of the masking key ("masking-key-octet-j"):

     j                   = i MOD 4
     transformed-octet-i = original-octet-i XOR masking-key-octet-j

   The payload length, indicated in the framing as frame-payload-length,
   does NOT include the length of the masking key.  It is the length of
   the "Payload data", e.g., the number of bytes following the masking
   key.

>  
> c) Or the social argument: anyone clever enough to crack an SSL secured connection might fall off their chair laughing hard when after spending days or decades cracking the SSL-shell-of-encryption and they see secure random being transmitted in the open along with data to make the data "more secure" - I would not want to be responsible for the kind of injury they might sustain falling head first onto an open computer case... ;-)
Hahaha
>  
> > > I would not recommend trying to implement your own PRNG either -
> > > getting it right is horribly difficult. Getting the entropy gathering
> > > right in a cross- platform way is much worse effort…
> > 
> > I wouldn’t even dare :-) This is a research field on its own.
>  
> Very wise decision. :-)
However, now that you pointed me to Julius Caesar...
>  
> > > I wonder whether it would be possible to expose the low-level APIs of
> > > OpenSSL to Qt, it has quite a good random number generator and it is
> > > used for QSslSocket already.
> > 
> > Indeed, I planned to use the OpenSSL RNGs (the library has FIPS approved
> > RNGs), but that library is not available on all platforms I think.
> > Besides that, I am afraid this is a very expensive operation, certainly
> > because another masking key has to be calculated for every frame.
>  
> Don't bother for the masking key.
>  
> If you do use OpenSSL RNGs: don't specifically pick FIPS approved ones or some other specific models for whatever reason (one of the FIPS RNGs may have been made intentionally insecure by the NSA: Dual-EC-DRBG) - just pick the default secure RNG and let the experts from OpenSSL decide which one is best ("best" may even change between releases because of new discoveries in crypto).
Nice advice.
>  
> > Konrad, reading the cases where random numbers are used, do you think it
> > is worth the effort? I am even considering to calculate the masking key
> > just once and use it for every frame (would speed up the communication).
>  
> Don't do any elaborate calculation on the "masking key". Just generate it with qrand every time you need one. Using the same "key" every time might piss off some paranoid implementations (I've seen some truly idiotic implementations in the SOAP arena, I don't expect those vendors to do better with Websockets).
Indeed, especially paranoid about someone having cracked the message ;-)
After a second thought, I could increment the key and then left-shift 3… If the other side hasn’t been written by Suetonius, I’ll be safe, haha.
>  
> There is one specific case in which it would make sense to use secure random and in which the OpenSSL library can be assumed to exist. If all of those criteria are met then the handshake key needs to be secure:
>  
> 1) the handshake happens on a connection that uses SSL
Can be done with the WebSockets specification.
> 2) there is a chance that the websocket spans several actual TCP connections
>   (e.g. by being split over several HTTP requests, the splitting could be
>    done by a proxy in this case)
The initial HTTP handshake request is very small, too small to split, and secondly a web socket is bound to a single TCP connection.

> 3) the key data (or something derived from it) is actually used to identify
>    the connection between separate TCP connections
There are two kinds of ‘keys’: the key that is exchanged during the handshake (128-bit) and the masking key (32-bit).
The first one, is thrown away as soon as the handshake succeeds. The second one is regenerated for every frame.
So, not used for identification.
>  
> If criterion 1) fails (unsecured connection) then there is no need to bother. The protocol can be executed by any attacker. Using good random slows the legitimate user down, not the attacker.
Right. XOR-ing the data over an insecure connection is stupid (and a hacker doesn’t even have to crack his head: just look at the RFC and the solution is there). XOR-ing the data over a secure connection, well, if the connection is already secure, is defeating its purpose. Well maybe - I have not studied that - if a hacker would break the SSL connection, that very last one hurdle is maybe one too much, and maybe he’ll give up?
>  
> As far as I could get from Wikipedia item 2 is not applicable, since one TCP connection is upgraded from HTTP to Websocket and stays active in Websocket mode (i.e. if the TCP connection closes, then the Websocket is lost as well). So the whole argument fails and the key does not need to be secure.
Completely right.
>  
> I couldn't find much information about criterion 3 yet, but it seem to be used for the initial handshake only - never after that - right?
Indeed, as explained above: the handshake key is thrown away after the initial handshake, and the masking keys are regenerated for every frame.
>  
>  
> However, if all 3 of them are correct then the handshake key is the only thing that chains separate TCP/SSL connections together. In order to be secure it has to be at least as strong as the connections it is supposed to chain together.
Out of luck I guess ;-)
>  
>  
> Maybe I should read the RFC later on - I might need a good laugh after work tomorrow... :-)
Mind the open computer case...
>  
> 
Kurt
>  
>  
>  
> 	Konrad

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/development/attachments/20140126/03ac4426/attachment.html>


More information about the Development mailing list