Subject: [hybi] Mandatory vs Optional masking. was: Straw Poll: is Upgrade with client->sever XOR mask acceptable?

From: Greg Wilkins <[email-masked]>
Date: Fri, 24 Dec 2010 08:46:34 +0100

On 24 December 2010 06:49, Maciej Stachowiak <[email-masked]> wrote:
>
> Masking should not be optional. If we use GET+Upgrade as the handshake, almost all of our security against cross-protocol attacks will rest on masking. If there is a way to turn it off, then tricking clients and servers into turning it off becomes an extremely powerful attack. Even if that is possible only in the face of bugs, it's still very dangerous. Therefore I would recommend against this.

There is a big difference between having masking optional in a the
protocol and having it optional in a client.

I have zero problems with classes of clients (eg browsers) making
masking non optional, so that there is no way of switching it off.
If you are saying it might be switched off due to a browser bugs, then
you may as well posit that a browser bug will allow a predictable or
zero masking key or bugs that let arbitrary text sent anyway.

> If we get evidence that this is needed in the future, we can revisit the issue.

If we make it non-optional, then we will not be able to revisit in the
future.   Infrastructure will be written with hard wired masking and
it will not be able to be switched off or replaced in future.

Also, without any usage of the extension mechanisms, I expect many
buggy implementations will be written that do not correctly handle
extension data and that within a short period we will be unable to use
the extension mechanism because of buggy implementations that have
been deployed.

Making masking an extension will give us future flexibility and will
also mean that all implementations written now will have to implement
the extension data handling correctly.

I repeat, the browsers can and should make masking non optional and
the default if no other extension is negotiated.  There should be no
way for the browsers to turn off masking.

---

From: Maciej Stachowiak <[email-masked]>
Date: Fri, 24 Dec 2010 01:46:47 -0700

> zero masking key or bugs that let arbitrary text sent anyway.

The attack I'm worried about is using a browser-hosted HTTP client to attack a WebSocket server. If the server can be tricked into turning masking off, then masking is no longer a defense against this threat model.

> the extension data handling correctly.

If masking is the only piece of extension data in most frames, then there is still a risk that implementations will get it wrong, e.g. by expecting masking info to be in extension data. So I don't see any benefit here.

> way for the browsers to turn off masking.

If every server that gets written will have a way to turn masking off, then there is still risk. Browser-hosted clients and servers that are exposed to the public Internet (i.e. not behind some sort of firewall) both need to force masking on, always. Given this, there is not much room to make it optional.

Regards,
Maciej

---

From: Willy Tarreau <[email-masked]>
Date: Fri, 24 Dec 2010 14:33:26 +0100

> The attack I'm worried about is using a browser-hosted HTTP client to attack a WebSocket server. If the server can be tricked into turning masking off, then masking is no longer a defense against t…

I thought we said quite some time ago that the browser-hosted HTTP client
was not able to set the Upgrade: WebSocket header.

Willy

---

From: Bruce Atherton <[email-masked]>
Date: Fri, 24 Dec 2010 17:26:31 -0800

> If every server that gets written will have a way to turn masking off, then there is still risk. Browser-hosted clients and servers that are exposed to the public Internet (i.e. not behind some sor…

I think this is an assumption that need not be made. I don't think the 
spec needs to mention optional masking at all.

What I would suggest is that the spec say that by default all websocket 
traffic uses XOR or whatever masking scheme is determined as desirable. 
But it should also mention that custom masking schemes may be used 
through a custom extension.

Thus, the vast majority of all websocket-aware software will only 
implement the default masking, since no other is specified. But all the 
well designed software will recognize that the masking is not 
necessarily fixed and will allow a hook for a custom masking strategy. 
Then, in places where someone actually needs an alternate like null 
masking, there will be a way to allow that.

For everyone else, default masking will rule.

---

From: Bjoern Hoehrmann <[email-masked]>
Date: Sun, 26 Dec 2010 17:54:23 +0100

* Greg Wilkins wrote:
>[...]

I am not sure I understand this discussion. It seems that Greg wants the
protocol to be designed in a manner so that consenting endpoints do not
have to apply masking, while Maciej doesn't want endpoints to be able to
negotiate masking from within the protocol. If you have a controlled en-
vironment where it's okay to not mask, that's something that can be de-
termined out of band, simply let those endpoints use keys that translate
to no masking; that requires a certain protocol design and would not e-
liminate the size overhead of the keys, but Greg seems more concerned
with the computational overhead than the size overhead, so these are not
mutually exclusive positions.
-- 
Björn Höhrmann · mailto:[email-masked] · http://bjoern.hoehrmann.de
Am Badedeich 7 · Telefon: +49(0)160/4415681 · http://www.bjoernsworld.de
25899 Dagebüll · PGP Pub. KeyID: 0xA4357E78 · http://www.websitedev.de/

---

From: Adam Barth <[email-masked]>
Date: Sun, 26 Dec 2010 16:07:05 -0800

> mutually exclusive positions.

In such environments, the endpoints should feel free to use
BjoernSockets and ignore the the WebSocket protocol entirely.  For
WebSockets, however, the masking is an essential part of the security
of the protocol and therefore is not optional.

Adam

---

From: Greg Wilkins <[email-masked]>
Date: Mon, 27 Dec 2010 22:31:40 +0100

Bruce,

What I'm concerned about is coming up with a design such that
websocket code that does not care about content does not need to
implement any masking.  ie it can transport the payload as an opaque
blob and not care if it is masked or not.

Only the endpoints and the few intermediaries that care about content
will need to implement masking.  Thus is masking changes, less code
will be affected.

To achieve this, it is important that framing is not masked.  Only the
payload should be masked.

On 25 December 2010 02:26, Bruce Atherton <[email-masked]> wrote:
>> If every server that gets written will have a way to turn masking off,
>> then there is still risk. Browser-hosted clients and servers that are
>> exposed to the public Internet (i.e. not behind some sort of firewall) both
>> need to force masking on, always. Given this, there is not much room to make
>> it optional.
>
> I think this is an assumption that need not be made. I don't think the spec
> needs to mention optional masking at all.
>
> traffic uses XOR or whatever masking scheme is determined as desirable. But
> it should also mention that custom masking schemes may be used through a
> custom extension.
>
> Thus, the vast majority of all websocket-aware software will only implement
> the default masking, since no other is specified. But all the well designed
> software will recognize that the masking is not necessarily fixed and will
> allow a hook for a custom masking strategy. Then, in places where someone
> actually needs an alternate like null masking, there will be a way to allow
> that.
>
> _______________________________________________
> hybi mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/hybi
>

---

From: John Tamplin <[email-masked]>
Date: Mon, 27 Dec 2010 16:49:15 -0500

> will need to implement masking.  Thus is masking changes, less code

I am still not sure exactly what intermediaries would care about
WebSocket framing but not the payload.  Do you have an example?

> payload should be masked.

I suppose we could say the extension data field contains the mask if
masking is present, and rely on knowledge of which end of the
conversation you are in to interpret it, but that seems unclean to me
and complicates the life of simple implementations that don't ever
want to support extensions.

You didn't comment on the other thread where I wrote up what I thought
a reasonable solution to your requirement was (though it seems clear
we aren't going to gain consensus on optional masking).

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

---

From: Greg Wilkins <[email-masked]>
Date: Mon, 27 Dec 2010 22:59:32 +0100

> The attack I'm worried about is using a browser-hosted HTTP client to attack a WebSocket server. If the server can be tricked into turning masking off, then masking is no longer a defense against t…

I'm sorry but I don't understand this threat.  Servers will never mask
data sent, they will just unmask data received.

Thus is a client using whatever technology is able to send bytes that
look like a HTTP request with a spoofed host header, then they might
be able to poison an intermediaries cache.    This can be done with or
without masking, because the attacker controls the server and knows
any masking key that might exist.

Besides, I do not think that a non WS HTTP client in a browser will be
capable of doing an upgrade or sending the required Sec- headers.

> If masking is the only piece of extension data in most frames, then there is still a risk that implementations will get it wrong, e.g. by expecting masking info to be in extension data. So I don't…

Currently without any defined extension data, implementations can
assume that extension data length is 0 and will work fine.  Having a
masking key as extension data, perhaps with undefined length, will
force implementations to consult the extension data length field to
find the normal data payload.

> If every server that gets written will have a way to turn masking off, then there is still risk. Browser-hosted clients and servers that are exposed to the public Internet (i.e. not behind some sor…

I still don't see how this is a problem.  Browser based clients should
just be implemented to always send masked data.  They should not have
an option to turn off masking, so there is no risk.   Even with
compulsary masking, browsers could be written with options for 0 keys
or predictable random number generators, so compulsary masking is no
protection from browsers intentionally dropping their guard.

cheers

---

From: Greg Wilkins <[email-masked]>
Date: Mon, 27 Dec 2010 23:03:59 +0100

> WebSocket framing but not the payload.  Do you have an example?

A websocket aggregator that accepts WS connections and applies a MUX
extension to send frames from multiple connections to a smaller set of
connections to application servers.   Such aggregators already exist
for HTTP to reduce the connection load on application servers, so
there is no reason to think they will not be similar for WS.

Why should such aggregators have to implement masking, just to see the
framing, apply an extension and then remask before sending to the
application servers. These aggregators should be able to treat payload
as opaque blobs and should never need to implement masking, optional
or otherwise.

cheers

---

From: John Tamplin <[email-masked]>
Date: Mon, 27 Dec 2010 17:15:52 -0500

> as opaque blobs and should never need to implement masking, optional

Unless it is going to be masked multiple times, they do need to unmask
the input streams and remask them with one mask.

---

From: Maciej Stachowiak <[email-masked]>
Date: Mon, 27 Dec 2010 16:46:40 -0800

> data sent, they will just unmask data received.

Let me try to explain it in more detail.

We have the following entities involved:
- Browser-hosted HTTP client stack. Assumed trusted, but not necessarily aware of special WebSocket requirements.
- A WebSocket server with possibly sloppy handshake handling (historically it seems servers for newline-based protocols are very generous in skipping over unknown content, and loose in trying to parse things they recognize). The victim, not the attacker, in this case. In particular, this WebSocket server accepts command messages as WebSocket frames, and counts on validation by a browser-hosted WebSocket client to ensure it never receives any frames from unauthorized clients.
- Malicious JavaScript running in the browser.

The attack proceeds as follows:

- Malicious JavaScript code pre-generates valid-looking WebSocket frames that would issue undesired commands.
- Malicious JavaScript code uses a browser-hosted API that can issue cross-domain HTTP requests (form submission, XHR2, XDR) to connect to the WebSocket server.
- Malicious JavaScript tricks server into thinking masking is off.
- Malicious JavaScript sends the precomputed WebSocket frames as the body of its HTTP request.

Masking would ordinarily completely defend against this attack, because the server wouldn't be able to parse precomputed frames, since the malicious JS code has to compute them before seeing the server nonce. This is impossible, and the server has to get mask computation right to operate under normal non-attack conditions, so it's less likely that it will be too lenient.

But if masking is optional and can be turned off, then this attack on integrity remains a risk. In other words, if masking is optional and there is an in-protocol way of turning it off, this places WebSocket servers at greater risk. Note: this would not apply to an out-of-band way to turn masking off by prior arrangement between two endpoints that trust each other and are not exposed to untrusted traffic.

> any masking key that might exist.

I'm not sure what you have in mind here, but this sounds like a different attack from what I am describing.

> capable of doing an upgrade or sending the required Sec- headers.

My point is that since checking those things carefully is not required for normal operation, it is likely at least some servers will be sloppy in their checks (e.g. parsing the whole header with a regexp and failing to check for leading newlines).

> find the normal data payload.

That's true if the masking key is variable-length, though currently no one has proposed that and it doesn't seem valuable on its own merits.

> protection from browsers intentionally dropping their guard.

The risk is in the case that the attacker uses something in the browser other than the WebSocket client to perform the attack.

Regards,
Maciej

---

From: John Tamplin <[email-masked]>
Date: Mon, 27 Dec 2010 23:25:28 -0500

> find the normal data payload.

Currently there is no "extension data length" field in the standard or
in the examples given at the time we talked about how the framing
could be extended.  It was all either of known length based on the
extension or a tag/length/value format, so you could parse it as you
went and then what was left after you were done with extension data
was application data.

We could certainly define one, but unless it goes into the base frame
(I would object to that) or there is some flag to indicate that
extension data is present and therefore the length is the first thing
in the extension data, then I don't see how it helps.

---

From: Bruce Atherton <[email-masked]>
Date: Tue, 28 Dec 2010 11:43:07 -0800

Greg, I agree with you in every particular with what you say, and if you 
can achieve getting something like "servers MUST accept Websocket 
connections with default masking, but MAY accept no masking with the 
appropriate extension", then you have my grateful thanks.

My suggestion was for more of a compromise. Websockets without masking 
on the Internet is potentially harmful (at least right now), but in some 
situations for Intranets it is perfectly safe, and in fact quite 
beneficial. So the question I asked myself is how to write the spec so 
that the likelihood of any servers on the open Internet allowing 
unmasked connections is very low, while still allowing for such a thing 
to be enabled if required on Intranets.

So long as recognition is given that alternative masking (including no 
masking) may exist, it precludes design decisions (such as masking the 
framing) that make alternate masking impossible. If the developers of 
Jetty Websockets and Tomcat Websockets and mod_websocket all get 
together and declare a single custom extension shared by all of you that 
turns off masking, the chances are not bad that people that sell 
equipment into these Intranets will have to take that into 
consideration. If all of these implementations keep the acceptance of 
unmasked Websockets turned off by default, it reduces the risk of 
servers on the open internet accepting unmasked Websockets.

There is still a chance that someone writing a sloppy implementation of 
a Websocket server that will only serve publicly accessible Websocket 
ports will hear about this de facto standard and add support for it 
despite the fact there are no public internet Websocket clients that 
will speak it. If they are that lax, though, they may just add support 
for unmasked Websockets no matter what the spec says.

Of course, there is  greater risk by not specifying the no-masking 
alternative in the spec. Some companies may decide that vendor lock-in 
is far more important for their strategy than compatibility with de 
facto standards. So getting language about a no-masking option into the 
spec would be far more desirable, if you can manage it.

---

From: Bruce Atherton <[email-masked]>
Date: Tue, 28 Dec 2010 11:47:56 -0800

> the input streams and remask them with one mask.

Which to me is an argument for allowing unmasked streams within the 
Intranet, so that you don't end up with multiple masks in situations 
like this.

---

From: Bruce Atherton <[email-masked]>
Date: Tue, 28 Dec 2010 12:31:08 -0800

> the input streams and remask them with one mask.

Actually, in thinking more about it, I don't really see why you say that 
it necessarily needs to be remasked. Maybe I am misunderstanding 
something, but if the incoming stream of messages looks like:

[framing][key][masked payload]

is there any reason it couldn't be transformed into:

[new framing][channel 1][key][masked payload]

or even, if you want to send messages on multiple channels in one 
batched message:

[new framing][channel 1][key 1][masked payload 1][channel 2][key 
2][masked payload 2]

The latter example would mean that instead of a per-frame key you have a 
per-payload key, but I don't see it makes much difference.

Is this somehow contrary to the plan for masking?

---

From: Maciej Stachowiak <[email-masked]>
Date: Tue, 28 Dec 2010 15:31:31 -0800

On Dec 28, 2010, at 12:31 PM, Bruce Atherton wrote:

> Actually, in thinking more about it, I don't really see why you say that it necessarily needs to be remasked. Maybe I am misunderstanding something, but if the incoming stream of messages looks like:
> 
> or even, if you want to send messages on multiple channels in one batched message:
> 
> [new framing][channel 1][key 1][masked payload 1][channel 2][key 2][masked payload 2]
> 
> The latter example would mean that instead of a per-frame key you have a per-payload key, but I don't see it makes much difference.
> 

Yes. In masking as currently proposed, the actual mask applied is based on a combination of the per-frame key and a per-connection key, derived from the server and client nonces. If you take multiple connections as input, they will have different per-connection keys. To send them as a single multiplexed connection, you'll have to unmask them and remask them using a single per-connection key, the one you are using with the endpoint that receives a multiplexed stream. What you propose does not work, since the separate payloads were masked with different connection keys.

Even if the multiplexer and the server that receives the muxed stream somehow arrange no masking between themselves, the multiplexer must still unmask.

As an alternative, the future multiplexing extension could include a per-channel key that represents the connection key used to make that channel. However, this has several problems. First, it would increase the frame size in a way that is totally unnecessary when the the actual client is doing the multiplexing, rather than the intermediary. Second, it increases security risk, since the components of the mask would be in-band in the connection rather than negotiated based partly on a random value from the server. This would allow attackers to precompute what a valid frame looks like.

Thus, the only option is for a multiplexing intermediary to unmask each input stream.

Regards,
Maciej

---

From: Bruce Atherton <[email-masked]>
Date: Tue, 28 Dec 2010 17:54:13 -0800

> As an alternative, the future multiplexing extension could include a per-channel key that represents the connection key used to make that channel. However, this has several problems. First, it woul…

Thanks for the explanation, Maciej, but I am still confused.

It makes sense to me that a new channel would have to be requested 
before a client could be told that they have a  connection to the 
server. So I would imagine something like this:

client --[open websocket connection]--> muxer --[open new channel]--> server
client <--[server nonce (actually channel nonce)]-- muxer <--[channel 
nonce]-- server

So the client can mask based on both a channel key generated from the 
nonce and a frame key, the server can unmask, and the muxer doesn't get 
involved.

I don't see much overhead when the client does the muxing instead of a 
separate appliance, either. It would mean different nonces between 
different channels, but that seems pretty cheap and perhaps even more 
secure than otherwise. I also don't see where any more masking data is 
sent in-channel.

---

From: Maciej Stachowiak <[email-masked]>
Date: Tue, 28 Dec 2010 19:11:39 -0800

On Dec 28, 2010, at 5:54 PM, Bruce Atherton wrote:

> It makes sense to me that a new channel would have to be requested before a client could be told that they have a  connection to the server. So I would imagine something like this:
> 
> client <--[server nonce (actually channel nonce)]-- muxer <--[channel nonce]-- server
> 
> So the client can mask based on both a channel key generated from the nonce and a frame key, the server can unmask, and the muxer doesn't get involved.

You have neglected the client nonce, which will be different for each client. Let's assume there are two clients, one muxing intermediary, and one server. To extend this, you'd need a client nonce per channel too:

client1 -->[open websocket connection and send client1 nonce]--> muxer--> [open new channel with client-channel1 nonce (actually client1 nonce)]--> server
client1 <--[server nonce (actually server-channel1 nonce)] <--muxer <-- [sever-channel1 nonce]<-- server

client2 -->[open websocket connection and send client2 nonce]--> muxer <--[open new channel with client-channel2 nonce (actually client2 nonce)]--> server
client2 <--[server nonce (actually server-channel2 nonce)] <--muxer <--[server-channel2 nonce]<-- server

It seems this could allow the muxer to forward messages without re-masking, if it could prepend the channel ID without unmasking and remasking. Thoughts on this:

A) Given this kind of scheme, it's not clear that unmasking and remasking is going to be that much more expensive than reframing to add the channel ID.
B) In the case where muxing is done directly by the client, not an intermediary, the client would now have to track a send key per channel, rather than per connection, adding complexity that has no real benefit in that case.

C) This scheme requires the server to respond to a channel open request before the client can send on that channel, adding a round trip to multiplexing connection startup. A more natural scheme would have the client pick the channel ID and tell the server, while continuing to use the per-connection send key instead of negotiating one per-channel. This saves a round trip when the client sends on a new channel in an existing connection.

D) This scheme still works if multiplexing works outside the current proposed frame format, e.g. once you open a channel, every message is prepended by the channel ID. Then the muxer just prepends the channel ID and sends messages muxed as is. So this scheme is not a valid use case for avoiding masking of the  rest of the framing. In fact, with this kind of scheme, it would be quite reasonable to use the channel send key as the channel ID, and to include it in the frame before the per-frame key. This would ensure that the channel ID does not include attacker-controlled data.

Regards,
Maciej

---

From: Bruce Atherton <[email-masked]>
Date: Wed, 29 Dec 2010 18:59:42 -0800

On 28/12/2010 7:11 PM, Maciej Stachowiak wrote:
> You have neglected the client nonce, which will be different for each client.

You are absolutely right. Thanks for the correction to the diagram.

> A) Given this kind of scheme, it's not clear that unmasking and remasking is going to be that much more expensive than reframing to add the channel ID.

I'm not sure I understand what you mean. Unmasking and remasking will 
still have to reframe to add the channel ID (barring the uncomfortable 
scheme you suggest below). The savings from not going through an 
unmasking pass and a masking pass (or a combined pass) is going to 
depend on the size of the payload. For very small packets the savings 
may well be a rounding error. But for larger payloads it could make a 
difference in scalability.

Efficiency is not necessarily the most important point, though. When the 
muxer treats the data as opaque, there is a clearer separation of 
concerns. This way, the muxer doesn't even have to track any of the 
nonces and can thus be prevented from having any visibility into the 
content going past. This may make it easier to reason about behaviour on 
the network and may well have security implications.

I'm sure others, more familiar than I am with deploying these kinds of 
appliances, can come up with a host of other benefits.

> B) In the case where muxing is done directly by the client, not an intermediary, the client would now have to track a send key per channel, rather than per connection, adding complexity that has no…

I disagree that there is no benefit. I think in all cases it is more 
secure to have per-channel keys rather than relying on a shared 
per-connection key. One can imagine an attack that involves the attacker 
deducing the key based on the data sent back and forth on their channel 
and using that information to hijack another channel muxed to the same 
connection.

And what is the cost? How many bytes per-channel is needed to store the 
key in the channel struct?

> C) This scheme requires the server to respond to a channel open request before the client can send on that channel, adding a round trip to multiplexing connection startup. A more natural scheme wou…

You are right, that is another cost to having the added security of 
per-channel keys, beyond the few bytes. I see this as being the same as 
removing the ability to provide a payload from the client in the initial 
handshake when a connection is first created. Well worth the price for 
the security provided.

To me, opening a communications channel should have the same level of 
security whether it shares a socket or not.

> D) This scheme still works if multiplexing works outside the current proposed frame format, e.g. once you open a channel, every message is prepended by the channel ID. Then the muxer just prepends…

Really? You want to create yet another framing type? Is there such a 
strong objection to the method I suggested?

Using the frame key as a mechanism to identify a channel also makes me 
feel really uncomfortable. It overloads a relatively straightforward 
piece of data with a second orthogonal meaning that is bound to cause 
problems eventually. Muxing "as is" also rules out other kinds of data 
that you may want in a channel, such as a priority for QOS. Not to 
mention the risk of collision, which no matter how low it actually is 
seems too high to me to make this a good choice.

I don't follow your point about the channel id containing 
attacker-controlled data. How does that necessarily come about?