Authentification Client à serveur en C++ en utilisant des sockets

j'implémente un système de login / authentification pour mon petit programme serveur-client. Je me demande comment faire, et j'espérais obtenir quelques bons conseils / conseils de débordement de pile comme toujours. C'est comme ça que j'imagine que je vais le faire.

  • le Client se connecte au serveur.
  • le serveur envoie un' token ' au Client (basé sur le temps probablement et n'importe quoi)
  • le Client renvoie le nom d'utilisateur et un mot de passe crypté sha1, ainsi que le jeton.
  • le serveur les reçoit et authentifie l'utilisateur aux informations d'identification dans la base de données côté serveur.
  • Le jeton est maintenant vérifié et que l'utilisateur est connecté avec le jeton.

est-ce une façon sûre de le faire? J'ai pensé que le client envoie aussi une clé série ou une autre pour former une paire série / token, de sorte qu'un autre client ne puisse pas simuler le même token (bien que le token soit généré par le côté serveur).

mise en Œuvre les détails ne sont pas nécessaires, car je suis capable de faire la mise en œuvre.

Ma question serait, plutôt, deux questions:

  • comment réaliser un système de login/authentification avec sockets
  • Comment sécuriser ma connexion client-serveur
  • EDIT: j'ai oublié de demander, comme c'est une question C++, y a-t-il des bibliothèques qui peuvent aider au cryptage/authentification?

la Sécurité est un pour moi, donc je veux être sûr de le faire correctement.

peut-être quelques informations générales. C'est un serveur de jeux, une personne se connecte avec son compte et est emmené dans un "Lobby", où il peut choisir un "serveur mondial" pour jouer. Le serveur mondial est un processus séparé tournant (éventuellement) sur une machine différente dans le même réseau.

pour cette raison, je veux avoir un concept de session dans ceci, l'utilisateur se connecte et une session est générée, le serveur de connexion relaie la session à le monde serveur, l'utilisateur choisit, de sorte que le monde de serveur sait que l'utilisateur est connecté.

je pense que le client devra confirmer la session au serveur mondial et tout ça, mais je m'en occuperai plus tard.

sincèrement, Jesse

20
demandé sur Jesse Brands 2012-07-20 18:01:51

2 réponses

Vous n'avez généralement pas vous voulez envoyer le mot de passe sur le lien, pas même avec le cryptage. La méthode habituelle est un protocole défi-réponse.

  1. Le client se connecte au serveur, l'envoi du nom d'utilisateur (mais pas mot de passe)
  2. le serveur répond en envoyant un nombre aléatoire unique
  3. le client crypte ce nombre aléatoire en utilisant le hachage de son mot de passe comme la clé
  4. le client envoie le nombre aléatoire chiffré vers le serveur
  5. le serveur crypte le nombre aléatoire avec le hachage correct du mot de passe de l'utilisateur
  6. le serveur compare les deux nombres aléatoires cryptés

ceci a quelques avantages. Tout d'abord, cela signifie que le mot de passe ne passe jamais par le lien sous quelque forme que ce soit. Deuxièmement, il est à l'abri d'une attaque de replay -- si un attaquant enregistre la conversation, il ne peut pas rejouer les réponses du client plus tard pour se connecter, parce que le nombre aléatoire aura changé.

sécuriser la connexion (c'est-à-dire crypter le contenu) est un peu plus simple. Typiquement, l'un des deux (peu importe lequel) choisit un nombre aléatoire, le crypte avec la clé publique de l'autre, et l'envoie à l'autre. Les autres le déchiffrent, et ils cryptent le reste de la session en utilisant cette clé pour le cryptage symétrique.

Bibliothèques: Beecrypt et OpenSSL sont quelques-uns des plus évidents. Sauf vous avez une raison assez spécifique de faire autrement, TLS est ce que vous voulez probablement utiliser (il fait un peu plus que ce que j'ai décrit ci-dessus, y compris l'authentification bidirectionnelle, donc non seulement le serveur sait qui est le client, mais le client sait aussi qui est le serveur, il est donc raisonnablement vérifié qu'il n'est pas connecté à quelqu'un d'autre qui pourrait juste recueillir son numéro de carte de crédit et exécuter avec lui).

Edit:

Pour authentifier chaque paquet sans la surcharge de crypter tout, vous pourriez faire quelque chose comme ceci:

  1. Le serveur envoie sa clé publique avec le défi
  2. Le client génère un nombre aléatoire, le chiffre avec la clé publique du serveur, et le renvoie à sa réponse
  3. le nombre est le premier nombre utilisé pour le cryptage en contre-mode
  4. le client inclut un résultat de contre-mode avec chaque paquet qu'il envoie

le mode Counter signifie que vous générez nombres consécutifs, et chiffrez chacun à leur tour, en utilisant la clé de droite. Dans ce cas, la clé de hachage du mot de passe du client. Cela signifie que chaque paquet contiendra un nombre aléatoire unique que le client et le serveur peuvent générer, mais personne d'autre ne le peut. En utilisant le cryptage en contre-mode, chaque paquet aura un nombre aléatoire unique. En partant d'un nombre aléatoire, chaque session aura une séquence unique de nombres aléatoires.

pour minimiser les frais généraux, vous pourrait envoyer juste une partie du résultat avec chaque paquet -- par exemple, si vous utilisez AES en mode counter, il générera 16 octets de résultat pour chaque nombre que vous cryptez. Inclure seulement, disons, deux octets avec chaque paquet, de sorte que vous ne devez chiffrer un numéro, une fois toutes les 8 paquets. En théorie, cela réduit la sécurité -- un attaquant pourrait juste essayer toutes les 65536 valeurs possibles pour un paquet, mais si vous supposez que la connexion a été compromise après (disons) deux mauvaises tentatives, les chances d'un attaquant d'obtenir le la bonne valeur devient assez petite (et, bien sûr, vous pouvez à peu près choisir les chances que vous êtes prêt à vivre en contrôlant le nombre de mauvaises tentatives que vous autorisez et la taille de l'authentification que vous incluez dans chaque paquet).

29
répondu Jerry Coffin 2012-07-20 14:53:58

Si la sécurité est un gros problème pour vous, ne roulent pas vos propres. Vous voulez une bibliothèque de socket sécurisée. Quelque chose comme OpenSSL.

0
répondu Linuxios 2012-07-20 14:13:53