简体   繁体   中英

Client to Server Authentication in C++ using sockets

I'm implementing a login/authentication system for my little server-client program. I'm wondering how to go about this, and I was hoping to get some great tips/advice from Stack Overflow as always. This is how I imagine I'll do it.

  • Client connects to the server.
  • Server sends a 'token' to the Client (based on time probably and whatever)
  • Client returns the username and a sha1 encrypted password, along with the token.
  • Server receives them and authenticates the user to the credentials in the server-side database.
  • The token is now verified and the user is signed in with the token.

Is this at all a secure way of doing it? I figured the client also sends a serial key or some such to form a serial / token pair, so that another client cannot fake the same token (though the token is generated by the server-side).

Implementation details aren't required, as I am capable of doing the implementation.

My question would, rather, two questions:

  • What ways are there to achieve a login/authentication system with sockets
  • What ways are there to secure my client-to-server connection
  • EDIT : I forgot to ask, as this is a C++ question, are there any libraries that can assist in encryption/authentication?

Security is an issue for me, so I want to be sure I do it right.

Maybe some background information. It's a game server, a person logs in with his account and is taken to a 'Lobby', where he can pick a 'World Server' to play on. The world server is a separate process running (possibly) on a different machine in the same network.

For that reason, I want to have a concept of a session in this, the user logs in and a session is generated, the login server relays the session to the world server the user picks, so that world server knows that the user is actually logged in.

I reckon the client will have to confirm the session to the world server and all that, but I'll worry about that later.

Sincerely, Jesse

You generally do not want to send the password over the link at all, not even with encryption. The usual method is a challenge-response protocol.

  1. The client connects to the server, sending in the user-name (but not password)
  2. The server responds by sending out unique random number
  3. The client encrypts that random number using the hash of their password as the key
  4. The client sends the encrypted random number to the server
  5. The server encrypts the random number with the correct hash of the user's password
  6. The server compares the two encrypted random numbers

This has a couple of advantages. First, it means the password never goes over the link in any form. Second, it's immune to a replay attack -- if an attacker records the conversation, they can't replay the client's replies later to log in, because the random number will have changed.

Securing the connection (ie, encrypting the content) is a little simpler. Typically, one of the two (doesn't really matter much which) picks a random number, encrypts it with the other's public key, and sends it to the other. The other decrypts it, and they encrypt the rest of the session using that as a key for symmetric encryption.

Libraries: Beecrypt and OpenSSL are a couple of obvious ones. Unless you have a fairly specific reason to do otherwise, TLS is what you probably want to use (it does quite a bit more than what I've outlined above, including two-way authentication, so not only does the server know who the client is, but the client also knows who the server is, so it's reasonably verified that it's not connected to somebody else who might just collect his credit card number and run with it).

Edit:

To authenticate each packet without the overhead of encrypting everything, you could do something like this:

  1. The server sends its public key with the challenge
  2. The client generates a random number, encrypts it with the server's public key, and sends it back with its response
  3. The number is the first number used for counter-mode encryption
  4. The client includes one counter-mode result with each packet it sends

Counter mode means you just generate consecutive numbers, and encrypt each in turn, using the right key. In this case, the key would be the hash of the client's password. What this means is that each packet will contain a unique random number that both the client and the server can generate, but nobody else can. By using the counter-mode encryption, each packet will have a unique random number. By starting from a random number, each session will have a unique sequence of random numbers.

To minimize overhead, you could send just a part of the result with each packet -- eg, if you use AES in counter mode, it'll generate 16 bytes of result for each number you encrypt. Include only (say) two bytes of that with each packet, so you only have to encrypt a number once every 8 packets. In theory, this cuts security -- an attacker could just try all 65536 possible values for a packet, but if you assume the connection has been compromised after (say) two bad attempts, the chances of an attacker getting the right value become pretty small (and, of course, you can pretty much pick the chances you're willing to live with by controlling the number of bad attempts you allow and the size of authentication you include in each packet).

If security is a big issue for you, don't roll your own. You want a secure socket library. Something like OpenSSL .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM