[Development] websockets (was RE: Qt 5.3 Feature freeze is coming quite soon...)
Konrad Rosenbaum
konrad at silmor.de
Wed Jan 29 09:45:55 CET 2014
Hi,
[Warning: this mail is kind of lengthy]
I read the RFC for WebSockets and some of the material describing the attacks
that masking is supposed to mitigate.
Now that I'm through I'm quite disappointed: it was less funny than I thought.
The RFC is just not very good at explaining the security background of
seemingly strange specs.
I now also understand why masking needs strong random. Sadly.
One piece of strangeness remains: I can't for the life of me figure out why
the handshake has to use a cryptographic hash algorithm, when a simple header
value would have sufficed. On the part of the paper (link below) I guess it is
typical of cryptographers to use cryptographic tools to the exclusion of
simpler tools, on the part of the RFC authors ... I don't know...?
On Monday, Monday 27 January 2014 at 11:12, Konrad Rosenbaum wrote:
> On Sunday, Sunday 26 January 2014 at 23:46, Richard Moore wrote:
> > The aim of the masking is to prevent request splitting and smuggling
> > attacks when going through proxies. It prevents an application from
> > being to trick proxies into beginning a new request that does
> > something different to the one intended.
> >
> > https://www.owasp.org/index.php/HTTP_Request_Smuggling
>
> Thanks for the link, this is an interesting attack on faulty proxies.
The original paper on how these attacks relate to websockets:
http://w2spconf.com/2011/papers/websocket.pdf
Let's formulate a more understandable threat model than was done in the RFC:
The masking is supposed to protect explicitly configured and transparent
proxies (some of which are badly broken and vulnerable, ie. the normal
deployment for many large corporations) from malicious active web content.
Specifically against various attempts of cache poisoning (in which the proxy
is made to cache the wrong content for a URL) and IP hijacking (in which the
proxy briefly redirects a request to the wrong server).
In laymans terms: The conclusion of the paper was that if the script or
flash/java applet running in the browser is able to control any part of the
content that is sent over the wire enough to inject something that looks like
an HTTP header (even if it is technically at the wrong position in the stream)
then some proxies are idiotic enough to actually interpret these as part of an
HTTP exchange, sometimes redirecting the traffic, sometimes just accepting
anything at face value. The rest of the company now will get an attack kit
delivered instead of their morning news or the browser may be tricked into
allowing an attack applet that it should not have allowed (one which comes
from the wrong server, but still gets access to the open tab and its content).
To be explicit about it: the masking does not (as we assumed) try to protect
the data that is being transmitted from eavesdroppers. Instead it tries to
protect badly maintained infrastructure (and different users on the same badly
maintained network) from malicious scripts run in an usually trusted program.
In other words: the WebSocket spec tries to clean up after lazy and idiotic
proxy programmers and admins (sorry, I don't have a better term for them).
The masking does explicitly not defend against stand-alone applications that
the user starts outside the browser. This kind of magic is beyond the mere use
of bits...
Consequently it does also not defend against malicious browsers. Which are a
kind of application after all...
Let's translate this into scenarios which are relevant for Websockets in Qt:
Someone creates a browser with Qt (it has been rumored to have happened) and
uses this Websocket implementation to give scripts access to their servers.
Earlier or later some weird script (embedded in some flaky advertisement for
unsavory products) decides to poison the local proxie's cache.
This can be generalized to: any Qt based application that uses Websockets and
allows content from outside the app to control such a socket can be used to
mount this attack against a vulnerable proxy. A local user scripting his app
may be less likely to screw up his own environment...
On second thought: consider local users as good a conductor for malware as
copper is for electricity. So: any app that allows networked and/or user
generated content to control the websocket can be used as an attack tool
against (explicit or transparent) web proxies.
Masking is one way of defending against this: it makes it very hard for the
malicious script to control what actually goes over the wire.
The paper already showed a few mitigation strategies, only one made it into
the RFC in a very washed down way (the paper proposed a stream cipher as
masking).
There are several additional strategies, which should be employed in my not so
humble opinion:
1) create a fresh TCP connection for each Websocket, this way it is not
possible to combine a previous HTTP request and a socket in an attack;
consequently: if the handshake fails: terminate the TCP connection!
2) when faced with an explicitly configured proxy: ALWAYS use the CONNECT
method before sending the actual socket request - proxies do not care about
the socket content after a CONNECT is through - additionally there are
probably close to zero deployed proxies that even understand the semantics of
Upgrade: websocket.
Unfortunately 2) does not help with broken transparent proxies, since by their
nature you cannot detect them easily and it is not a good strategy to send a
CONNECT just in case...
3) implement masking properly.
The latter can be done in stages, I'd propose this plan:
First: implement websockets, get them into Qt. For the mask generation create
a virtual protected method "QByteArray getNextMaskValue(int numbytes)const"
and implement it using qrand()&0xff for each byte - please note that you have
to initialize with qsrand in each thread. Document the shortcoming with
something like this:
"This implementation of WebSockets uses cryptographically weak random numbers
during communication. If you allow user generated or downloaded scripts to
access WebSockets, then malicious scripts could abuse this implementation to
attack some vulnerable web proxy servers (e.g. for cache poisoning). In this
case it is recommended that you reimplement getNextMaskValue to use
cryptographically strong random numbers."
(maybe add a link to the paper)
Using qrand provides only a very small obstacle to scripts, I'd guess
something in the order of sending 2^10 frames (done in minutes) could be
enough to confuse some particularly bad proxies. If the script has access to
qrand it may even be a lot quicker. No amount of hashing, seeding, shifting or
otherwise manipulating the numbers would change this (I've fallen into this
trap years ago, the result was not pretty). Using a deterministic approach
(like shifting the number by a fixed amount or shuffling it a bit
mathematically) reduces the attack difficulty to the order of 10-50 frames
(Done in fractions of seconds) - the number is this high because you still
have to guess the kind of proxy that is being used (a clever script would need
2 frames to guess the "random" number sequence).
Later on: when a plan has been found to expose the low-level OpenSSL API to Qt
this implementation could be changed to use OpenSSL and fall back to qrand if
it is not available. The documentation would change to something like:
"If you allow user generated or downloaded scripts to access WebSockets, then
this implementation needs OpenSSL to protect some vulnerable proxy servers
against cache poisoning or similar attacks. OpenSSL will be detected
automatically, if OpenSSL is not available this class will fall back to a less
secure implementation."
A fair warning to proxy admins though: 32 bits of good random is still an
awfully small amount of bits that stands between a determined attacker and
your proxy. If untargeted attacks on proxies were as common as spam I would
expect about one cache poisoning incident per year for an organisation with
several hundred to a few thousand employees and perfect browsers. If someone
targets your organisation or one of the browsers uses bad random this can be
done in days and the poisoned cache is just the beginning of the trouble... So
keep your proxies up to date!
Konrad
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/development/attachments/20140129/1018f84e/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 490 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.qt-project.org/pipermail/development/attachments/20140129/1018f84e/attachment.sig>
More information about the Development
mailing list