[SOLVED] World server design questions simethereal

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.

Vault works like your saying.

When you start vault, you create a token for access to it.

$ vault server --dev --dev-root-token-id="00000000-0000-0000-0000-000000000000"

Set two environment var.

$ export export VAULT_TOKEN="00000000-0000-0000-0000-000000000000"
$ export VAULT_ADDR="http://127.0.0.1:8200"

Create an endpoint as key/value pairs in Vault.

$ vault kv put secret/github github.oauth2.key=foobar

Setup your apps with a bootstrap.properties file.

spring.cloud.vault.token=00000000-0000-0000-0000-000000000000
spring.cloud.vault.scheme=http

Now you can retrieve them in your code by calling the endpoint.

vaultTemplate.opsForKeyValue("secret", KeyValueBackend.KV_2).get("github");

You can also create new key-values, encrypt, decrypt, whatever.

Very slick as this vault will be run on its own server without anything else running on it.

This is a bump update.

I have been studying Vault since the last post and its helped me to understand the things @jayfella was saying immensely. Vault does everything you mentioned and more.

I ran into the usual problems with some documentation not as up to date as should be but have worked with hashicorp to get some things cleaned up. They are really responsive to reports.

In the final stages of bringing everything together now. Vault is very addicting but it’s the way to go for securing apps with SpringBoot imo.

On another note, I will have my own linux box for server testing in a couple of months since win 7 is hitting end of life. It’s a 32 bit Pentium that runs to good to just toss but just cant handle windows 10. Cant wait.

3 Likes

A small design question.

The gameserver credentials reside in the vault server but the way I am using vault is that the only app that can connect to vault is the WorldServer app and then it’s policy restricted to only read a servers credentials for authentication.

WorldServer only allows connections to the endpoints for saving and updating from specific addresses, ie the gameservers.

What are the opinions on using environment variables vs file for storing credentials of the gameservers for sending to the WorldServer?

I mean it’s not the end of the world. I know it’s common practice in some areas to do this. For example when you push jars to hosts, instead of putting your password in a build file you can use various other methods, one of which is pulling from an env var.

Technically speaking passwords should keep their presence in memory as short as possible (and in some super-sensitive cases they use an array of chars and overwrite them before disposing). My opinion of it is that it’s a frowned-upon method. I may do it personally, but I wouldn’t do it in a corporate environment, or at least wouldn’t encourage it as a standard procedure.

Right, I am wanting to avoid pushing a file to github and I exclude it from the dist jar as well.

I have it setup to use files during development and environment during deployment.

Vault uses config files for server and environment for clients.

Doesn’t seem to be a standard based off reading the war about it. Always good points for and against. I am having trouble pulling the trigger on files because of my past experiences with VPS.

Well keep in mind that a database is a file, too. So in that respect they are as vulnerable as flat files. And if I have access to the database I have access to the salt, and therefore the password.

Choose a reputable host.

Yeah, My first choice is centurylink but they have horrible customer service for business accounts. Been trying for 3 weeks to get them to even talk to me so that screams avoid at all costs.

My second choice doesn’t have enough data centers for what I am wanting to do but they have awesome VPS and dedicated pricing and customer service.

My two choices are digitalocean for a VPS and OVH for a dedicated. Kimsufi is an OVH reseller, and can be cheaper. Hetzner are another solid company.

1 Like

I would you suggest you use consul for healthcheck, service discovery…, keyclock as a main point for issuing, validating jwt, roles, sessions, security realms, users (can be integrated with 3d party services for oauth2) and leave vault for good also dockerize everything for happy life.

Oh My.

2019-09-12 16:43:09.629  INFO 764100 --- [ctor-http-nio-4] v.a.ReactiveLifecycleAwareSessionManager : Scheduling Token renewal
AUTHENTICATED true ID gameserver-1 Authority [XXX] cred xxxxxxxxx
2019-09-12 16:43:27.630  INFO 764100 --- [ctor-http-nio-1] c.p.s.ServerStats                        : Server [1] reported [0] players.
2019-09-12 16:43:27.631  INFO 764100 --- [ctor-http-nio-1] c.p.s.ServerRepositoryImpl               : addServerStats() #servers[1] { "serverId": "1", "numOfPlayers": "0", "location": "Temp City, USA", "memberServer": "false", "serverAddress": "localhost:4269" }
[snip]
v.a.ReactiveLifecycleAwareSessionManager : Renewing token
2019-09-12 16:44:49.704  INFO 764100 --- [ctor-http-nio-4] v.a.ReactiveLifecycleAwareSessionManager : Scheduling Token renewal
AUTHENTICATED true ID gameserver-1 Authority [XXX] cred xxxxxxx
2019-09-12 16:45:06.673  INFO 764100 --- [ctor-http-nio-1] c.p.s.ServerStats                        : Server [1] reported [1] players.
2019-09-12 16:45:06.674  INFO 764100 --- [ctor-http-nio-1] c.p.s.ServerRepositoryImpl               : updateServerStats() #servers[1] { "serverId": "1", "numOfPlayers": "1", "location": "Temp City, USA", "memberServer": "false", "serverAddress": "localhost:4269" }
2019-09-12 16:45:14.705  INFO 764100 --- [g-Cloud-Vault-2] v.a.ReactiveLifecycleAwareSessionManager : Renewing token
2019-09-12 16:45:14.724  INFO 764100 --- [ctor-http-nio-4] v.a.ReactiveLifecycleAwareSessionManager : Scheduling Token renewal
[snip]
2019-09-12 16:51:05.151  INFO 764100 --- [g-Cloud-Vault-2] v.a.ReactiveLifecycleAwareSessionManager : Renewing token
2019-09-12 16:51:05.166  INFO 764100 --- [ctor-http-nio-4] v.a.ReactiveLifecycleAwareSessionManager : Scheduling Token renewal
AUTHENTICATED true ID gameserver-1 Authority [xxx] cred xxxxxxx
2019-09-12 16:51:06.818  INFO 764100 --- [ctor-http-nio-1] c.p.s.ServerStats                        : Server [1] reported [0] players.
2019-09-12 16:51:06.819  INFO 764100 --- [ctor-http-nio-1] c.p.s.ServerRepositoryImpl               : updateServerStats() #servers[1] { "serverId": "1", "numOfPlayers": "0", "location": "Temp City, USA", "memberServer": "false", "serverAddress": "localhost:4269" }

Did I mention I hate functional programming and lambdas? Except Optionals and Providers.

I finally have a fully secured, custom reactive vault server implementation, that I can now use in my game for users, apps and anything else that needs it.

I had to implement a custom authorization manager and was able to get it working except for a bug in ONE LINE in the LAST METHOD. I understood exactly what was wrong, could easily fix it with normal java techniques or if this was a REST server but this crap is streams, lambda, functions and reactive programming.

Once upon a time I could of grabbed a good book on the subject and persevered. Not so easy now days. I literally read hundreds of terse, poorly written web pages written by people who mean well but suck at teaching. This includes the java tutorials. I even read the table of contents on dozens of books and their sample chapters which I am really good at determining the quality of the teaching from.

But like Paul mentioned, you may only get a chapter or less out of them worth a crap. Most were 2 pages at best. Though I consider myself a moderately skilled java coder, I am totally green on functional reactive programming and the light bulb just wouldn’t turn on.

Did I mention I hate functional programming? Except Optionals and Providers.

Finally, after turning every link on the subject in google and bing purple (literally hundreds) and 7 days, 8-12 hrs a day of reading, I ran across this.

https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/Lambda-QuickStart/index.html#

It helped because it uses a proper teaching technique but it wasn’t until I found this link at the very bottom of that page, literally the last link in the summary,

To learn more about Java and related topics check out the Oracle Learning Library.

that I got rid of my huckleberry. If you follow the learn link and enter lambdas in the search there is a free course on lambdas and streams that is just dam good stuff.

I still suck at this type of programming and think that its a total waste of effort for such a small gain. You give up readability for terse code and excruciatingly painfully hidden bugs using this crap.

I can see how some people could like it for some things but I truly don’t get the hard swing to using it that I see happening. Why not just binary code instead? About as intuitive.

2 Likes

Java streams are hit or miss IMO, often not worth the effort.

Silly fad in another futile attempt to appease the cool kids who’ve already moved on*. :slight_smile:
(*Except in situations where it makes sense to use parallelStream() for performance benefits.)

I once asked a guy teaching this stuff “What’s the downside?”, and he said learning curve. I would add readability/maintainability, myself.

On lambdas… for backend stuff, I rarely find myself using them. But with JavaFX UIs… damn, it would be painful without them. (NetBeans code assist also a big help there.)

Congrats on getting through the pain of security implementation.

1 Like