13

I am writing a multiplayer game. I have a central server which processes everything. For data exchange I use HTTPS protocol. Because this is a game I cannot use computationally expensive systems like RSA for data transfer.

To login,

  1. Client uses sha512 to produce hexadecimal hash from password and random seed.
  2. Client sends "login" request with username, hash and seed to the server.
  3. Server checks if user has not attempted too many login requests and checks whether the password hash matches the hash made from the password in the database. If it does, it sends an access_key and a response that login was successful

To send requests which require login,

  1. Client sends a hash generated from the access_key and seed along with the request data.
  2. Server checks whether the IP has not changed and whether the hash made from access_key and seed is correct. If it is, new access_key is generated from the old one, request data is processed and the server returns the new access_key along with the response from the request.

At any time, if client's IP changes or invalid access_key is sent, the session is automatically terminated.

How secure is this approach? What can I do to improve it?

Mike Ounsworth
  • 57,707
  • 21
  • 150
  • 207
Mirac7
  • 411
  • 4
  • 8
  • 8
    I have this general rule (which I think is pretty standard) that if anyone has direct access to the executable version of your software just assume they have your sourcecode for that application. In this case, because you hash your password on the client I would assume any attacker will know the algorithm you use, the method of generating seed/salt (I feel like you mean salt when you say seed but I could be wrong). None of this is necessarily a bad thing however if you have any flaws in implementation an attacker will know about it as opposed to hiding it a little better on the server. – d0nut Jan 05 '16 at 15:48
  • 1
    Not that I'm advocating security through obfuscation but it doesn't hurt to reduce the knowledge the attacker has :p – d0nut Jan 05 '16 at 15:49
  • 18
    I'm a bit confused as to why a game would need a secure data exchange system that goes beyond that used in e-commerce and banking applications (which just sends username and password to the site over HTTPS, then uses session tokens or two-factor authentication for the extra security layer). Have a proper security certificate, use HTTPS for sending username and password at first, move on with your game. And the IP thing won't help you much, they can change at any time: http://stackoverflow.com/questions/7550798/can-ip-change-during-session – BrianH Jan 05 '16 at 17:00
  • Every package has its own access key? This would mean that the connection would be terminated in case of package loss or isnt it? – BlueWizard Jan 05 '16 at 20:04
  • 2
    @BrianDHall: There can be [legitimate reasons to spend effort on game security](http://security.stackexchange.com/questions/106896/why-is-steam-so-insistent-on-security). Games may not usually be high-value targets (although some can be), but they're definitely *popular* targets for attacks. – Ilmari Karonen Jan 05 '16 at 22:58
  • As a rule of thumb, don't roll your own security protocol. What kind of devices do you target with your game? I highly doubt, that it's to weak to do a little RSA for key exchange and AES (or at worst RC4) to encrypt data. – David Foerster Jan 05 '16 at 23:24
  • If you're not using real-time streaming UDP, then use OAuth. If you *are* using UDP, then use a standardized HMAC, which will do essentially what you're trying to invent. – chrylis -cautiouslyoptimistic- Jan 06 '16 at 01:35
  • @BrianDHall A lot of (but not all) e-commerce and banking applications actually have *less* security than is technically possible, because they rely on the legal system to make up the difference. – user253751 Jan 06 '16 at 04:42
  • *I use HTTPS* ... *Can't use RSA*... Hmmmm... – Luke Park Jan 06 '16 at 11:51
  • 1
    `if client's IP changes` Don't do that, you game cannot be reliable played at schools/other large places and at homes where a ipv6 connection is in use connection – Ferrybig Jan 06 '16 at 14:18
  • @ferrybig - If your IP changes mid-game, you're probably going to end up being disconnected anyway. – Bobson Jan 06 '16 at 16:25

2 Answers2

28

First of, crypto is hard, and you shouldn't create your own.

Vulnerabilities

Your login seems to suffer from a pass the hash vulnerability. An attacker doesn't need to crack the hash to login, they can just pass the hash, and will be logged in. This defeats the purpose of hashing the password in the first place.

sha512 is not recommended for storing passwords, as it's way too fast. Use something like bcrypt instead.

HTTPS and Encryption

You say that RSA is too expensive. But generally, RSA is only used to exchange a key, which is then used with a much less expensive private key cryptosystem.

As you clarified that you do use HTTPS, it should be noted that you do already use RSA. HTTPS uses RSA or diffie hellman for key exchange and some block or stream cipher for the actual data encryption.

As you use HTTPS, you already have data confidentiality and integrity (and server authentication and optionally client authentication), there is no need for additional encryption on the application level.

Advantages of your scheme?

Your scheme doesn't really seem to serve any purpose. You already are secure from eavesdropping and data tampering via HTTPS (and your scheme wouldn't have prevented it anyways).

So your scheme doesn't seem to be about data exchange so much, as it is about authentication.

Generally, authentication is handled like this:

Login:

  • Client sends username and password (plain)
  • Server hashes password, and compares hash against hash in db
  • Server sends session id back

Other Requests:

  • Client sends session id
  • Server validates session id
  • (optional) when session state changes, server regenerates session id

Your approach is similar, but did introduce the pass the hash vulnerability, and contains a seed, which seems to be unnecessary and thus only complicates the scheme. It also regenerates the session id on each request, which isn't really needed and only seems to cause unnecessary overhead.

tim
  • 29,018
  • 7
  • 95
  • 119
  • I use HTTPS for *all* data exchange – Mirac7 Jan 05 '16 at 16:04
  • 11
    @Mirac7 That's good. That only leaves the **pass-the-hash attack**, and the **weak hashing** (both of which are serious issues). But what exactly are you then trying to achieve with your scheme? You already have confidentiality and integrity (and server authentication and optionally client authentication). Why not go with the normal approach here? (login: client sends user+password, server checks and sends session id; other requests: client sends session id, server checks; when session state changes, regenerate session id) Whatever language or framework you use, it should already support this. – tim Jan 05 '16 at 16:12
  • @Mirac7 tim is definitely right here. If hashing is done serverside then pass-the-hash shouldn't be an issue (if i'm not mistaken; right, tim?) – d0nut Jan 05 '16 at 17:36
  • 1
    @iismathwizard exactly, the password should be hashed server-side and then compared to a stored hash. That way, an attacker that did get access to the database cannot log in with the stored password (except if they manage to crack the hashes). – tim Jan 05 '16 at 17:55
  • 1
    Hashing the password clientside protects the password from the server. So even if someone gets to sniff traffic [where TLS is added and removed](https://i.imgur.com/4p9oMTp.jpg) it's harder to use the sniffed passwords in other places (as [password reusing](https://xkcd.com/792/ "well...") is quite common). Of course server-side hashing is still important. – Gustavo Rodrigues Jan 06 '16 at 12:56
  • 1
    @GustavoRodrigues that's a good point. Of course, using sha512 defeats that purpose as well, and removing ssl doesn't sound like a great idea, but it sounds like a good approach as defense in depth, and does help in case the server is compromised and the attacker logs the traffic in the hopes of getting plaintext passwords. So what you would do is: client: sends hashed password; server: hashes hashed password and compares it to stored hash of hashed password? Sounds like a good idea. – tim Jan 06 '16 at 13:02
16

... Client sends "login" request with username, hash and seed to the server.

Since the seed is created by the client, the combination of seed and hash effectively form a password equivalent which can be replayed again and again. You are probably trying to implement something similar to Digest Authentication here. But with digest authentication the nonce (i.e. your "seed") is determined by the server and not by the client and thus safe against replay attacks.

Apart from that: you are already using HTTPS which protects the traffic against sniffing and modification. Why build another security mechanism on top of it? Digest authentication is usually used for connections which are not encrypted and has the problem that you need to have the password in clear (or equivalent) at the server. If the connection is already protected against sniffing you don't need extra protection for the password and can send it in clear. This has the advantage that you can store the password then as an irreversible hash at the server.

Steffen Ullrich
  • 184,332
  • 29
  • 363
  • 424
  • So should I remove this entire procedure and I can assume that no attacks are likely to be successful? – Mirac7 Jan 05 '16 at 16:05
  • 7
    @Mirac7: If you use https **properly** then you don't have to worry about sniffing and thus don't need to protect the data you transfer additionally – Steffen Ullrich Jan 05 '16 at 16:24
  • @Mirac7 In case it isn't obvious, the same principle of "password equivalence" applies to the hashed session key you're generating. There's not much point in changing the key after every single request if you trust your implementation of SSL. Changing the key after every request is going to have a scalability cost as well, and it adds complexity to the protocol with no clear benefit. – Steve Sether Jan 05 '16 at 16:46
  • @SteffenUllrich What does *properly* actually entail? – Mirac7 Jan 05 '16 at 17:20
  • 2
    @Mirac7: Don't disable validation of certificate and hostname and better use certificate pinning. Alternatively expect a single fixed certificate from the server (which can also be self-signed). – Steffen Ullrich Jan 05 '16 at 17:25
  • I too was confused - if you're already using HTTPS, where's the problem? – corsiKa Jan 05 '16 at 18:23