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:
- I need a login mechanism that doesn’t expose the user’s password, and
- I’d like to secure chat/IM messages to protect users’ privacy, and
- 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.