SpiderMonkey Security: TLS & Auth

Just read the SpiderMonkey docs, and noticed one important thing missing from them: security.

If I’m reading the docs correctly (and I may very well not be!), pretty much any jME3 client can connect to a server if it uses SpiderMonkey and connects to the correct port.

I’m wondering if there is a way to enable or implement two important security constructs on top of the default SpiderMonkey implementation:

  • TLS; that is, SSL over TCP (I assume SpiderMonkey “speaks” a plaintext/binary/unencrypted TCP serialization protocol) and I’d like to see if TLS can be baked in somehow; and
  • A custom authentication (identity management) and authorization (access management) model. Here, in the simplest case:
    • Perhaps the jME3 user provides a username + password when connecting to the server
    • On the server, before even allowing the connection, the username + password are authenticated and the user is assigned a set of roles/permisions (RBAC model)

Is this possible, and if so, what classes would need to be extended/implemented in order to provide these capabilities?

2 Likes

Hmmm, interesting concept that you bring up. I would think that SSL or any kind of data encryption of user transmitted data would result in poor performance of the game. I mean you would be decrypting/encrypting N amounts of packets for each user connected to the game server.

1 Like

You’d have to provide your own connector implementations and stuff. The system was architected that way but SSL was never implemented as a) it can be a pain for users to setup properly, b) it’s really slow, and c) often you want to integrate with some existing solution that is already using HTTPS.

No, it must also configure all of the same ports and have the same name and protocol value.

That’s usually enough unless the client is a malicious actor (hacked specifically to connect to your server)… and then the problem becomes a lot trickier. There really isn’t a complete solution in that case.

1 Like

Thanks both @themiddleman and @pspeed

I’ll need to sit back and think about SSL, but you’re absolutely right about the slowness (I come from the enterprise Java world where SSL is a must have, so it’s sort of ingrained into my train of thought).

But what about auth? If there was a way for the client to provide extra information (username/password, token, etc.) to the server, the server could then be extended to authenticate + authorize the client’s initial connection attempt. That just might be good enough for me to do without SSL and all the latency it would introduce.

I see that HostedConnection has a getAttribute(...) method, which makes me think there might be a way to set custom attributes from the client at connect-time. If that were the case, I might be able to implement authn/authz from inside the server’s ConnectionListener like so:

// Groovy pseudo-code
class ServerConnListener implements ConnectionListener {
    @Override
    void connectionAdded(Server server, HostedConnection conn) {
         // Perform authn and then subsequently authz
        Principal principal = findPrincipal(conn.getAttribute("username"), conn.getAttribute("password"))
        List<Role> roles = loadPrincipalRoles(principal)
        securityContext.register(principal, roles)
        // something like this, etc...
    }
}

The only “downside” to this approach is that we’re performing auth from inside the ConnectionListener, after we’ve already connected to the server. Might not be a big deal (or any deal at all) but I feel like ConnectionListener is meant to be invoked after a successful connection has been made. Whereas, from a security perspective, I’d prefer for the connection to fail if authentication fails.

However, in the Network class, which is what the SpiderMonkey docs recommend for generating Client instances, I’m not seeing any place where I can set these custom (username + password) attributes.

Any ideas as to how/where I could send a username + password alongside a connection attempt, and how/where I could be performing auth on the server-side? Thanks again!

1 Like

I don’t no anything about SpiderMonkey but couldn’t you implement something like that using a simple Message?
But then please don’t transmit the password as is but rather only a hash of it or even better use the password as IV or something to encrypt a “challenge” from the server. I guess a hash is enough though.

Then you set some flag or close the connection or wait until the client re-auths. This topic is pretty game specific though so there might not be a generic solution (e.g. some LAN games only need a name, or other games where you don’t store anything on the server, have no inventory, xp, …)

Edit: Forget about that challenge and response thing. If you use hashes you don’t even have to store the password on the server, less trouble for you.

1 Like

Thanks @Darkchaos - having an “app-layer, message-based” auth system is my fallback here. I’m just wondering if there’s a way to integrate auth as part of the SpiderMonkey connection, which would be preferable (its arguably easier and less orchestration/work to set up a single server-side auth mechanism than to have to coordinate back-and-forth handshake messages between client and server). But yes, that is my backup if nothing else/better will work!

1 Like

The attributes on hosted connection are attributes you set in your server code based on whatever logic on the server. It’s a convenient way to keep track of things from one message handling to another.

There is no built in authorization “to connect” (which is kind of a ridiculous notion since you’d need to connect to receive anything anyway). You must manage all of that yourself from one of the hundreds of ways to do it. Like, are you sending passwords in the clear? Are you hashing them? Hashing them with what? Are you sending random salt from the server to mix into the hash?

Many games will want to avoid doing their own account management. It implies some kind of home-rolled web service for submitting password reset requests, setting your account e-mail, whatever. I rolled my own for Mythruna and I was never happy about it. Every time a user forgot their password I had to manually reset it for them… or they just created a new account. So anyway, there’s a lot of “account infrastructure” you have to deal with in that case.

Alternately, you can use some third party service and have the client and server both communicate with that. For the new version of Mythruna, I piggy-backed on the wordpress accoutns I was already keeping for paid users. I still ended up doing local accounts for the server, though… but now there was much less burden on password resets and stuff.

Or maybe you want to integrate with Steam accounts. Or use OAUTH against Facebook accounts or Google accounts… or whatever.

There are a bunch of different approaches. SpiderMonkey did not pick one for you. It’s lower level than that.

2 Likes

Not sure if it helps but you can run SSL/TLS through any data channel you like. Just feed the cipher text into an SSLEngine and take the plaintext output (decrypt = unwrap) or vice versa (encrypt = wrap).
You just need to transport these bytes with SpiderMonkey and you’ll end up with an encrypted channel embedded in your protocol.

Also, encryption is not THAT costly. Once the asymmetric handshake is done, the data is encrypted symmetrically. You also don’t need to encrypt everything if you use this “embedded SSL channel” method. For example, I only use encryption for login and chat.

2 Likes

Thanks @1000ml

Just curious where that SSLEngine class comes from, what the “cipher text” would be considered to be (the AbstractMessage impl as serialized bytes, maybe?), and how I might wire my Client and Server instances to use SSLEngine. Thanks for any-and-all help here!

1 Like

You can find the SSLEngine here:

https://docs.oracle.com/javase/7/docs/api/javax/net/ssl/SSLEngine.html

There are two ways to use the SSLEngine.

On the one hand you could serialize the data by yourself in a byte array encode it with the SSLEngine into a new byte array. Send this array with Spidermonkey in a Message which contains only the array. When you have received the message you can decode it with the SSLEngine on the other site of the wire and deserialize the byte array to you game data. Beforehand you have to set up the engine with some custom messages. I think this is the way @1000ml talked about. You have one problem: You have to do the serialization yourself. That’s a shame because Spidermonkey does a great job at this task.

Your second opportunity is two write your own Connector which makes use of the default connector. This is closer to what pspeed was talking about in his first post. Then Spidermonkey serializes the data for you and you only have to encode it. This is great but you have to dig deep in the Spidermonkey API to get it done.

I just wonder for what kind of message do you need ssl? Super private chat messages? Please don’t use it for game data updates like positions and so on. Most of them are send over UDP because it’s faster and the order doesn’t matter.

1 Like

The auth method with the hash is not secure. If the hash is openly readable, an attacker can simply use the hash to login. It doesn’t matter if you send the plaintext password or the hash… (though it’s probably a bit better since it doesn’t reveal the password which you might be using for other sites too)
The challenge-response thing is vulnerable to man-in-the-middle attacks (should you care about them).

And please never store plaintext passwords - at least use hashed passwords with salts.

Exactly!
I don’t know how SpiderMonkey works, but this could simplify the serialization:
When an encrypted message (EncryptedMessage extends AbstractMessage) is received, it is processed by a special MessageListener for EncryptedMessage. It decrypts the cipher text and feeds the resulting plain text back into the protocol handler where it is processed like a normal message that comes from the socket.
Same goes for sent messages: LoginRequest extends EncryptedMessage
LoginRequest is serialized, encrypted and and the byte array then wrapped in an EncryptedMessage.

1 Like

Paul may I ask a question ?

I searched about SSO using OAuth2 protocol.
I am not sure how it works for desktop apps.

Using this protocol the Authentication is being done through an external web browser and HTTPS protocol, Yes ?

Do we need to manually transfer the access token from browser to our app ?

I have not looked at how wordpress authentication works yet.
Are you using the same method (sign in from an external browser) for your game log in ?

Sorry if my question is noob. :slight_smile:

1 Like

Disclaimer: I am not into OAUTH actually, but:
I don’t know if you need a web browser, you could call a REST API or something, maybe even using Java’s new URL() stuff…

The key here is that users can use already existing accounts and you just get the okay from Facebook, w/e.
This also reduces the number of passwords/accounts users need and all, however if you use exclusively steam sso, users need steam.

2 Likes

I will take a look at them.
Thanks so much for your help @Darkchaos .

1 Like

Probably some might even have a java library already ready!
OAUTH(2) has been defined so multiple SSOs don’t have a different implementation each, so I guess there might be general purpose OAUTH libraries which work for everything

2 Likes

Maybe this is what I am looking for ! :slight_smile:

1 Like

If you are using Swing or JavaFX, you can also open an embedded browser in your application to do oauth.

2 Likes

We usually use Jersey 2 when doing REST stuff and they have support for both OAuth1 and OAuth2. You can either use Jersey as a server or client.

It’s a bit black box magic going on there, but the code is quite clean.

https://jersey.java.net/documentation/latest/security.html

I think people in general are afraid of encryption and stuff and tell that it takes time etc. It does take some CPU and will slow you down a bit, but the most expensive part is the handshake. I’ve been able to do 18000 HTTPS req/s from my computer (Quad i7 Skylake) at home to a server at running Tomcat 8.5. I did use keep-alive and HTTP/2, but still you can do quite many requests per second with TLS.

However; you need to decide what data that is important to keep secret. Use PBKDF2 or another suited password algorithm, absolutely not MD5, SHA1 or another normal hashing method.

You can read more about it and get some example code Secure Salted Password Hashing - How to do it Properly

You can also add a little hash to your packets if you’re afraid that people might trry to tamper with the data. Just exchange a common shared secret (preferably over TLS) that you use for hashing your content. Use SecureRandom and get some random bytes that you exchange. Small packets are quite fast to hash.

My favourite example of people doing “optimisations” was a time ago, when I saw an API where they used MD5 (don’t use if for anything today, and I do mean anything, it has been cracked for years) to get a hash code of the request, and then use the check sum together with a salt in another SHA2 HMAC method that later would be confirmed by the server. They did that instead of just wrapping all the request in a single SHA2 HMAC hash to save CPU cycles. I actually did some testing and found out that they actually saved about 12 seconds per 1 million requests, that cost about 0.01 USD cent if you run it in Azure.

I don’t know what game you’re doing, and the importance of the data, but at least keep passwords safe; only store a hash.

2 Likes

Heh, chaining MD5 with SHA2 and HMAC to save cycles… clever, very clever.

I seem to recall a study by Google from several years ago that found that the encryption overhead added to HTTP by SSL was somewhere in the very, very low percentage of total request processing time (I’m thinking 2 - 3%, but I could be off on that).

At any rate, the stuff you need to get between client and server FAST is probably stuff that is totally mundane and security insensitive - object positions, velocities, etc. There’s really no need to encrypt that. Stuff that might make sense to encrypt (a) is usually infrequently sent (chat messages), and (b) isn’t time sensitive (also chat messages). Any overhead added by encrypting those types of messages is totally lost in the noise. I’d bet very good money that you’d spend far more cycles serializing/sending/deserializing those messages than adding encryption on top of those. That’s especially true now with newer architectures that have hardware AES instructions, and the newer JVMs that can leverage those instructions.

My bottom line for encryption: Setting up encrypted channels is fairly expensive. Do it infrequently. Using encrypted channels is fairly cheap. Do it whenever it makes sense and don’t worry about the cost.

1 Like

Yes, but what we’re concerned about here is latency of small packets.

Just don’t encrypt real time traffic. It’s silly.

Edit: and it’s never ever been about CPU usage.

1 Like