Advertisement

User login system for mobile.

Started by July 20, 2017 08:16 AM
11 comments, last by hplus0603 7 years, 3 months ago

I want to reverse engineer what most mobile multiplayer games do with there login system and with that I mean the user is able to start to play immediately with a guest account and can later fill in a name and link with Google, Facebook or email/password. I think I need the following steps the moment the user presses "play immediately".

 

  • Create a unique user name, something like guestXXXX and a password.
  • Store Username and password locally. Encrypt password locally.
  • Store the username and password in the database. Encrypt password with a unique salt.

Now when the player boots up the game again he will skip the login step since there are local credentials. The only problem I see here is when the user does not register an email, his own password or links with a social media account he will lose his account once he loses his local credentials, most likely with an uninstall. But I think it's very good to have the user play first before he commits with yet another username and password or link with Facebook. I can always throw in a warning when an account is not linked every now and then and give a small bonus when the user links it.

Am I forgetting something here? Are there other proven methods so the player can get engaged immediately?

 

  • You don't strictly need to generate a password, since you can issue the user with an authentication token - just like when you return to a website after having logged in before, the cookie can get you in without it needing to contain the password.
  • You don't 'encrypt' passwords with a salt - to encrypt means there is the possibility of decryption. You'd be hashing the passwords which is a one-way operation (or rather, using a key derivation algorithm, before the crypto folks complain about my terminology. It's important you don't just use any old hash algorithm. Ideal choices are currently Argon2, PBKDF2, or scrypt.)

Beyond that, I don't think there's anything you're missing (apart from the possibility of playing without an account at all, but I'm assuming that's not practical here).

Advertisement
3 hours ago, Kylotan said:
  • You don't strictly need to generate a password, since you can issue the user with an authentication token - just like when you return to a website after having logged in before, the cookie can get you in without it needing to contain the password.
  • You don't 'encrypt' passwords with a salt - to encrypt means there is the possibility of decryption. You'd be hashing the passwords which is a one-way operation (or rather, using a key derivation algorithm, before the crypto folks complain about my terminology. It's important you don't just use any old hash algorithm. Ideal choices are currently Argon2, PBKDF2, or scrypt.)

Beyond that, I don't think there's anything you're missing (apart from the possibility of playing without an account at all, but I'm assuming that's not practical here).

Could you elaborate on an authentication token? Wouldn't that be the same as a password? The issue is the user need to be able to return to his account after he re-installs the game. If I would store the token locally it won't be available on a different device.

And yes I meant hashing, should get that terminology right but I did use hashes for a website a couple of years ago. Any idea on what to use with Java? I understand that securing users credentials is important since most of them use the same password for everything.

But using a password like this I need to store it locally as well to automatically sign in. So I think I do need to encrypt it locally and then decrypt it on the server where I will check the password+salt vs the hash.

An authentication token is a client-side object that shows that the client is who they claim to be. The best example here is a browser cookie - once a user logs in, they might get a cookie that contains a user ID and an expiry time. If they supply that cookie, you know that they logged in previously (via password, or whatever). You normally would also cryptographically sign the cookie using a server-side secret key so that it's impractical for a user to forge one. This is sometimes called digital signatures.

Whether you use a token or a password, if you store it locally, they won't be able to access it on a different device anyway. The problem is exactly the same. Traditionally we use passwords because they're something a user can know (as opposed to something a user has, or something a user is) and therefore they do not need to be stored anywhere, but when you randomly generate them, that's out of the window. Storing it locally changes it to something the user has, but then you have to ensure they don't lose it; which is out of your control.

One major advantage of using a token is that you don't ever need to store any passwords locally, and therefore you won't have jeopardised the user's security if their device is stolen or otherwise wrongly accessed. When transmitting passwords that have been entered by the user, you should not be encrypting that yourself - use a tried-and-tested protocol like HTTPS to do that for you.

Kylotan is right: You don't want to store the password itself on the client.

Instead, have a table on the server of "userid -> issuetime -> issueip -> token" which stores strong-random tokens (256 bit.) Presenting this token to the server will serve as authorization, until the token is revoked (by being deleted from the table.) Separately, store the bcrypt() or scrypt() of the password with salt on the server. issuetime is useful to expire very old tokens (your protocol may detect tokens that will expire in the future and issue a newer token;) issueip is useful for logging purposes to ferret out the russian/philipines/egyptian/whatever-it-is-today sock puppet spammer rings.

I would probably not generate any of those things on the client, because the client still needs to upload the data to the servers, and the client can't know what names are unique; instead, I would have a service on the server which is "play now" and generates a unique name (the server knows this; the client can't!) and password and authorization token, and returns the needed data to the client. You could also take this opportunity to set a cookie on the client with the appropriate username (and perhaps token, too) assuming you use the clients' web stack to connect to the server.

You probably want to also design the tutorial such that the user has a little bit of fun, then pops up a dialog saying "to get your 100 free gems, enter an email address or phone number, and we will send you your reward code so you can keep playing!" Don't actually send the password in email/SMS; instead just use the email/SMS to support a traditional password reset flow.

Finally, while "guest1234" is straightforward and somewhat traditional, I prefer auto-generated names like "BlueAppleDampPony" but that's just me :-)

 

enum Bool { True, False, FileNotFound };

Mobile platforms generally already supply the basic information to make this work. For example, iOS provides a vendor-specific identifier, which will uniquely identify the user's device to you.

You'll need to provide an additional mechanism for when the user wants to migrate to a new iOS device, but iOS has you covered there too - if you stash a UUID token in the keychain, Apple will sync it to their new device transparently.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

Advertisement

Users also migrate between device families (I used to have a iPhone 6+, now I have a OnePlus 3T).

Users also use multiple modes (I watch Netflix on PlayStation, laptop, phone, and media PC).

Users may also use iCloud, or Dropbox, or OneDrive, or some other such mechanism on their computers.

So, yes, the mobile platforms have things that can help a little bit. Similarly, the platforms also already have logins/accounts! You can use the Google account, or the iTunes account, as an identifier, even without using a specific device. It all depends on what your specific use cases are, and what kind of permissions/dialogs you want to have your user accept before using the app.

enum Bool { True, False, FileNotFound };

Ok, that makes a lot of sense. When the user loses his token he will be presented with the login screen again and if he registered/linked his previous account he can get his token back otherwise he has to create another guest account.

How does this token look? Is it just a "long" random char field that does not have to be unique since the username is already unique? And does this need to be encrypted or can I just store it locally in a obvious user settings file?

How does this token look? Is it just a "long" random char field that does not have to be unique since the username is already unique? 

There are two kinds of tokens:

1) A long, random, string, which you use as a primary key on the server to look up user ID, expiration date, and so forth. A good way to generate this is to generate 32 bytes of random data (using /dev/urandom, or CryptGenRandom) and then encoding as base64 or base85, so that it consists of entirely printable ASCII characters.

2) A token that consists of some "real" data and a signature. For example, the token could be "version:userid:generatedtime:signature" where "signature" is computed as HMAC(version:userid:generatedtime, secret-key) and only your servers know the secret-key. Your servers can then verify this token by looking at the generated time, making sure it's in range, and then verifying the signature. The signature is likely using SHA256 and encoded similar to how you'd encode the long random string in the other case. You'd use "version" to be able to add more data in a compatible way later, or to update the private secret every so often if you fear it leaking out.

The benefit of 2) is that it doesn't require a database lookup to generate or validate. The benefit of 1) is that it's simpler, and there's no private secret to share on your servers (and that someone could steal.)

does this need to be encrypted or can I just store it locally in a obvious user settings file

These tokens are very similar to session cookies, stored by web sites when you log in. Web browsers used to store cookies in plain files on the user's hard disk. I think that with "browser sync," the mechanism is a little more involved these days, but in principle, if someone can already infect your computer to the point where they can read your files, you can't protect against them anyway, so encrypting on the local machine is probably not necessary.

enum Bool { True, False, FileNotFound };

Have you thought about just using an API for this? Amazon has Cognito (OK) and Google has Firebase (better), and then there's GameSparks (GREAT, if their platform is a good fit for you).

Authentication is a lot more complicated than you might think, especially doing it in a proven & secure way.

Drew

FTA, my 2D futuristic action MMORPG

This topic is closed to new replies.

Advertisement