Subject: [hybi] Proposal: require non-final websocket frames to have a minimum payload length of X bytes

From: William Budd <[email-masked]>
Date: Thu, 20 Jun 2013 10:23:05 +0900

Hello everyone,

While I find RFC 6455 very reasonable all around, there is one
consequence of the spec with regard to fragmentation that seems quite
unfortunate to me.

First off, the following reasoning is given in favor of fragmentation:

"The primary purpose of fragmentation is to allow sending a message
that is of unknown size when the message is started without having to
buffer that message.  If messages couldn't be fragmented, then an
endpoint would have to buffer the entire message so its length could
be counted before the first byte is sent.  With fragmentation, a
server or intermediary may choose a reasonable size buffer and, when
the buffer is full, write a fragment to the network.

A secondary use-case for fragmentation is for multiplexing, where it
is not desirable for a large message on one logical channel to
monopolize the output channel, so the multiplexing needs to be free to
split the message into smaller fragments to better share the output
channel.  (Note that the multiplexing extension is not described in
this document.)"

And I completely agree with that. Large messages need to be fragmented
in order to be processed efficiently by websocket endpoints and
intermediates.

However, I think the spec should also make provisions against
over-fragmentation. Unless I overlooked something, RFC allows any
message to be split into an infinite amount of fragments with payloads
of 0 bytes (or if I'm wrong about that, it still allows a message to
be fragmented in a nutty number of fragments with 1 byte); and
endpoints need to handle that in order to comply with RFC 6455.

This is particularly annoying when a websocket server wants to guard
against denial of service attacks, because in the case of deliberately
over-fragmented messages the server needs to process an excessive (or
infinite?) amount of framing data before it has enough payload data to
determine whether the message is valid with regard to any API built on
top of the websocket layer.

This issue could be easily prevented if websocket frames that do not
have the FIN bit set need to specify a payload of at least X bytes
(where I would vote for X to be 125, but could conceivably be as small
as 8 or so bytes). Any non-FIN frames smaller than X could then simply
be declined with a 1002 protocol error. A nice side effect of this
measure would be that special purpose websocket servers that serve an
API which never expects payloads of more than (X - 1) bytes, wouldn't
need to handle fragmentation at all (because the maximum expected
valid payload size would be reached before any continuation frame
arrives or is parsed).

Of course, all of this depends on the presence/absence of valid use
cases for non-final frames with tiny payloads. I can't think of any
(which is why I'm writing this email), so please inform of such cases
if they do exist. If so, would they smaller than 125 bytes? How small
do they need to be, and why?

Hoping to get some constructive feedback, if only to inform myself
better. Also, sorry if this has been brought up before (but a few
cursory Google search made me none the wiser).

Regards,
Will

---

From: Takeshi Yoshino <[email-masked]>
Date: Thu, 20 Jun 2013 16:27:48 +0900

> over-fragmented messages the server needs to process an excessive (or

Guard against this kind of attack could be done by frame/sec limit,
fragments/message limit, idle (no new payload octet coming) timeout, etc.

> top of the websocket layer.

With this change, we can delegate DoS detection to code after defragment. I
agree that it's useful. For keep-alive we already have ping/pong, so nobody
should miss empty (non-first && non-last) frames.

> have the FIN bit set need to specify a payload of at least X bytes

I'd relax it to "!FIN && !first".

> as 8 or so bytes). Any non-FIN frames smaller than X could then simply

If we were still standardizing per-frame mux, I'd say "this could be source
of head of line blocking when used for multiplexing. Though 125 sounds
small enough not to clog multiplexed connection, I don't want X to be
greater than 1".

But now in the latest mux spec, we're encapsulating fragments into
messages. So, it's fine wrt current mux spec.

> do they need to be, and why?

Personally, I think fragmentation should be completely transparent to
semantics of messages. And, nowadays, there shouldn't be any device that
cannot afford 125B/connection buffer while paying extra network overhead
for small fragments. So, I don't come up with any real/concrete concern for
now.

> cursory Google search made me none the wiser).

IIRC, no.

I don't want to get bothered by minimum transmission unit when flushing
data, but in practice, we're always asked to consolidate small chunks if
possible to reduce overhead, and we do so.

Sorry for rambling response.
Thanks

---

From: William Budd <[email-masked]>
Date: Thu, 20 Jun 2013 20:12:48 +0900

> fragments/message limit, idle (no new payload octet coming) timeout, etc.

Yes, careful timing can certainly catch a lot of unreasonable traffic
(albeit at the cost of a significant processing overhead in some
cases). I'm not sure what you mean by a fragments/message limit
though. If a server decides to drop fragments beyond a certain
fragment count, isn't that a violation of RFC 6455 (as the reason for
declining would be based on the framing rather than on the contents of
the payload)?

> should miss empty (non-first && non-last) frames.

Glad to hear that!

> I'd relax it to "!FIN && !first".

Alright, but could you give an example of when it would be desirable
to make the first frame of a fragmented message (very) small?

> of head of line blocking when used for multiplexing. Though 125 sounds small
> enough not to clog multiplexed connection, I don't want X to be greater than
> 1".
>
> But now in the latest mux spec, we're encapsulating fragments into messages.
> So, it's fine wrt current mux spec.

A fortunate coincidence. :)

> possible to reduce overhead, and we do so.

Agreed. Thank you for your thoughtful input!

It would be good if other people chimed in with their opinions too,
but if it turns out there are no significant drawbacks I hope said
minimum size can be ratified in the next version of the websocket
protocol.

Best,
Will

---

From: Tobias Oberstein <[email-masked]>
Date: Thu, 20 Jun 2013 07:11:27 -0700

> However, I think the spec should also make provisions against over-
> fragmentation. Unless I overlooked something, RFC allows any message to be
> split into an infinite amount of fragments with payloads of 0 bytes (or if I'm
> wrong about that, it still allows a message to be fragmented in a nutty number
> of fragments with 1 byte); and endpoints need to handle that in order to comply
> with RFC 6455.

Not only endpoints, but also any intermediary..

> This is particularly annoying when a websocket server wants to guard against
> denial of service attacks, because in the case of deliberately over-fragmented
> messages the server needs to process an excessive (or

If you want to protect against DoS, there a multiple scenarios not explicitly discussed or specified in the RFC.

E.g. opening handshake timeouts, maximum frame size or excessive numbers of ping requests.

I think the decision what's acceptable depends on the concrete situation and application, and can be left open to implementations providing knobs for users to adjust.

So you can have a knob "minimal frame size for non-final frames" and fail the connection with a custom close code upon exceeding the limit.

Having fixed (non-negotiated) and implicit (non-modifyable) limits for specific parameters seems less desirable from my perspective.

/Tobias

---

From: Peter Thorson <[email-masked]>
Date: Thu, 20 Jun 2013 10:15:38 -0500

> Having fixed (non-negotiated) and implicit (non-modifyable) limits for specific parameters seems less desirable from my perspective.

I would argue that a WebSocket server that dropped connections attempting to send excessive numbers of fragments (for some application defined value of excessive) or fragments that were too small (for some application defined value of small) with a private code or code 1008/Policy Violation would be compliant with RFC6455 without any modifications.

With respect to protections against excessive resource usage in general I agree that it doesn't make sense to explicitly specify every limit in an RFC. There are too many potential limits and the appropriate values depend too much on what the application's needs are and will change over time. Application specific tuning parameters seem like a good way to address this. Perhaps the security section of any errata or future RFCs can include a list of parameters that other applications have found useful to tune from a security and interoperability standpoint?

---

From: Tobias Oberstein <[email-masked]>
Date: Thu, 20 Jun 2013 08:26:29 -0700

> I would argue that a WebSocket server that dropped connections attempting to
> send excessive numbers of fragments (for some application defined value of
> excessive) or fragments that were too small (for some application defined
> value of small) with a private code or code 1008/Policy Violation would be
> compliant with RFC6455 without any modifications.

Ah, right. Forgot about 1008. I agree: no real need for inventing an app specific code.

> With respect to protections against excessive resource usage in general I agree
> that it doesn't make sense to explicitly specify every limit in an RFC. There are
> too many potential limits and the appropriate values depend too much on what
> the application's needs are and will change over time. Application specific
> tuning parameters seem like a good way to address this. Perhaps the security
> section of any errata or future RFCs can include a list of parameters that other
> applications have found useful to tune from a security and interoperability
> standpoint?

That would be quite useful!

E.g. me I forgot about "attack vector" tiny fragment sizes (or max. frame count or something) as William has brought up.

A systematic list of potential "DoS protection knobs" in the security section: +1

/Tobias

---

From: Zhong Yu <[email-masked]>
Date: Thu, 20 Jun 2013 10:28:15 -0500

Not all websocket applications treat messages as atoms. If
client/server are doing streaming (within a message), we need to
support tiny frames. The requirement of min payload length will
restrict how the protocol can be used.

Empty frames are odd, and a sender should never depend on empty frames
to carry any semantics. But why would empty frames cause any trouble
for the receiver? Can't the receiver simply discard them?

Zhong Yu

On Thu, Jun 20, 2013 at 6:12 AM, William Budd <[email-masked]> wrote:
> _______________________________________________
> hybi mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/hybi

---

From: Joakim Erdfelt <[email-masked]>
Date: Thu, 20 Jun 2013 09:06:34 -0700

What about a new fragment extension that can communicate these limits?

Something like this...

On client handshake it can say
  fragment; min=125; max=65535
which would tell the server that messages should be fragmented, within
these limits.

alternative behavior would be for the Client to state that it supports
fragment rules by simply saying
  fragment
and the server responding with the rules it expects
  fragment; min=0; max=1234567

thoughts?

--
Joakim Erdfelt <[email-masked]>
webtide.com <http://www.webtide.com/>
Developer advice, services and support
from the Jetty & CometD experts
eclipse.org/jetty - cometd.org

On Thu, Jun 20, 2013 at 8:15 AM, Peter Thorson <[email-masked]>wrote:

> against
> > If you want to protect against DoS, there a multiple scenarios not
> explicitly discussed or specified in the RFC.
> >
> > I think the decision what's acceptable depends on the concrete situation
> and application, and can be left open to implementations providing knobs
> for users to adjust.
> >
> > So you can have a knob "minimal frame size for non-final frames" and
> fail the connection with a custom close code upon exceeding the limit.
> >
> > Having fixed (non-negotiated) and implicit (non-modifyable) limits for
> specific parameters seems less desirable from my perspective.
> >
> > /Tobias
>
>
> I would argue that a WebSocket server that dropped connections attempting
> to send excessive numbers of fragments (for some application defined value
> of excessive) or fragments that were too small (for some application
> defined value of small) with a private code or code 1008/Policy Violation
> would be compliant with RFC6455 without any modifications.
>
> With respect to protections against excessive resource usage in general I
> agree that it doesn't make sense to explicitly specify every limit in an
> RFC. There are too many potential limits and the appropriate values depend
> too much on what the application's needs are and will change over time.
> Application specific tuning parameters seem like a good way to address
> this. Perhaps the security section of any errata or future RFCs can include
> a list of parameters that other applications have found useful to tune from
> a security and interoperability standpoint?

---

From: Joakim Erdfelt <[email-masked]>
Date: Thu, 20 Jun 2013 09:10:14 -0700

an empty frame within the context of a streaming message is possible.

if you have a websocket library that supports streaming of a message, it
has to make some judgement calls on when to flush the outgoing data in the
form of a fragment.
The library however has no prior knowledge of the size of the message, so
the flush could occur, then the user application determines it is done
streaming data and simply closes that message stream, resulting in a need
for a final 0 payload length FIN frame.

On Thu, Jun 20, 2013 at 8:28 AM, Zhong Yu <[email-masked]> wrote:

> small