[SOLVED] World server design questions simethereal

Question answered?

Not done yet. :frowning:

May run into some design issues with security even though I implemented some basic stuff.

I am going to try and setup roles and other things that make it stronger from attacks.

I will tag it when finished.

1 Like

Yeah, mongoDB is a joy to work with if you like JSON at all… so a natural fit for anything REST related that tends to use JSON anyway. (It’s a damn sight better than all of the other “big data” noSQL solutions to setup, access, etc… just nice.)

I don’t know about it’s licensing, though. For my personal projects, that hasn’t mattered yet.

For security, I think I should be using JWT and securing the endpoints on the rest server.

All examples I am finding are typical unsecured, worthless examples since they are hard coding the passwords in the client code and using a human login interaction.

I believe I understand how to setup the rest server to skip the login stuff and setup the client to send, its the client storing and retrieving its credentials to send part securely that’s throwing me.

How does the client application store its password or token for sending to the rest server securely and how do you access that token without coding the password and stuff into the client?

Edit: The endpoints for saving and updating a server stat are secured and the public endpoint is open to anyone. The saving and updating are restricted by address but as I understand things, that can easily be broken.

This is for server to server stuff?

yes server to server.

So you are looking for some kind of public/private cert thing? Some web containers (like JBoss) will support that sort of thing directly.

Else the presumption is that you’re making HTTPS connections anyway and then what you send doesn’t quite matter as much and it’s up to you at some level. My own security-fu ends about there. In my “day job”, I have other folks to wire that stuff up. :slight_smile:

Can you explain the what you’re doing. Like “login, talk to server A, decide who to join, join server” or whatever your process is. I can tell you how to do it but I just need to understand what it is you want to do.

Server = HTTP World stats server that holds all servers reporting to it in memory using ConcurrentHashMap.

GameServer = SimEthereal servers with Spring WebFlux WebClient.

Server Endpoints
save - Server receives POST(creates a new ServerStats object) currently filtered by address.
update - Server receives PUT(updates a existing ServerStats object) currently filtered by address.
list - Server receives GET(sends out list of active servers that reported for duty) open to anyone.

Every GameServer upon startup sends a saves to Server reporting for duty.
Each GameServer upon a new user connecting updates its stats on the Server.
Each GameServer upon a user disconnect updates its stats on the Server.

Works great.

I want to secure the endpoints better and jwt and roles seems to be the proper way to do it but I need to figure out how to store the clients credentials and retrieve them securely.

I have found this and am just learning about it,

https://spring.io/projects/spring-vault#samples

I have read about OAuth also but to tell the truth OAuth seems more complicated and terse than I like.

JWhen you store a password you use pkbdf2 with x iterations. The more the better. It increases every year.

The client sends via HTTPS the new password in plaintext. That’s fine because https is encrypted. That password is hashed on the server with a salt and stored as hash:salt in a database or whatever.

When a client logs in they again send it plaintext over https. The server retrieves the stored salt for that user and hashes the password to compare it. If the hashes match then it’s the same password.

So that’s how you store passwords.

When a user logs in successfully a session is created for that user. The session is usually generated using a secure random string of pre-defined characters. they are also usually given a cookie that contains that session ID. And it is an ID. That session ID now identifies the user. That cookie is automatically sent back to the server whenever we talk to it. So now the server knows who we are every time we talk. If we don’t have a session ID or the session ID is invalid (not found) then we are not logged in.

So now we are in a position where we can maintain a conversation between the client and a server.

If you want to go beyond that you can limit session lifetimes to 15 minutes, so every time you hear from a session you check the time since the last request and if it exceeds 15 minutes reject it or delete it in a cron or both.

You can require re-authentication on sensitive transactions. Banks do this. It invalidates the old session and forces a new one. Anyone that somehow had your session doesn’t anymore and they can’t jack it in the middle.

Email validation also works. Password, email changes? Send an email with a verification code. This is being superseded by 2-factor authentication slowly.

Oauth is great because it’s just like a session ID but with a limited scope. It knows it’s you but you can only do certain things with it. If you want more you have to login to a website and use the traditional sessionID method with the aforementioned security steps.

It means I’m sending a session but with limited permission. Sure you could change some stats. Tell the server I have 30 players online, but you can’t hijack my account with it. You’re limited by the scope of what an oauth2 session is allowed to do.

With a traditional sessionID it’s essentially a password. You don’t want to send that ANYWHERE other than to the server that gave it to you. With an oauth2 session it’s way more secure because they have nothing but basic permissions to carry out non-secure tasks on your behalf. You can just issue another one and done. Nobody was harmed. Slight disturbance. But most importantly it’s easily stopped and a whole bunch more secure.

I am missing something. I understand how the procedure works on Server for salt and storing, but its the storing and reading on GameServer prior to sending that’s still not making sense to me.

Say password for a GameServer is
abcd

Anyone can read that if its stored in a file on the GameServer drive and just use it. If its hard coded into the GameServer send method, they can easily read the code and get it there.

Its the storing and retrieval on GameServer that escapes me. I don’t see how hashing it makes a difference for GameServer if I am storing the hash in a file on GameServer, cant they just copy the hash and send that?

This is what I am understanding for steps.

hash abcd
store hash,
read hash and send hash to Server,
Server salts and stores.

I keep this article handy. Worth a few reads in a row, probably:
https://crackstation.net/hashing-security.htm

Edit: and I caution against skipping sections because “I already know that”. You might miss something important.

1 Like

You can use Java’s Cipher to secure your file with a password.
You need CipherInputStream and CipherOutputStream to read and write files encrypted with Cipher.

   private void read() {
        final Cipher cipher;
        try {
            cipher = Cipher.getInstance(transformation);
            cipher.init(Cipher.DECRYPT_MODE, key);
        } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException ex) {
            throw new RuntimeException("Error initializing decrypt cipher", ex);
        }

        try (FileInputStream fis = new FileInputStream(path);
                BufferedInputStream bis = new BufferedInputStream(fis);
                CipherInputStream cis = new CipherInputStream(bis, cipher);
                ObjectInputStream ois = new ObjectInputStream(cis);) {
            userIndex = (HashMap) ois.readObject();
        } catch (ClassNotFoundException | IOException ex) {
            throw new RuntimeException("Error reading user repository " + path, ex);
        }
    }

    private void write() {
        final Cipher cipher;
        try {
            cipher = Cipher.getInstance(transformation);
            cipher.init(Cipher.ENCRYPT_MODE, key);
        } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException ex) {
            throw new RuntimeException("Error initializing encrypt cipher", ex);
        }

        try (FileOutputStream fos = new FileOutputStream(path);
                BufferedOutputStream bos = new BufferedOutputStream(fos);
                CipherOutputStream cos = new CipherOutputStream(bos, cipher);
                ObjectOutputStream oos = new ObjectOutputStream(cos);) {
            oos.writeObject(userIndex);
            log.trace("Saved user repository in {}", path);
        } catch (IOException ex) {
            throw new RuntimeException("Error saving user repository to " + path, ex);
        }
    }

example of creating SecretKey from password string:

        try {
            // Create Key
            DESKeySpec desKeySpec = new DESKeySpec(password.getBytes());
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm);
            key = keyFactory.generateSecret(desKeySpec);
        } catch (InvalidKeyException | InvalidKeySpecException | NoSuchAlgorithmException ex) {
            throw new RuntimeException("Error creating user repository SecretKey", ex);
        }

Yes, but who is “they”?

Wouldn’t each game server have its own login?

  • read hash and send hash to server.

No. That hash is just for comparison. You create a session ID or an oauth token after the login was successful to converse. A session ID is virtually the same as a password, so don’t send that anywhere. The only thing you want to do with a session ID is to put it in a cookie. So what you want is an oauth token that has limited permissions. It can update statistics for that server in your instance, but it cannot change a password, view sensitive data, etc.

If anybody does manage to get a hold of that oauth token then the scope of what they can do is limited by the permissions you allow that token to do. If you only allow that token to update statistics then thats the worst they can do. All you have to do to mitigate the problem is delete that token and issue a new one.

I think somethings getting past everyone or I am still not getting it, which is definitely the case for me.

There are two apps. Each is a server, neither has form login.

Server = a resource server. It can receive input only by url.

GameServer = a SimEthereal server. It can only receive input by reading a file located on its drive or when starting through a startup command or by retrieving it somehow from somewhere.

Server can easily store a salt and hash. Doesn’t matter if the file is read by someone snooping through your file tree as this server will use the password it is presented with through the PUT/POST and do validation.

GameServer password cannot be stored on the drive since it must be readable. My experience has been I can snoop ANY vps account on a server if I have an account on that same server and I can read any file that has read file permission.

This leaves setting the password for GameServer to use with Server by manually passing it in as a argument when starting the GameServer and setting a private variable. I know I can prevent the command from being stored in history.

Problem with this as I see it is I cant run a script that restarts the GameServer in the event of a crash, which I have found to be mandatory or players get real pissed when you have a 2 am crash and you are sleeping.

I do not know how this is done with github and travis but the way they do it would be the way to go where you give the app permission and create a token so the app can access the Server. How they store this stuff so it can interact with each other is what I am trying to figure out.

I think Vault that I linked to may be the answer but as always I may be reading something into it that its not doing.

Spring Cloud Vault Config provides client-side support for externalized configuration in a distributed system. With HashiCorp’s Vault you have a central place to manage external secret properties for applications across all environments. Vault can manage static and dynamic secrets such as username/password for remote applications/resources and provide credentials for external services such as MySQL, PostgreSQL, Apache Cassandra, MongoDB, Consul, AWS and more.

Not if they are configured correctly. That would be a major game-changing problem. It does not exist except on badly configured setups. I would argue it’s pretty hard to actually do that unintentionally.

So here’s how I see it.

  • User creates an account. They are now allowed to use your game, either as a player or server owner.
  • User decides to set up a gameserver.
  • User requests to register a new gameserver.
  • Server responds by giving the user an oauth token (per gameserver. A user can have 10 servers if they want and each server will have a unique oauth token). You can restrict the amount they can have if you want.
  • This token has permission to CRUD a single gameserver data and nothing else.
  • User puts that oauth token in their gameserver settings.
  • Users new gameserver starts. It sends data to the server with oauth token.
  • Server checks if the oauth token is valid.
  • Server responds OK with the CRUD request if the oauth token is valid.

So there’s a few things you can take from this.

  • The server will know who owns the gameserver because a user will own the oauth token.
  • The server will know which gameserver data to operate with because each token only has access to one gameserver data. A one-to-one relationship.
  • When the gameserver starts and sends the CREATE request, it will also send it’s IP. Your server can query that IP to know if it’s offline. You can do that on request (when someone wants to actually know) or if you checked less than 10 seconds ago, send that response (i.e. mitigate internal hammering).
  • Only the gameserver and the server know the oauth token, and they are transferrered via https so it’s “secure”. There’s no need to encrypt it, or actually any possible way to do so successfully. HTTPS is “the way” to do it.
  • A person can “hammer” the CRUD endpoint but that’s a server thing, not necessarily an application thing. Firewalls can temporarily block IP addresses that request too fast for x minutes. My point is this isn’t something you should overly concern yourself with in development.

If you want your gameservers to have passwords, the password can be set in the gameserver settings file. That’s a perfectly normal way to do it for something like a gameserver. In virtually every single configuration file on a server, that’s how they’re stored. MySQL passwords and all. When you “ping” the gameserver to see if it’s alive it can tell you it has a password set. You could even be super-efficient and keep it all in the header.

1 Like

No. This has been removed. User can only play the game I code.

This is the jest of things right there. There is no user input. Consider the User to be the SimEthereal GameServer. I have a WebClient integrated into SimEthereal that runs as a AbstractHostedService.

When the server starts up. It tells the World Server its is up and running. World Server stores this object in a ConcurrentHashMap. From then on the GameServer just updates its object on the World Server.

The rest is good once the GameServer receives its Authorization.

This is what I am seeing from other things but this is what concerns me. I haven’t ran an vps for a considerable time but I used to hop around the server and check out other peoples stuff, telnet to other servers on the net and do the same. As long as any folder had read permission I could easily do this anywhere. Like for isp server logs, any read permission folders or files.

But you are saying this is no longer possible?

It isn’t if you use any reputable service, no. If it were it would be one hell of a security breach. They are as secure as a dedicated server if configured correctly.

1 Like

Well that solves all my problems if I can store the password in properties file.

I create and store all the hashed passwords and salts on the Server then and each GameServer can do its thing.