Using game network login as secure auth for cloud data

Hi guys.

I’m looking for a good way to let users log in and save game data to the cloud. My game already uses Google Play Games Services (https://docs.coronalabs.com/plugin/gameNetwork-google/) for leaderboards and achievements, and I’d like to piggyback on that so the player doesn’t need to supply a password and create an account within my game. In other words, I’d like to create a row in my cloud database’s Users table that is linked to the player’s Google Play ID, a 21 digit integer returned by gameNetwork.request(“login” … )

That part’s straightforward, but I’m concerned about security. I only want that row in the cloud database to be accessible to a player who is genuinely logged into Google Play using that ID. If the only thing linking that row to the real user is that ID, then anyone who knows my ID (and I don’t think they’re secret) could spoof a request to the server and read/write my data. 

The only way I can think to prevent this is ask the user to create a PIN or password within the game when they first save data to the cloud. And then if they ever change phones and need to access that cloud data, they’d need to reenter that PIN. But that’s a crummy user experience – players will forget their PIN, or just never enter one to begin with.

This must be a problem that others have solved: I’ve played plenty of games where the only thing I logged into was Google, and my whole user profile was available on multiple devices. 

Thanks!

Hi aaronkarp,

What BaaS do you use, or do you run your own? You’ll need to have a “secret” key within your app, and/or adopt a secure request method, so only a process within your app can make the request, even with the Google ID.

If you provide more information, you could get a more specific answer.

Thanks Aidan. I’m currently using Parse, and evaluating alternatives (in particular, Coronium and Firebase). My game is not yet released.

Embedding a secret key with the app doesn’t seem like a secure approach. Anyone who cared to could pry it out* and run amok with it.

*APKs are just ZIP files, and as far as I can tell, the strings all get preserved in plain text after the Corona build process. If I rename my .apk to .zip and extract the contents, open /assets/resources.car in a text editor, and search for my Parse API Key, it’s right there, barely obscured. I don’t believe it’s a good practice to embed a secret key in any client. The only safe place for a secret key is on the server. That’s why Parse issues separate “client keys” (i.e. public keys) and “master keys” (i.e. secret keys). 

Looks like Facebook login is on the roadmap for Coronium 2. I realize that isn’t GPGS, but IMO Facebook is a better auth method than pretty much anything else, just based on ubiquity.

https://forums.coronalabs.com/topic/61635-coronium-2-wish-list-and-use-case-needs/

Every app has a secret key somewhere in their code and there’s many steps you can take to protect your backend.

  1. Obscure your key - generate it with code, require filtering with a complex in-app algorithm, anything to slow the breach.

  2. Require specific information for a request to be authorized (sessionToken, timestamp)

  3. Set up a security funnel so you can rate limit requests and so on, Parse does a lot of this for you.

  4. If you are breached, generate new key, push out update.

  5. Keep track of bad requests, could be a sign someone is messing around with your binary.

Any method is better than a publically readable and writable backend.

Thanks guys. I think Alex is getting to the heart of the matter, which is that I want GPGS to behave like a full fledged login/account system, akin to Facebook or Google Sign In. I want it to return some sort of auth token when the user signs in that’s more secure/unguessable than just the player ID. Something that’s unique to the player-game combo.  If the game client can only send me a player ID, there’s no way for me to verify that the user *actually* logged into Google. 

I could take the player ID and hash it into a password using some obfuscated, hard to reverse-engineer process, like what Aiden is suggesting for a secret key. That would require an attacker to figure out the hashing algorithm from the code in order to impersonate another user. That’s a lot better than nothing, but still vulnerable. Maybe fine for a game, but I wouldn’t take that approach for a more sensitive app.

(N.B. I think the discussion about secret keys in apps is interesting but not essential to resolving this question.)

Following up here, it looks like there is a way to get the auth token in the native android GMS client, so if you’re an enterprise customer you could presumably use this value to properly authenticate users on the server side. I am not an enterprise customer and haven’t tried.

https://developers.google.com/android/reference/com/google/android/gms/games/Games.GetTokenResult.html#public-methods

Hi aaronkarp,

What BaaS do you use, or do you run your own? You’ll need to have a “secret” key within your app, and/or adopt a secure request method, so only a process within your app can make the request, even with the Google ID.

If you provide more information, you could get a more specific answer.

Thanks Aidan. I’m currently using Parse, and evaluating alternatives (in particular, Coronium and Firebase). My game is not yet released.

Embedding a secret key with the app doesn’t seem like a secure approach. Anyone who cared to could pry it out* and run amok with it.

*APKs are just ZIP files, and as far as I can tell, the strings all get preserved in plain text after the Corona build process. If I rename my .apk to .zip and extract the contents, open /assets/resources.car in a text editor, and search for my Parse API Key, it’s right there, barely obscured. I don’t believe it’s a good practice to embed a secret key in any client. The only safe place for a secret key is on the server. That’s why Parse issues separate “client keys” (i.e. public keys) and “master keys” (i.e. secret keys). 

Looks like Facebook login is on the roadmap for Coronium 2. I realize that isn’t GPGS, but IMO Facebook is a better auth method than pretty much anything else, just based on ubiquity.

https://forums.coronalabs.com/topic/61635-coronium-2-wish-list-and-use-case-needs/

Every app has a secret key somewhere in their code and there’s many steps you can take to protect your backend.

  1. Obscure your key - generate it with code, require filtering with a complex in-app algorithm, anything to slow the breach.

  2. Require specific information for a request to be authorized (sessionToken, timestamp)

  3. Set up a security funnel so you can rate limit requests and so on, Parse does a lot of this for you.

  4. If you are breached, generate new key, push out update.

  5. Keep track of bad requests, could be a sign someone is messing around with your binary.

Any method is better than a publically readable and writable backend.

Thanks guys. I think Alex is getting to the heart of the matter, which is that I want GPGS to behave like a full fledged login/account system, akin to Facebook or Google Sign In. I want it to return some sort of auth token when the user signs in that’s more secure/unguessable than just the player ID. Something that’s unique to the player-game combo.  If the game client can only send me a player ID, there’s no way for me to verify that the user *actually* logged into Google. 

I could take the player ID and hash it into a password using some obfuscated, hard to reverse-engineer process, like what Aiden is suggesting for a secret key. That would require an attacker to figure out the hashing algorithm from the code in order to impersonate another user. That’s a lot better than nothing, but still vulnerable. Maybe fine for a game, but I wouldn’t take that approach for a more sensitive app.

(N.B. I think the discussion about secret keys in apps is interesting but not essential to resolving this question.)

Following up here, it looks like there is a way to get the auth token in the native android GMS client, so if you’re an enterprise customer you could presumably use this value to properly authenticate users on the server side. I am not an enterprise customer and haven’t tried.

https://developers.google.com/android/reference/com/google/android/gms/games/Games.GetTokenResult.html#public-methods