Advertisement

Create player accounts on custom server (for steam users)

Started by August 18, 2016 09:52 PM
12 comments, last by Lewa 8 years, 1 month ago

I want to explain my current situation:

I'm building a 3D parkour platforming game in which players race on seperate maps/levels and win medals by beating the time trials as fast as possible.

The game also includes a map-editor with which players can create their own maps.

Alongside the game i intend to provide a (master-)server which takles the following tasks:

- custom map uploading (so that players have a place to upload and share their maps)

- online leaderboards for the "official" maps and all uploaded maps on the server

- calculation of player statistics (number of medals, "ladderpoints", etc...)

I plan on releasing the game on steam (still isn't 100% set if it's going to be commercially or free, although i would love to use the opportunity and release it commercially to see how the "indie live style" would look like and if it's viable for me to do this as my full-time job in the future.) and thus it would be great if it would be possible to create "user accounts" on the master server for each steam-player who played the game.

The main purpose for the accounts is to allow the players to log-in on the games website and upload their custom maps to the central database.

(So that only players who played/purchased the game can log-in and upload custom maps.)

I already implemented a possible solution, although it has some issues:

After the start of the game the client connects to the server (via simple HTTP request) and sends the steam-ID of the player to the server.

The server then checks if the Steam-ID is already in the steam database. If not, the steam-ID is added to the database.

If the player is already registered, then the game attempts to log-in by checking of the saved password on the client matches with the one on the server (the password is transferred somewhat securely via hashing and a session specific salt which is generated at the login attempt.)

If the player registers at the first time, he recieves a "password" (generated by the server) which he can use to login on the website.

Now here is the biiiiiiiig problem:

The password is created once and stored as a local file on the client.

If the player looses this file, he will not be able to login anymore if he doesn't know the password which was generated by the server.

Even worse: What if someone tries to mess with the system and submits HTTP requests with random Steam-IDs to the server?

If a player starts the game for the first time and the steam-ID is already in the database, he/she will not be able to login as the password was already generated.

Those accounts don't have any kind data which can be used to verify the player (like an email).

To counter this problem i allowed the client to request a "password reset".

To do a password reset, the server has to generate a unique public "key" which is then sent to the client.

The client then hashes the steam-ID with the public key + a private key which is stored in the games exe. (The private key is stored on the client and server.)

The hash on the clientside is then sent to the server. If the hash is valid then a new password is sent to the client (like on their first registration attempt.)

The idea was that nobody is going to be able to submit simple HTTP requests to the server to registrate random Steam-IDs without the valid steam accounts.

Now the problem is that once the private key is figured out, literally anybody could request a password reset for every single account and login on the website... (i know that storing keys/passwords isn't really secure...)

I just want to prevent that "hackers" get into the accounts of other players and wreak havoc by submitting/spamming maps or change settings of the users account.

There are alternatives to this solution which came to my mind, but each of those has its own issues (mostly security wise)

  • Steam Web Api - This would probably the easiest solution. The game would simply register the steamID on the server (if the ID isn't already in the database) but now password would be generated/sent to the client. Instead players would be able to login into their account on the website by using Steams OpenID system. The issue here is that i'm afraid that the data might be compromised. (Someone could either hack into the server and redirect the openID login onto a fake webiste or use a Man in the middle attack and redirect to a fake website from there.) It may be unlikely that this would happen, but i simply don't want to take the risk. Additionally i've read that steams OpenID implementation does violate some of the OpenID specifications and thus is "potentially" insecure (at least that's what i've read on some websites) however i'm not an expert in that field.

  • Allow players to create custom accounts by using an email and "link" steamIDs with this account. This solution is much safer (the email would be the only "critical" user-information which is stored on the server) but the problem is that i can't avoid that players create multiple accounts and link steam-IDs which belong to other users. (This system wouldn't prevent duplicate/fake accounts.)

Now bare in mind that security of sensible userdata is on top of my priority list. Data breaches happen in this day and age. Of course i will make sure that everything is set up as secure as possible, but i simply can't quarantee that this never happens.

The simplest solution would be to remove the mapsharing idea completely and only provide leaderboards... (which don't require any kind of login...) althoug it would be nice to be able to provide that feature as each map (even player created ones which got uploaded) recieve their own leaderboard on the serverside on which players can battle against the best time possible.

Sorry for the long post. I know that it's a very specific issue.

I don't expect anyone to come up with an idea/solution (or even answer at all.) But maybe someone here as an idea or something to contribute to a possible solution. (Or even if someone who has experience with features/systems like this and who could share their knowledge.)

You need either some token that steam and your server know, but the client does not, OR a token that the client and your server knows, that the client will remember.
The first is OpenID. The second is "create separate account with email and password." You have enumerated them, and now have to pick a choice :-)
FWIW, if you know that there's been a break-in/disclosure, you can invalidate all steam OpenIDs issued to your application ID, so there is mitigation should you have a break-in.
Meanwhile, if there is a break, and you leak everyone's email addresses, that list of addresses are in the wild. Hopefully you use bcrypt, so the passwords aren't also in the wild ...
A third option would be to use another federated login -- facebook, google, or such -- and tie that to the steam ID, but it seems better to just use the steam OpenID.
enum Bool { True, False, FileNotFound };
Advertisement

FWIW, if you know that there's been a break-in/disclosure, you can invalidate all steam OpenIDs issued to your application ID, so there is mitigation should you have a break-in.

Maybe i'm missing something here but what exactly should i invalidate? AFAIK OpenID redirects the player to Steam on which the user inserts the username and password. OpenID then practically tells my server if the login was validated or not. (Or is there more to that?) The information if the login was succsessfull or not is enough.

(Maybe i just misunderstand something here.)

What worries me is that the redirect from my website to steam (for the openID verification) could be intercepted and compromised. (If someone finds a way to break into the server, he could easily alter the code so that he either redirects to a fake openID website or harvests the passwords in another way.)

Additionally i don't even know what's up with the whole "steam does violate the openID standard" statements. (and if that introduces security issues.)

Meanwhile, if there is a break, and you leak everyone's email addresses, that list of addresses are in the wild. Hopefully you use bcrypt, so the passwords aren't also in the wild ...

Yes, the fact that emails would be stored in plain text on the database makes me paranoid. (No one likes his email to be compromised.)

I actually do secure passwords by using sha256(password+uniqueSalt).

To make 100% sure that no gets the idea of reusing one of his critical passwords (like for gmail, steam, etc...) i implemented a random password generator. Basically it's not possible to set your own password, but you can generate a new one.

A third option would be to use another federated login -- facebook, google, or such -- and tie that to the steam ID, but it seems better to just use the steam OpenID.

That's also an option. Although it still has the same issue as openID mentioned above (redirecting to fake websites, etc...)

(No idea how other websites which use steam OpenIDs handle this specific issues. They will be held liable if something goes wrong and somehow someone finds a way to break in and collect login information of users.)

I have to think about that.

But thanks for your input. :)

I actually do secure passwords by using sha256(password+uniqueSalt).


You should use bcrypt() or scrypt(), not just plain hashing.

the redirect from my website to steam (for the openID verification) could be intercepted and compromised


Presumably, the user will notice that the URL in the login window doesn't say "steampowered.com" but instead something like "steampwored.com" when looking at the SSL certificate validity key (green/red mark.)
This is in general a problem on the web -- some impostors are quite good. I guess the good news is that your game is probably not so super-successful as to be the biggest target for an attacker to go after.
That, in addition to "don't get hacked to the point where they can change your site."
Also, good site operations include making sure website code isn't surprisingly changed, perhaps re-deploying fresh code every so often and such.

Using a simple encryption key hard-coded into your site code to store the email address may be all you need to protect against most hackers -- most hackers just try to dump a database table to harvest info, and aren't super-coders with the resources of a nation state :-)
enum Bool { True, False, FileNotFound };

You should use bcrypt() or scrypt(), not just plain hashing.

What are the advantages of bcrypt and scrypt compared to the hash(pw+randomSalt) method? (I'll also look that up.)

Presumably, the user will notice that the URL in the login window doesn't say "steampowered.com" but instead something like "steampwored.com" when looking at the SSL certificate validity key (green/red mark.)
This is in general a problem on the web -- some impostors are quite good. I guess the good news is that your game is probably not so super-successful as to be the biggest target for an attacker to go after.

The issue is that not everyone is that careful and looks at the url or the SSL certificate before typing this information in.

And yes, it may be true that a game which isn't that popular is most likely never going to be attacked by hackers, but this isn't really an excuse for neglecting this aspect. (The problem is that the website would directly or indirectly have access to players data, like passwords. Otherwise it would be fine.)

Because if something like this happens (even if the chance is low) I as the developer/provider of this service would be in a looooooooot of trouble. (Especially if that is a commercial product.) That's why i'm always very careful (and paranoid) when it comes to stuff like this.

That, in addition to "don't get hacked to the point where they can change your site."
Also, good site operations include making sure website code isn't surprisingly changed, perhaps re-deploying fresh code every so often and such.

Redeplying the code every once in a while sounds like a good idea. I'll note that.

Using a simple encryption key hard-coded into your site code to store the email address may be all you need to protect against most hackers -- most hackers just try to dump a database table to harvest info, and aren't super-coders with the resources of a nation state :-)

Are they (the majority of them) using SQL injections to do this?

But you're right on this one.

Again, thank you for the input. I'll look if i can somehow bypass this issue (without requiring any sort of password login.) If not i might scrap the mapsharing idea altogether to save me trouble which might (or might not) occur later down the line...

(Or i use the current method which doesn't store personal userdata but is by no means secure due to the fact that the master-key is stored in the client. It would have no privacy issues whatsoever but people could get access to other accounts if this key is figured out. This would allow them to login- and upload mapfiles to another players account.)

The issue is that not everyone is that careful and looks at the url or the SSL certificate before typing this information in.


This is true, but there is no better solution :-(
Well, you can have players purchase a cryptographic token from you, but that's not a low-friction onboarding experience :-)

Or i use the current method which doesn't store personal userdata but is by no means secure due to the fact that the master-key is stored in the client


One option is to start there, and then give the user the option of signing in with a Steam ID if they want to be able to play from other places, able to upload files, etc.
Let the user decide.
Note: If you have that "easy onboarding" option, then if there is any kind of abuse possible of your system (using it to host file uploads, etc,) then that's what the bad people will use, so be sure to take that into consideration!

Are they (the majority of them) using SQL injections to do this?


There are about three attack vectors:

1) SQL injection, or other hosted-software vulnerability (WordPress, Drupal, ImageMagic, etc.) This generally gives you database dumps and perhaps admin interface access to the site.

2) Host vulnerability (Heartbleed, etc) This generally gives you command-line access to the site, which you can use to discover databases that you can then dump, insert payloads in hosted pages, etc.

3) Social engineering ("I am Robert, the County Password Inspector!") This generally gives you some kind of employee access to the site from the command line, again.

The question, then, is what the bad guys are after. If you store credit card details, absolutely that! If not, perhaps a list of emails and passwords to try on other sites. Or perhaps just another box they can run DDoS, email spam, and fradulent web sites from.
If you keep your development code on another system, with tight security, and use good source control, and good automated deployment methodology, you will minimize the impact from most such events, once you can detect that they occurred.
Wipe the hard disk, re-deploy to new OS image, restart servers; done!
enum Bool { True, False, FileNotFound };
Advertisement

This is true, but there is no better solution :-(
Well, you can have players purchase a cryptographic token from you, but that's not a low-friction onboarding experience :-)

I also once witnessed how forum userdata was compromised:

Someone was able to sneak into the backend of the server and install some sort of password-logger which recorded all typed in passwords of users. (they probably also had access to the database but wanted to bypass the hashed passwords...)

Stuff like this makes me really paranoid and scared in letting my website handle sensitive data.

I might stick with the current system and hope that no one is going to attempt figuring out how that stuff works...

One option is to start there, and then give the user the option of signing in with a Steam ID if they want to be able to play from other places, able to upload files, etc.
Let the user decide.
Note: If you have that "easy onboarding" option, then if there is any kind of abuse possible of your system (using it to host file uploads, etc,) then that's what the bad people will use, so be sure to take that into consideration!

I only allow hosting of specific game binarys (map files) which were generated by the game. I additionally check (on the serverside) if the content of the file is an actual valid mapfile for the game. If not, the file gets rejected. (This should be enough to make this somewhat secure. Am i right?)

1) SQL injection, or other hosted-software vulnerability (WordPress, Drupal, ImageMagic, etc.) This generally gives you database dumps and perhaps admin interface access to the site.

2) Host vulnerability (Heartbleed, etc) This generally gives you command-line access to the site, which you can use to discover databases that you can then dump, insert payloads in hosted pages, etc.

3) Social engineering ("I am Robert, the County Password Inspector!") This generally gives you some kind of employee access to the site from the command line, again.

I don't have that much experience in security practices for web development. (if at all.)

I know that SQL injections can be prevented by using prepared statements. (Don't know if filtering characters/SQL expressions is nessecary after using prepared statements.)

Host vulnerability... i'll look into that.

Social engineering... i'll have to make sure that people know that admins don't ask for passwords or sensible data. (Displaying that info at the login screen should be enough.)

The question, then, is what the bad guys are after. If you store credit card details, absolutely that! If not, perhaps a list of emails and passwords to try on other sites. Or perhaps just another box they can run DDoS, email spam, and fradulent web sites from.
If you keep your development code on another system, with tight security, and use good source control, and good automated deployment methodology, you will minimize the impact from most such events, once you can detect that they occurred.
Wipe the hard disk, re-deploy to new OS image, restart servers; done!

Well, the only cricitcal information which i would store is the (public) steam-ID and (maybe) the last login date. (If we ignore the password.)

Besides that there will be only the uploaded mapfiles and player statistics.

If i use an email/username/password registration, then the passwords and the emails would be a potential target. The steam login would also be a potential target.

I'm just thinking... is it "ok" to assume that due to a lack of "lucrative" userdata that no one (or at least fewer "hackers") is really going to attempt to break into that system?

(I'm sure some people are going to attempt that just for fun...)

If that's the case the whole "masterkey in the client (which is only used to reset passwords/keys/tokens)" method might not be a bad idea (in this circumstances)? (Or am i totally wrong here with my assumptions?).

If so, i might be using this system and (as you previously said) switch/extend to an alternative login solution (like steam login) if it's needed.

The easiest solution for mapsharing would be to just use steams workshop (which would be nice as i wouldn't need to worry about all that stuff) but i wanted to provide statistics (leaderboards, experience points, etc...) which would also be determined by player created custom maps. In order to calculate those statistics i need to have access to the server backend (with access to all uploaded mapfiles) which simply isn't possible with steams workshop,

Sorry for the convoluted questions. Trying to cover the ground as much as possible.

I also once witnessed how forum userdata was compromised:
Someone was able to sneak into the backend of the server and install some sort of password-logger which recorded all typed in passwords of users. (they probably also had access to the database but wanted to bypass the hashed passwords...)


If someone gets physical access to your server then you're pretty much out of options. Luckily that's astronomically unlikely to happen these days, with someone else holding your physical server for you.

I know that SQL injections can be prevented by using prepared statements. (Don't know if filtering characters/SQL expressions is nessecary after using prepared statements.)


No, prepared statements handle the syntax for you. The problems arise when you start trying to construct SQL queries out of sticking strings together, so don't do that.

If i use an email/username/password registration, then the passwords and the emails would be a potential target. The steam login would also be a potential target.

I'm just thinking... is it "ok" to assume that due to a lack of "lucrative" userdata that no one (or at least fewer "hackers") is really going to attempt to break into that system?


Live email addresses are a lucrative target, but it's proportional to how many you have.

If that's the case the whole "masterkey in the client (which is only used to reset passwords/keys/tokens)" method might not be a bad idea (in this circumstances)?


I don't entirely understand the whole masterkey system you have, but it seems a bit overengineered for the purpose it serves. Either way, you can't say it uses a 'private' key if that key is distributed in the client.

If you want to confirm that the user is a Steam user, and that they are authorised to use a given Steam User ID, you need to ask Steam for that information, i.e. presumably by having the client auth with Steamworks and give that information to you at password-reset-time.

Beyond that, a limited-time password reset token is about as good as it gets. Remember that almost all consumer-level authentication ultimately breaks down to "does the person currently have read access to the email account stored in this account's details" and there's not much you can do to improve on that without imposing a significant usability cost.

As long as you build the system such that it is OK if a bad guy reads all the source code, you should be fine.
The security oerhaps encrypting database dataf the system comes down to the keys/passwords used to terminate SSL and connecting to the system for admin purposes.
As long as those keys are safe, and you patch your OS frequently, you should be fine.

Is it "OK" to rely on the secutity you can build? What options do you have? Everyone who runs an online system does this.
enum Bool { True, False, FileNotFound };

I don't entirely understand the whole masterkey system you have, but it seems a bit overengineered for the purpose it serves. Either way, you can't say it uses a 'private' key if that key is distributed in the client.

Well, basically i wanted players to communicate with my server (in order to send and synchronize statistics) without forcing them to register on the server.

Additionally i wanted to allow players to "login" on the website (with some sort of validation) without registration. (So that they can look up their stats or even upload custom levels/mapfiles for others to download.)

My idea was the following:

Players should recieve a password which was generated on the server-side once they connect to it for the first time. (This password is then used to login on the game client as well on the website by inputting the steamID + the recieved password.)

Now the question is how to generate passwords for players without using some sort of email/regstration process on the website (due to the mentioned security risks of this data getting compromised.)

My current idea was to store a secret key in the application as well as on the server.

The Communication process looks like this:

1. Game Client requests a new password from the server

2. Server generates a random token and sends this one to the client

2. Client Sends his steamID alsongside with a hash which is generated Like this: Sha128(steamID+token+secretKey)

3. Server recieves this Information and performs the same hashing operation. If the hash is exactly the same as recieved from the client then generate a new player password and send it back to the client. If not, throw an error. (and delete the token on the serverside so that a new one will be generated at the next attempt.)

This password can then be used to login via the website or to login from game clients.

The problem is that once someone figures out what the secret key is, the whole systems falls apart. (As people could just request new passwords for other players accounts.)

This secret key is NOT used for any kind of admin logins/verification on the database/website. It's only used for generating new passwords for players.

I know that there are other security vulnerabilities (not using HTTPS or SSL as the networking functions of the game engine which i'm using do not support that at all.)

That's the reason why i don't want to store any kind of personal data (like emails or user entered passwords on there). This way, if someone manages to break in into the server, no personal user data will be stolen (as no user data is stored there in the first place.)

The game accounts themselves are only used to store player statistics and potentially user created mapfiles for the game. (No critical information as this system would be faaaar to insecure for that.)

But i wanted to create a system on which players can login on the website and authentificate themselves without them having to worry about that someone just enters their player ID on the website and manages to login into their account.

As i said, my intention is to make sure that even if someone manages to break into the server (by hacking or somehow getting my admin password for backend access), no critical user data gets compromised so that players don't have to worry about stolen passwords / compromised email addresses or that someone was able to get their steam-password (while logging in via steam OpenID) by using a man in the middle-attack or anything like that.

As long as you build the system such that it is OK if a bad guy reads all the source code, you should be fine.
The security oerhaps encrypting database dataf the system comes down to the keys/passwords used to terminate SSL and connecting to the system for admin purposes.
As long as those keys are safe, and you patch your OS frequently, you should be fine.

Those keys aren't used for any kind of admin login. (So they can't get access to the server backend by figuring out the "secret key" stored inside the client.)

However, it would be possible to login into other players accounts if this key is figured out.

Admin/server backend access isn't exposed to the game client nor the website.

I suppose that i just have to weight out the pros/cons of this system and then decide if the insecure player login is worth the additional features (leaderboard stats and content sharing).

/Edit: Is something like that even acceptable for a commercially sold game?

This topic is closed to new replies.

Advertisement