Be careful when using websockets!

I was playing skribbl.io with a couple of my friends the other day, and I decided to download this Chrome extension called AutoDraw for skribbl.io. Basically, what it would do is you drag and drop in an image, and then it would automatically draw your super awesome image onto skribbl.io. I was having a lot of fun playing around with this extension, so I decided to check out what was going on under the hood. 

It turns out that skribbl.io actually opens up a websocket connection from your browser to their server (mine was probably located somewhere probably in France (the IP belonged to OVH and the ping was 18ms from both London and Amsterdam) and it was sending my mouse movements every 50ms to the server in 195 byte messages. For those keeping count at home, this is around 0.0312 Mbps that I have to pay. Now, my friends in the game were also receiving these 0.0312 Mbps from the server to their browsers, free of charge. 

If we had max-ed out the room to the size limit of 12 players (which unfortunately we didn't do because we are bad at coordinating these fun activities 😢), we would have been able to use 0.0312 Mbps to force skribbl.io to expend 0.3432 Mbps sending my mouse movements to all my friends, which is a bandwidth amplification factor of 11! This obviously is pretty tiny and probably won't be putting skribbl.io at any risk, but maybe this should bring to our attention a problem that is prevalent in a lot of applications that use websockets?

When we build websocket applications like skribbl.io where we need to take events emitted from one client and broadcast them to other subscribing clients, are we creating a system that is inversely supported by economics, as Dr. Fielding once said? At the end of the day, skribbl.io feels like an application that follows the event-based integration (EBI) architectural style. EBI scales nicely when there are many more event sources than recipients of event notifications, say, if there were many drawers and few guessers in skribbl.io. But then when there are few event sources and many event notification recipients, EBI scales much worse and opens up for denial of service attacks. Maybe this is why skribbl.io limits rooms to 12 players? If they allowed for, say, 100 players in one room, they'd have to expend bandwidth that is 100 times my bandwidth just to broadcast my drawing to all the other players, which might allow them to be DDoS'ed by a malicious coder opening a bunch of private rooms, with the drawer being a real open websocket constantly transmitting mouse movements at max bandwidth, and the other players being just a bunch of websocket connections leading to places with low or no download bandwidth...

While this might be a bit controversial, I think a solution to this could be to implement some form of polling in websockets. Perhaps to receive your 195 byte message containing the drawer's mouse movements, you must burn 195 bytes? You could also create some sort of system where if you begin by pre-burning, say, 195×10 bytes, and then you would earn enough "credit" to receive the next 10 messages. And as you receive these messages, you burn more bytes to replenish more tokens to receive future messages. This would achieve the goal of preventing a DDoS attack of the form described above by balancing the server's bandwidth obligations with the client's bandwidth obligations. But then, it might also defeat one of the purposes of websockets in the first place: to reduce wasted overhead. But maybe this trade-off is worth it for the security?

Comments

Popular posts from this blog

First-Principles Derivation of A Bank

A Play-by-play of the Mirai botnet source code - Part 1 (scanner.c)

You can control individual packets using WinDivert!