5

In order to encrypt communications from our (custom) client to our (custom) servers our current scheme is a bit like this:

  1. Client uses the bundled public key A to encrypt some random key material.
  2. Lobby server decrypts it with the private key, uses the encrypted key material to set up an encrypted channel with symmetric encryption.
  3. Client gets another public key B1 from the lobby server for login to game server 1, over the encrypted channel. (Game Server 2 would have public key B2 etc, each of these are generated at server restart)
  4. Client connects to game server and follows same scheme as 1-2 to secure communications.

Leaving aside how how the key material is generated and used, would there be any change in security we change it to:

  1. Client uses bundled public key A to encrypt key material
  2. Lobby server decrypts with private key, uses the encrypted key material to set up an encrypted channel with symmetric encryption.
  3. Client connects to game server and follows same scheme as 1-2 to secure communications with THE SAME PUBLIC KEY "A" the lobby used (so both lobby and game servers use the same private key)

In other words, do we get any enhanced security from only using the bundled public key for the lobby login?

A final alternative would be with a separate login server:

  1. We create a login server which the client connects to in the manner of 1-2
  2. The client is then awarded a new symmetric key C and an identifying number D
  3. The client connects to the lobby server, presents the number D in plain-text.
  4. The lobby and client now continues communication using the key (assume C is in a shared db or similar) C
  5. The client connects to the game server, again follows 3-4 to set up an encrypted channel.

Are any of these schemes significantly worse or better than the other? I can't see any huge difference.

0
8

One potentially significant advantage of not using the same private key for both the lobby and the game servers is that, even if one or more of the game server keys is compromised, the lobby server key (whose public half is bundled with the client, making it hard to change) is still safe.

Presumably, the game servers present a significantly larger (and more frequently changing) attack surface than a dedicated lobby server, so it makes sense to design your system to be able to recover from an attack on the game servers, while making the lobby server as hard to compromise as possible.

Your third alternative also shares this advantage, since only the login server needs to know the private half of the bundled key. Indeed, depending what else besides authentication the "lobby" server is doing, separating the critical authentication functions onto a dedicated server may be a good idea.

Also, your third alternative guarantees that clients will not be able to bypass the lobby/login server even if they somehow manage to acquire a copy of the game server public keys (e.g. from another, compromised, client). (The client could still bypass the login server if they somehow acquired another client's symmetric key, but since those keys are tied to client IDs, your servers should be able to detect it.) Depending on your use case, this may or may not be an advantage, but at least it shouldn't hurt.


BTW, I feel like I really should amend this old answer to note that there's a more secure (and practical) option than any of those described above:

  • Don't bundle any of the game or lobby server public keys in the client. Instead, bundle the public half of a "root" digital signature key, while keeping the private half somewhere safe (i.e. not on any publicly accessible servers).

  • Use the private root key to sign the public keys of your game and lobby servers.

  • When a client connects to a server, the server first presents (over an insecure channel) a "certificate" containing its signed public key. The client first verifies the signature using its bundled public root key, and then establishes a secure channel to the server using the verified public key.

You will also need some mechanism of revoking compromised server keys. The simplest way is to attach an expiration timestamp to the public server key before signing it, and have the client refuse to use an expired key. Of course, this means that you'll have to change (or at least re-sign) the server keys at regular intervals before they expire, which is something you'll want to automate.

You can also include in your protocol an option for e.g. the auth/lobby server to send the client a list of revoked server keys that the client should not trust even if they otherwise look valid. This will at least allow quick revocation of game server keys, without having to wait for them to expire. This can be useful e.g. if some game servers are run by third parties who cannot easily receive automated key updates, making it inconvenient to use a very short expiration time for their keys.

Of course, another option could be to give such third-party game server operators their own "branch" signing key, itself signed by the root key, so that they can generate and sign their own server keys. Of course, the client then needs to be able to follow such chains of signed keys all the way up to the bundled root key. And the branch keys need to carry some (signed) metadata indicating which servers they're valid for, so that the third party can't e.g. just generate and sign their own lobby/auth server keys.

The nice thing, though, is that you don't really have to implement any of those features yourself, since they're all part of the public key infrastructure model used in TLS (and DTLS), which is the protocol that e.g. your web browser uses to connect securely to Stack Exchange (and to any other HTTPS website). While TLS is a very complex protocol (party due to historical accumulation of features) that you really don't want to implement yourself, there are plenty of TLS libraries that you can use. Nowadays, it's more than likely that your language runtime even has one bundled in. (If it can fetch data from an https:// URL, it does, or uses one bundled with your OS.)

Of course, you'll still need to learn how to configure your TLS library to suit your needs (e.g. to only trust your own root certificate and to disable any legacy features you don't want) and how to generate and sign TLS keys, which can be a non-trivial task in itself. But it's certainly a lot easier than implementing a secure communications protocol all by yourself from scratch.

1
  • Just so that it's clear: The client may authenticate itself, but only over the secured connection after the encrypted channel is created (i.e. stage 2 is completed). However, not all requests to the lobby require authentication, e.g. registration. (Lobby requests are also stateless, so authentication may occur multiple times) – Nuoji Dec 31 '12 at 17:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.