8
\$\begingroup\$

I am developing an open source game that uses a client-server scheme similar to Minecraft. We will control the central authentication server that verifies an account is valid, while players will run their own servers.

Authenticating the client is simple, but how can the server know that the user is valid, without having any access to is credentials or session token?

For example:

  • Client > Auth Server: Sends user credentials.
  • Auth Server > Client: Responds with a session ID if valid login.

Then, the client can connect to the server, but the server has no way of verifying is the client is who it says. These servers are ran by players, which make it easy for them to modify the server and collect the user data. (Only the central auth server can be trusted)

The authentication server could accept TCP connections, but I wonder if HTTPS would be easier in this case, as getting a response is easier than establishing a listener on each side, especially for only a few requests.

\$\endgroup\$
3
+100
\$\begingroup\$

Edit: After posting this I realized it's almost the exact same answer given by Ali.S (slightly different but the overall approach is the same.) It started out as something completely different though.

This method assumes that all communications are being held over a series of secure tunnels. How you achieve this doesn't matter. I would suggest TLS, but that's just me.

  1. Client => Game Server The client connects to the game server and initiates a login session.
  2. Game Server => Auth Server The game server connects to the auth server and requests a session ID token from the auth server. This connection is kept open to listen for the login success/failure.
  3. Game Server => Client The session ID token is sent back to the client.
  4. Client => Auth Server The client sends the session ID to the auth server along with the username and password of the user, and some information about the server (IP, TLS public key, etc. See footnotes)
  5. Auth Server => Game Server The auth server then sends information about the login to the game server (success state, username, stats, etc) using the session ID provided by the client.
  6. Game Server => Client The game server tells the client that the auth was successful, and lets them in.
  7. All connections except for the initial client to game server connection are now torn down.

Alternatively, you can give the game servers a dedicated port to listen for logins. If you choose this route, then the flow would look like this:

  1. Client => Auth Server The client sends the username, password, and server IP to the auth server.
  2. Auth Server => Game Server + Client If the login is successful, the auth server sends a unique token to the game server and client. Send the IP of the client to the game server too, so that the token can't be stolen.
  3. Client => Game Server The client then sends the token to the game server, where it is then verified and deleted on the game server. The game server then lets the client in.

This second approach would make the overall implementation a bit easier.

Footnotes:

The reason I specify that some information should be sent about the game server to the auth server is to harden the process against spoofs. The server can verify the information to make sure that it is authorizing the connection that the player expects.

Session IDs would not have to be cryptographically secure, though it would make spoofing connections somewhat harder if they were.

If you do choose to go the TLS route, you can set up a signing server that signs all the certs used by your infrastructure, and add it as a trusted CA in the client/server software. So long as you don't let your signing cert get loose, you'll be able to provide some decent authentication.

For the sake of mitigating DoS attacks, make connections timeout after 20 or fewer seconds. If it lasts longer than that, then something is wrong and you don't need to wait 3 minutes waiting for the connection to timeout on its own.

\$\endgroup\$
  • \$\begingroup\$ Note that your alternate flow is likely not to work for clients which are behind "parallel" NAT devices (classified as "strict", by Microsoft's Xbox Live program). And may similarly have trouble if two clients are both simultaneously behind the same NAT device (depending on the specifics of how their NAT device handles that situation); this is because the game server may see a different IP address+port than the auth server does, just due to NAT. The first listed approach should work without trouble in all cases. \$\endgroup\$ – Trevor Powell May 27 '15 at 10:24
  • \$\begingroup\$ Just to make the terminology clear, the Client (the player) would have no special requirements placed on them for the second flow. Only the game server would need a dedicated port mapping for this method. Since it is already serving the game on a dedicated port, this shouldn't be too much to ask. The entire process is started by the client initializing a connection with the auth server, which any device on the internet can do, regardless of how strict their NAT is. \$\endgroup\$ – Kaslai May 29 '15 at 5:55
  • \$\begingroup\$ Upon re-reading your comment, I think I see what your issue was. In the case of a user utilizing some sort of load balancer that can theoretically send the auth request via one IP and the game connect request via another IP, then that can be solved using Ali S's solution. \$\endgroup\$ – Kaslai May 29 '15 at 6:03
  • \$\begingroup\$ Yes, that's what I was intending to point out (but maybe didn't make clear). Under "strict" NAT (by Microsoft's definition), the auth server and game server won't see the same IP:Port values for a single player, so the auth server can't usefully tell the game server the IP/port to expect to see. This issue can also happen with "moderate" NAT (depending on specific NAT implementation) if there are two players behind the one NAT device, both trying to send from the same port number. \$\endgroup\$ – Trevor Powell May 30 '15 at 1:39
  • \$\begingroup\$ Ah, well I was just thinking that the IP itself should be accounted for. The port doesn't really matter; It's just to prevent a malicious third party from stealing the token and using it elsewhere. It doesn't really matter if there are multiple users behind the same NAT, as the token will identify the actual user, so there aren't any collision issues to worry about. \$\endgroup\$ – Kaslai May 30 '15 at 6:57
2
\$\begingroup\$

The client should have a private and a public key.

The private key should be what the unique identifier that the client receives from the authentication server. The public key should be also sent to the client.

Before the client connects to a game server, it should send a message with its private key and the ip of the game server it wants to connect to, to the authentication server. The authentication server should then verify and find the match for the private key and store the public key in its records.

The game server that the client is connecting to should send a request to the authentication server after obtaining the public key of the client. If the authentication server can verify that the client wants to connect to that IP of the game server, send that it's an okay client back. The game server should then allow the client to connect.

The private key is only used for authentication of the client so that the game server doesn't obtain the real authentication id.

\$\endgroup\$
  • 1
    \$\begingroup\$ I think I understand the process used. I wrote up a flowchart kind of thing: i.pyratron.com/MXkZXU.png Does this information seem correct? \$\endgroup\$ – Cyral May 23 '15 at 1:34
  • \$\begingroup\$ @Cyral That looks correct. \$\endgroup\$ – Static May 23 '15 at 1:40
1
\$\begingroup\$

There are multiple solutions that I can think of, but here is the most secure one:

  1. client connect to server.
  2. client requests an authentication bridge.
  3. server connects to auth server, acting as a proxy between player and auth. server.
  4. client and auth server, form an SSL session over this newly formed bridge.
  5. using this secure connection over bridge, client logins into auth server.
  6. auth server tells game server whether the login was successful or not, over some other TCP connection. then disconnects it's bridge/login connection.
  7. client and game server can now resume communication (only) over already existing connection (which was used for authentication).

Note that, in this scenario game server actually has no way of eavesdropping, even though the whole authentication is passing through it. for the same reason your ISP can't monitor what packets you send to Facebook, or are coming from facebook.

\$\endgroup\$
  • \$\begingroup\$ Technically the ISP has access to the raw data. \$\endgroup\$ – Static May 23 '15 at 1:05
  • \$\begingroup\$ @HaroldSeefeld Technically not the ones that pass through IPSec/HTTPS connection. \$\endgroup\$ – Ali1S232 May 23 '15 at 1:09
1
\$\begingroup\$

The way I would do this is by having Auth server send token to Client after login along with list of validated Game servers (so that the Client can be sure the Game server is valid).

Then the Client would send the token to the Game server, which would then send it to Auth server to confirm that this is the valid client.

Login:

  1. Client to Auth server: username and encrypted password
  2. Auth server to Client: token

Later when joining a Game server:

  1. Client to Game server: the previously mentioned token
  2. Game server to Auth server: again the token
  3. Auth server to Game server: if token is valid then OK signal
  4. Game server to Client: allows client to join
\$\endgroup\$
0
\$\begingroup\$

How about signing a JWT token with a secret only the central auth and player server knows? It lets you sign json, which can be verified later.

\$\endgroup\$
  • \$\begingroup\$ Wouldn't that allow player-run servers to steal their users' credentials? \$\endgroup\$ – idbrii May 28 '15 at 22:26
  • \$\begingroup\$ No, 2 ways to do this: 1 - client asks for a jwt with the server in it, allwoying the server to steal identity, but only on their server (not a big deal) 2 - JWT only works once \$\endgroup\$ – Ben Aubin May 28 '15 at 22:30

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.