web-udp-public
web-udp-public copied to clipboard
UDP as a WebSocket extension
Here's my proposal for a WebSocket extension that would expose UDP securely to web pages:
During the initial WebSocket handshaking, the client signals support with the header Sec-WebSocket-Extensions: udp. The server replies back with the port that the client can use for UDP: either Sec-WebSocket-Extensions: udp (port 80 or 443, depending on whether it's ws or wss) or Sec-WebSocket-Extensions: udp=1234. Note that the host for the connection would be the same as the http request host.
For web developers, the WebSocket object would have a sendUnreliable method to send a datagram to that UDP port, and once the first datagram is sent, the server then knows where to send UDP packets to (and that the client supports UDP; initial packet has to come from client because of NAT). The WebSocket object would also have "udp" added to its extensions property, so the client knows that the server supports UDP. Sessions would be handled entirely by the developer and don't really need to be dealt with in the protocol.
Now, some issues:
-
SSL: It makes sense to not wrap datagrams using DTLS, since the entire purpose of using UDP is to minimize CPU and latency costs. While a possible solution is using DTLS for secure websockets (and not using it for insecure websockets), this causes problems with the fact that https origins can only use secure websockets, and game developers would force their users to only use http (basically all browser MMOs out there already redirect https to http because of this). My proposal is always using insecure datagrams, since anything supposed to be secure can just go over TCP.
-
Raw datagrams: Raw datagrams have a few issues, possibly the biggest ones are IP fragmentation and flow control. Should raw datagrams be exposed, those would be pushed onto developers to deal with, I don't really see the problem with that, as I don't think this should be solved at the protocol layer. My proposal is to just send raw datagrams after the initial handshake is made.
If there aren't major objections to this approach, it is possible to write a browser extension that exposes this interface, and this would get the ball moving faster for browser developers to take a look at the proposal.
After WebSockets HTTP 101 handshake, the underlying implementation of extension can require UDP (or alternative) transport to perform second handshake. If underlying protocol is not connection based then some extra header information has to be implemented by an extension to prevent messages to be sent/received from other sessions or even different endpoints.
This will also release a need from application to make initial message to deal with NAT as it will be dealt by second handshake.
Regarding congestion control, this might be too much of a security concern for a web community and will unlikely allow such API to be implemented.
Regarding SSL, if developers already use non-SSL for avoiding CPU cost associated with encryption, then DTLS is not a problem as it will leave a choice to developer while preserving security requirements for the web. Additionally HTTP + HTTPS approach can be used, where main page served over HTTP and some other traffic served over SSL. It won't work otherwise due to security practices around the web.
Regarding congestion control, this might be too much of a security concern for a web community and will unlikely allow such API to be implemented.
Could you elaborate this point? You mean raw UDP is too much of a security concern because people could DDoS using it? My proposal wouldn't allow sending UDP packets to a server until it signals it wants to receive them.
Regarding SSL, if developers already use non-SSL for avoiding CPU cost associated with encryption, then DTLS is not a problem as it will leave a choice to developer while preserving security requirements for the web.
Avoiding HTTPS because of CPU costs isn't really that bad. I think it's a separate issue from avoiding DTLS for those UDP packets.
Additionally HTTP + HTTPS approach can be used, where main page served over HTTP and some other traffic served over SSL. It won't work otherwise due to security practices around the web.
You can't create insecure websockets in a secure context (https). Since we want the web to advance towards HTTPS everywhere this would mean forcing DTLS (which I don't think that is desirable). Always using insecure datagrams and letting developers use the normal websocket connection for secure communications would be a good compromise IMO.
Could you elaborate this point? You mean raw UDP is too much of a security concern because people could DDoS using it? My proposal wouldn't allow sending UDP packets to a server until it signals it wants to receive them.
Congestion control is required by underlying transport protocol to avoid one side to overwhelm with traffic another side as it can be unable to process messages fast enough. This leads to network congestion issues which lead to more packet losses and increased latency. Most popular case is when someone is playing a game and neighbours on same network start streaming some videos and downloading stuff. Quality of a players connection will start to suffer due to local network congestion issues.
If a protocol does not implement congestion algorithms then it is easy to halt the network on server or client by spamming it non-stop with either large messages or many small ones. Other connected clients will suffer from that too.
You can't create insecure websockets in a secure context (https). Since we want the web to advance towards HTTPS everywhere this would mean forcing DTLS (which I don't think that is desirable). Always using insecure datagrams and letting developers use the normal websocket connection for secure communications would be a good compromise IMO.
But you can create connections other way, from non-SSL to SSL. Means you can have some of application logic to be performed on SSL connections and some on non-SSL. Main page have to be served on non SSL connection though. And cross-domain issues has to be handled too, as https and http on same hostname are considered as cross-domain.
IMO congestion control should be in the application layer in this case, since that's how UDP already works. The worst this proposal exposes is equivalent to what you can already do (with xhr, img tags, etc.): exhaust all the user's bandwidth.
But you can create connections other way, from non-SSL to SSL.
But we're moving towards HTTPS everywhere. You won't be able to have a non-HTTPS page eventually, and proposals made today need to have that in mind.
@Matheus28 Agreed on the congestion control at the application layer. Also, packet fragmentation and reassembly at the application layer + reliability done there too. Just the minimal required at the low-level that gets the connection-based and encrypted UDP without DTLS/SSL overhead is all we need.
ps. there is now a browser implementation for netcode.io that should provide what you need: https://github.com/RedpointGames/netcode.io-browser
@gafferongames
I've seen netcode.io in the past, but with all due respect, it's a just not a good solution (in my opinion). Those "connection tokens" have no place in protocol level.
Those "connection tokens" have no place in protocol level.
I'm going to have to disagree with you, because this is exactly how it's done in the AAA space.
SSL: It makes sense to not wrap datagrams using DTLS, since the entire purpose of using UDP is to minimize CPU and latency costs. While a possible solution is using DTLS for secure websockets (and not using it for insecure websockets), this causes problems with the fact that https origins can only use secure websockets, and game developers would force their users to only use http (basically all browser MMOs out there already redirect https to http because of this). My proposal is always using insecure datagrams, since anything supposed to be secure can just go over TCP.
You are proposing sending game protocol over unencrypted UDP, because anything secure can just go over TCP? This is madness...
@Matheus28 You really do need the token + basic encryption. Otherwise spoof + replay attacks are pretty trivial.
And DDoS amplification attacks...
I have to disagree, because this is exactly how we solve this problem in the AAA space.
What are you referring to? Connection tokens? That should be application level.
You are proposing sending game protocol over unencrypted UDP, because anything secure can just go over TCP? This is madness.
So you use encrypted UDP for real time stuff on AAA games? I've worked with a few third-party engines and none of them did that. Not to mention my own networking engines. There's no reason to. The only stuff that go over UDP is the data to replicate the entity system. If you want secure UDP, that can go on user code, not part of the protocol.
@Matheus28 You really do need the token + basic encryption. Otherwise spoof + replay attacks are pretty trivial.
That can go on the application layer. Server gives client a token to sign his requests and identify them over TCP, and client uses that. That's not supposed to be on the protocol layer.
And DDoS amplification attacks...
Now you gotta be kidding me. I spent the last few minutes writing these replies and you come up with this? You're better than this. There's no UDP communication before a TCP handshake. You (and @vvanders) took my opinion on your netcode.io solution as a personal attack, and you're trying to pull any reason to criticize this proposal. I don't think you even read it thoroughly at this point.
@Matheus28 No need to get personal here.
Yes, all of that could go into the application layer. However one of the core principals of the web is security and I think it makes sense to have that bundled in and painless to use.
Replay attacks/mitm are very much a thing. I've also never seen network protocol overhead even show up on a profile. If you're sending that much data you've toasted a user's network connection and on the server back-end you always have beefy servers or proper load balancing.
So you use encrypted UDP for real time stuff on AAA games? I've worked with a few third-party engines and none of them did that. Not to mention my own networking engines. There's no reason to. The only stuff that go over UDP is the data to replicate the entity system. If you want secure UDP, that can go on user code, not part of the protocol.
Yes. AAA multiplayer games always do this. You'd be crazy not to. Think of the MITM attacks...
Replay attacks/mitm are very much a thing.
True, but for most use cases that want UDP, they don't matter. If a malicious router is making the player walk into a wall instead of shooting at people in a game, how much damage is that really causing...? Most games don't transmit secure information over UDP.
I've also never seen network protocol overhead even show up on a profile. If you're sending that much data you've toasted a user's network connection and on the server back-end you always have beefy servers or proper load balancing.
Most of my games handle 100~1000 players in a single CPU core, in fact, most of the time is actually spent encoding and sending those messages (over TCP, of course).
Now you gotta be kidding me. I spent the last few minutes writing these replies and you come up with this? You're better than this. There's no UDP communication before a TCP handshake. You (and @vvanders) took my opinion on your netcode.io solution as a personal attack, and you're trying to pull any reason to criticize this proposal. I don't think you even read it thoroughly at this point.
I don't feel attacked. I just think you're wrong.
Yes. AAA multiplayer games always do this. You'd be crazy not to. Think of the MITM attacks...
Like preventing the player from doing an action or sending them erroneous entity states? I'll take the risk of that over imposing that overhead over all udp packets coming/going to the browser. Anything secure can go over TCP. And if you need secure real time data, you can include DTLS in the application code.
Also, as a personal example, last time I worked with Source Engine, there was no encryption. That's one I remember for sure.
Depends entirely on the game and how complex your protocol is. If it's dead simple, sure you could make an argument that encryption is unneccessary overhead. Fine. I disagree, but fine.
But you haven't addressed spoofed packet headers and DDoS amplification attacks. This is unfortunately real and quite serious. If a UDP packet from server to source packet IP address is larger than typical request or input packet, you expose your protocol to be used as part of a DDoS amplification attack.
You also haven't considered that dedicated servers for many games are quite expensive. You want to stop people from connecting to a server without having authentication to do so. This, along with the challenge/response to stop spoofed packet headers and DDoS amplification, is why AAA games do it the connect token way.
cheers
But you haven't addressed spoofed packet headers and DDoS amplification attacks. This is unfortunately real and quite serious. If a UDP packet from server to source packet IP address is larger than typical request or input packet, you expose your protocol to be used as part of a DDoS amplification attack.
You haven't read the proposal. Before any UDP packets are able to be sent, a handshake happens over TCP. You can only send UDP packets to the same host that you shake hands with. The browser also doesn't allow you to spoof the source IP.
You also haven't considered that dedicated servers for many games are quite expensive. You want to stop people from connecting to a server without having authentication to do so. This, along with the challenge/response to stop spoofed packet headers and DDoS amplification, is why AAA games do it this way.
That's application layer, not protocol. You're just running in circles here.
You haven't read the proposal. Before any UDP packets are able to be sent, a handshake happens over TCP. You can only send UDP packets to the same host that you shake hands with. The browser also doesn't allow you to spoof the source IP.
So I open up wireshark and find the IP address that UDP packets are being sent to. I note this, and later on I start sending UDP packets to that IP address and port to attack your protocol. You need to think this through Matheus...
You haven't read the proposal. Before any UDP packets are able to be sent, a handshake happens over TCP. You can only send UDP packets to the same host that you shake hands with. The browser also doesn't allow you to spoof the source IP.
I read the proposal and understand it fully. It's incredibly naive.
So I open up wireshark and find the IP address that UDP packets are being sent to. I note this, and later on I start sending UDP packets to that IP address and port to attack your protocol. You need to think this through Matheus...
Just like you can DDoS any other server? What is the issue here?
I read the proposal and understand it fully. It doesn't work.
You might have read it, but you clearly didn't understand it based the points you raised.
Just like you can DDoS any other server? What is the issue here?
You don't seem to understand how DDoS amplification attacks work.
That's application layer, not protocol. You're just running in circles here.
This is your opinion, and you've firmly stated it several times without any justification. Fine.
I still think you're wrong. It's not application layer. It's an essential security step to make it possible for UDP-like functionality to be secure enough to get included in a browser.
@Matheus28 Just because something is out there and widely used doesn't mean it's not vulnerable. Here's just one of many sources you can find about how the Source engine isn't the most secure(it's has it's upsides but I wouldn't list networking as one of them, yes I've shipped titles with it).
https://www.slideshare.net/z0mbiehunt3r/ddos-amplification-attacks-with-game-servers
You don't seem to understand how DDoS amplification attacks work.
You don't seem to understand how they work. Before we waste any more time: Are you saying this proposal enables web browsers to unwillingly participate in DDoS attacks, or are you saying that the proposal as it is allows the server to get DDoS'd more easily than any other server serving traffic over UDP?
You don't seem to understand how they work.
I'm sorry, are you five years old?
@Matheus28 Google "DDoS UDP packet amplification". I'll wait...
Where does it say in my proposal how the server replies to UDP requests? Tell me how the proposal facilitates those attacks in any way. No, really, give me an example.
Example: Somebody creates a game using your WebUDP proposal. Instead of inputs to server, and server sending snapshots of world down to a client at steady state (as you almost certainly do for agar.io), they build their protocol around request/response (this is pretty common pattern for MMOs and mobile games...). Bad guy connects to their server websockets-UDP whatever and find its IP address and port via wireshark, then takes advantage of a request packet that is smaller than the response from the server to launch a DDoS packet reflection attack, eg. spins up a bunch of processes in linux with raw sockets and spoofs UDP packet IP source header to the IP address to be attacked, and the WebUDP server responds with packets larger than request packets, eg. amplification.
It's that simple. Yes, this actually happens. By saying that this is application level, you're making it possible/likely that somebody fucks this up and this situation happens. Therefore, It should not be at application level. It should be taken care of by the protocol-level so this cannot happen.
Where does it say in my proposal how the server replies to UDP requests? Tell me how the proposal facilitates those attacks in any way.
That's the problem. It needs to be baked into the protocol that you only respond to the correct IP addresses. Otherwise its enabling an new generation of services which may be vulnerable as DDoS amplifiers to be deployed on the internet and the browser vendors won't support it.
Its the protocol that is the vulnerable thing; example common UDP protocols that are used as DDoS amplifiers: DNS, NTP, SNMPv2, NetBIOS, SSDP, CharGEN, QOTD, BitTorrent, Kad, Quake Network Protocol, Steam Protocol, RIPv1, Multicast DNS (mDNS), Portmap/RPC, LDAP, Network Time Protocol (NTP)