Multiplayer game logins, SSL/TLS, & Spidermonkey

Hi fellow monkeys,

I’m facing some important security-related design issues on a jME project I’m working on and I’d like some input from you all. The project is an MMO-style platform - users create an account, login, and play. Assets are downloaded to the client on demand rather than bundled with it, but should only stream to logged in users (to avoid content rippers). Users will be able to chat with other players via both public chat channels and private messages.

Here are the design issues I’m having:

  1. I need a login mechanism that doesn’t expose the user’s password, and
  2. I’d like to secure chat/IM messages to protect users’ privacy, and
  3. I’d like to prevent (as much as is reasonable) man-in-the-middle tampering attacks.

As far as issue #1 goes, at the moment I have a rather standard (albeit vulnerable) system: the user’s password is hashed on the server, and at login time the client hashes the password, mixes it with a salt, hashes the result (to prevent replay attacks & recovery of the unobfuscated password hash, which could be attacked with lookup tables), and sends the final hash + salt to the server. The server performs the same operation and verifies that the final hashes match. Hashing is currently done with SHA256.

The weakness with this scheme is that the user’s password is transmitted in hashed form in plaintext. A motivated attacker could record the hash and (given enough time) recover the original password.

At one point I devised a more sophisticated scheme that relied on encrypting one-time “keys” to verify the authenticity of the client, but I was informed by a professional cryptographer that this scheme had several vulnerabilities and that I’d be far better off relying on TLS than attempting my own login protocols without it.

However, (a) SSL adds network + CPU overhead, and (b) the bulk of transmissions wouldn’t need to be encrypted for privacy reasons (only logins, private messages, and perhaps a small handful of other things). I already use both a TCP channel and (soon) will be using a UDP channel in addition. I don’t want to have to maintain an SSL connection to a client on top of that too. To get around this I’ve toyed with the idea of performing the login via HTTPS and sending the client a one-time key (and possibly a symmetric encryption key to encrypt sensitive messages) to establish an authenticated TCP connection in Spidermonkey, but a man-in-the-middle attack could potentially hijack the key in flight and use it to log in. I’ve also toyed with the idea of using some sort of JWT (JSON Web Tokens) scheme, but these need to be used over SSL or they can be replayed.

So at this point I’m not sure what to do. I’m not keen on running all TCP traffic over an SSL connection (since most of it probably doesn’t need to be encrypted), but unencrypted traffic can be tampered with relatively easily. I don’t know how much of this is legitimate concern, what’s “good enough,” and what’s just paranoia on my part. Any thoughts or advice would be greatly appreciated.

For number one, you hash the password and send the hash and compare it. Do it as early as possible and only ever.store the hash. Comparison is verification. I recommend oauth2.

The rest should fall in to place.

Do all login and account management through HTTPS using proper and vetted web protocols.

Securely trade tokens. Use the token for actual SpiderMonkey login.

For chats, if you really want to encrypt them, trade something over the HTTPS connection that lets you encrypt the content over the wire.

Anything else is a lot of extra effort for little gain. Especially since there is a 99% chance you will want some web UI for managing accounts anyway.

3 Likes

Thanks for the quick responses.

@jayfella, I’m looking into OAuth2 provider implementations for Java. (I’m not keen to add yet another separate server into the mix - the architecture already has enough going on.) Worst comes to worst I’ll fall back to a plain POST over HTTPS + JWT for login.

@pspeed, I’ve designed all game protocols that operate over TCP under the assumption that TCP latency will always be unacceptably high for anything time-sensitive (I realize this is an exaggeration under good network conditions, but I’d rather assume the worst case during design and get better performance under normal conditions in practice). My concern is that pretty much all traffic over unencrypted TCP can be man-in-the-middle snooped or spoofed. For 99% of games that probably doesn’t matter, but I’d rather not knowingly leave gaping holes in the protocol. As soon as there’s real-world value involved someone could do all sorts of nasty things if they can spoof messages at the transport layer (transfer inventory/in-game currency, spoof chats, get other players banned, etc.). Am I just paranoid? At the moment this is all purely hypothetical, but I’d much rather address this now than frantically try to hack on a half-baked patch later after a breach has already been made.

As I recall, Spidermonkey has compressed message types so I’m going to trot off and look at the sources and see if I can’t base a sensible encrypted message scheme off of those.

P.S. - Yes, eventually I definitely do want a web UI for accounts (and likely other things too). I’m leaning in favor of JWT at this point, possibly using an OAuth provider to issue them.

Yeah, I was going to suggest OAuth but wasn’t sure you were keen on bringing in outside services… but it’s definitely high on the list of “things to use”… and why a web solution for all account related stuff is best.

As to the other, I guess just encrypt the messages you are particularly worried about… the chat could have personal info in it so I could see that.

As to the other, the server is ultimately handling all game transactions and maybe it’s a little paranoid to think someone would happen to man-in-the-middle the TCP connection right from the start just so they could wait for you to be in the right place/position/state to transfer inventory or whatever. But I guess it could happen.

For game state, I’d definitely use UDP, though. Something like Sim-ethereal will be very fast in comparison.

The problem with TCP is that one slow packet will potentially block the whole stream for several seconds… and then all the messages come in as a flood.

TCP can be good for client->server stable communications (like chat, other commands) but given that I have access to Sim-ethereal now, I’m not sure I’d ever use TCP for game state → client synching anymore.

I’m not keen to bring in outside services, but if it provides enough benefit to justify the extra administrative burden I’ll do it. A simple HTTPS servlet + JWT might suffice for my needs (I already have Jetty embedded in my server) - I’m not super familiar with OAuth so I’m reading up on it now.

I’d love to use SimEthereal, but unless I’m missing something it has a couple limitations that I’m not sure I can work around. The first I brought up a few months ago in this post: Multiple SimEthereal spaces on one host. The second issue I have is that I’d like to be able to time-sync more than just object position/rotation - entities have very flexible attributes (components in ECS-speak) that aren’t all necessarily meaningful to the core server. Ideally any attribute could be interpolated/lag compensated. Sooner or later somebody’s going to think of something I didn’t. Additionally, I have my own internal types for representing position/etc. that closely fit with a custom serialization library I wrote for DB persistence. I have a draft protocol (highly based off of SimEthereal) planned that would make use of this serialization library and allow SimEthereal-style syncing of any attribute type.

If it were just the first issue I’d fork SimEthereal and offer any changes I’d made back as a PR, but with the second issue I don’t see how I can reconcile this design with SimEthereal at all.

Just a note that it seems strange that a custom serialization library would be a constraint on the data types used. (For example, Zay-ES’s SQL support automatically handles Vector3f and Vec3d without any custom code.)

You obviously have a lot of time invested in your approach and so going your own way is probably preferable… but that design constraint seemed really odd to me. Like having the cart lead the horse around.

The serialization library isn’t the “real” constraint. It’s not reflection based (each serializable type has to have a serializer/deserializer registered specifically for it), but this is due to a design choice I made a while back. As I mentioned in my initial posts, assets are downloaded at runtime rather than packaged with the client. I wanted a simple, clean way to make sure that once an asset is uploaded it will always be readable by the client with no special dependencies or reliance on other libraries (it must be future-proof). (This breaks down a little with things like images/audio - hard to efficiently handle those without touching compressed image/audio formats, but if I need to change core formats like these later I can do so.) To accomplish this I designed a custom binary format (and a corresponding serialization library). Each asset blob starts with a magic number, a format version number, and then a text string describing the type of the contents to follow. The type tag was inspired by MIME types and serves exactly the same purpose - anyone reading one of these assets knows the type of the data following. A serializer/deserializer pair are mapped to a Java class corresponding to that type, and any time someone deserializes an asset blob they get an instance of that class. Since the type tags are decoupled from the classes, you can freely change the class types used without worrying about binary compatibility - just make sure your serializer/deserializer for the new class read/write the same format as before. I realized after I wrote this system that I could also use it to serialize entity attributes for persistence and network transmission too (although for network use there will be the option to pre-negotiate attribute types so you don’t have to send type tags with every update). The advantage is that I get a fast and compact format that I can easily serialize anything I want to, the disadvantage is that libraries like SimEthereal where the wire format is pre-initialized for specific bit widths don’t play nicely with it.

Why not use 3rd party programs and protocols for chat? Jabber based protocols with super awesome and hard to implement security features are a dime a dozen. No need to do your own. It is very hard to get the details correct so good chance anything you roll on your own will be barely better than plain txt anyway. Also its a video game. What is in fact wrong with plain txt? Remember the golden rule of security. Authentication is more important than obfuscation.

Also TCP is NOT Slow. Why does this myth persist?

This is a MMO-type platform, so it’s important that common features like chat are handled internally (especially so since scriptable objects will be able to chat directly with users). If someone doesn’t like the internal functionality there’s nothing hindering them from using an external program. As to plain text, I don’t intend to support anything beyond it (especially in v1.0). :wink:

In this case it’s not that TCP is slow, but that under poor conditions TCP (by nature) must introduce latency to follow through on its guarantee of ordered data. In cases such as syncing physical objects, the latency added by TCP when the network isn’t behaving well can cause unacceptable lag. Plus, it’s likely that by the time TCP catches up with the packets the object has already moved again and you don’t even care about the first packets - so the time TCP sent re-sending them is totally wasted because in effect you want to throw them away anyway.

For quasi-realtime data, the fact that UDP can drop packets and keep later packets flowing is a feature, not a flaw. My protocol is designed to capitalize on both - UDP when volatile quasi-realtime data is being sent, TCP when I really, really want the data to get to the other side and don’t care if a dropped packet stalls it along the way.

Most modern MMOs are moving AWAY from internal chat and using 3rd party chat. Sure the interface is handled in the client. But not the backend. For game links they use URIs.

I know how TCP works. THIS DOES NOT MAKE IT SLOW. In fact it is why you often get lower latency and higher throughput in many real world (read not 1990 anymore) situations because switches etc can do things like header compression. Even more to the point, modern networks just don’t reorder anymore. Unless your doing your own 10G+ or custom wireless link (like 20+km) there is no need to reinvent the wheel. And trust me. You will do it badly like 95% of the games out there. (the rest is quake/unreal FPS style protocol or use TCP)

You either need reliable delivery or you don’t. If you don’t then sure UDP may me ok. But TCP will still probably be a better choice as UDP packets are what your ISP will drop first. Then you add your own reliability layer right.? Oh wait, what about flow control, congestion collapse and the 2 generals problem? don’t know what they are? Then JUST USE TCP. I mean an entire planet worth of engineers and scientist do actually know what they are doing. 99% of the time TCP is the right choice and UDP is wrong. Add security into the mix, then even more so.

I know you know how TCP works. :wink: I just included that bit so you could see my thought process behind why I’m messing with UDP at all.

I 100% agree with you. My only reason for adding UDP into the mix is for quasi-realtime object sync, which I intend to base as closely as possible on SimEthereal’s design. I have no intention of attempting to duplicate TCP functionality. :wink:

On a 100gig fiber network we could not use TCP to sync camera movements on three machines sitting on the same switch… because occasionally one or the other machine would pause for 2-3 seconds. Then it would really quickly play back that now old useless 2-3 seconds worth of data (180 position updates we didn’t care about).

Other than that, yeah it was plenty fast. Latency on the LAN was only 20 ms or so.

…of course, UDP latency in that case was <1 ms… ie: effectively 0.

And granted this was around 2004 or so. (Though the publicly released Mythruna currently suffers from the exact same issues in modern times over the WAN. It’s only playable at all because at most two objects per player need synching in that version.)

Anyway, SimEthereal already implements a semi-reliable protocol over UDP. It should not be affected by the two generals problem because we aren’t coordinating two homogeneous generals but two very asymmetric endpoints. One constantly sending updates about their own commands and the other constantly sending updates about the whole world.

Put another way, the two generals problem is very solvable if you consider the other general dead and unimportant after he doesn’t report in for a while… when you’re expecting frequent reports.

Real time client server games are not a general (the lower case ‘g’ word) problem. Communication is constant in both directions, time is always moving forward, and old data is unimportant. This makes it different than trying to solve the general bidirectional communication problem… which if you try to implement using UDP then you end up with a badly implemented TCP.

TCP is quite good at what it does. It’s just not good about handling a single dropped packet in a timely fashion.

2 Likes

Take a look at scribejava
You can let your clients sign in with their Google, Yahoo, Twitter , … accounts

For chat I prefer to use a free 3rd party software

3 Likes

Another option which requires some work (mostly for the handshake part) but frees you from dependencies:
You can use Java’s builtin SSLEngine to handle the TLS stream yourself and channel its output through an already existing stream (Spidermonkey messages, TCP or reliable, ordered UDP).

@Ali_RS I’m leery of using an entirely separate login like that. I suppose there’s nothing to stop me from storing user identities for things like bans though, but in general I like to remain as uncoupled from other web services as possible unless there’s a good reason to rely on them. I’ll definitely take a look at scribejava though - something like that is bound to come in handy sooner or later.

@1000ml, thanks for the lead there! I’ve never had occasion to use raw SSL/TLS before, so I didn’t realize that Java had a standard mechanism to decouple the SSL/TLS protocol from the network transport. That’s sure to come in handy one of these days.

You should note that i did put a 10G+ in there as an exception. TCP window size starts to cause issues at that speed. But if your doing stuff at that end you should be properly informed about networking. Indeed you probably should consider working at a different layer often (how ppl i know deal with it).

However most men/woman and their dog that are going to write a game “with best fastest internet ever” have no idea what they are talking about. They don’t even know what window size for TCP is!

Also these days you just don’t get dropped packets. You just don’t. Even lowly Ethernet now uses full forward error correction etc. You either get most packets dropped or none. The all case is typically because some idiot uses their own custom UDP without flow control and just congestion collapse everything.

Fact 99.9% of the time ppls “reliable” UDP isn’t and has no flow control and is slower and crappier in the presence of actual packet loss than TCP.

99.9% of the time. TCP is the correct choice. And until you can prove that it is specifically something about TCP that is breaking something (bet you it isn’t) don’t consider UDP. There is no easy short cuts to actual packet loss (don’t forget most hardware layers already do resend!).

Now with resends etc add security requirements to the mix. Yea right.

Yes, I’m not an idiot.

You said packet loss isn’t a thing. I strongly disagreed and said it is… even on high speed fiber networks where packets should never get lost. They just do. We ran that same application over wi-fi, over 10baseT, over gig-e… until we switched to UDP we would occasionally see these “pause for 2 seconds then replay two seconds worth of data”. It’s just the nature of TCP. The window gets trashed it has to go back and reload the whole window.

I’m glad it never happens for you. I’m also glad you have no problem throwing rocks at a library you’ve obviously never even looked at. That means I don’t really have to continue this argument. You apparently know “everything”… so there is no point.

I just wish I lived in your world because things would be a lot easier.

1 Like

There are some very nice articles about networking and games. and he explains what @pspeed observed experimentally. so yes I believe @pspeed is right, tcp was made for a different purpose than game pos syncing. if tcp starts to loose a pkg it can not deliver the already received stuff but has wait for that - for game completely uninteresting - pkg which is already in the past. and I think this is still valid even in 2018.

Holy shit dude. That wasn’t directed at you. As in right at the start. i mentioned exceptions and pointed out the high speed one! And yes i have looked and used spider monkey. No offense was meant. It was directed at the general population who are going to “roll their own and it will be better”.