Empêcher la triche multijoueur

10

Je suis presque en train de développer un petit jeu multijoueur de style indépendant. Bien que j'aie l'intention de permettre aux gens de tricher en solo, ce n'est évidemment pas acceptable en multijoueur. Quelqu'un connaît-il des moyens d'aider à empêcher le Joe moyen d'utiliser quelque chose comme Cheat-Engine pour modifier des parties du jeu? Je prévois actuellement que le client télécharge un hachage MD5 de chaque fichier de paramètres utilisé par le jeu (stocké sous forme de XML) sur le serveur de jeu pour vérification toutes les quelques secondes, mais est-ce que je peux faire pour arrêter des choses comme les éditeurs de mémoire, etc. ?

User093203920
la source
2
Je recommanderais cet article, Construire des jeux multijoueurs - La sécurité est écrite pour certaines API multijoueurs, mais les idées sont bonnes et s'appliquent toujours
Cyral

Réponses:

8

Si vous vous inquiétez du code modifié localement, comment pouvez-vous être sûr que quelqu'un n'a pas simplement modifié votre code de notification pour envoyer une liste statique de hachages MD5, les mêmes que vous attendez? En fait, vous n'avez même pas besoin de modification de code pour ce faire, vous avez juste besoin d'un proxy assez basique (en supposant qu'il n'y ait pas de SSL, mais même cela pourrait être truqué avec un peu plus d'effort).

La seule façon de faire ce que vous voulez est d'avoir un serveur et de ne pas faire confiance au client. Tous les calculs doivent être traités sur le serveur et toutes les actions vérifiées comme étant au moins quelque peu possibles. Par exemple, ne permettez pas au client de dire qu'il veut se déplacer d'un côté de la carte lorsque vous savez qu'il était de l'autre côté il y a un instant. Sans un serveur au milieu faisant tout ce qui est vital pour le jeu, il est impossible de ne pas tricher, car quelqu'un d'intelligent sera toujourstrouver un moyen de contourner tout ce que vous pouvez intégrer au client. Même avec un, c'est toujours possible si vous ne réfléchissez pas à toutes les différentes façons de manipuler légèrement la situation. Par exemple, la validation de mouvement que j'ai mentionnée précédemment: si vous effectuez un simple calcul point à point, les gens pourront toujours se téléporter à travers les murs.

La question est donc: quelle est la moyenne de «Joe moyen»? Vous avez déjà mentionné l'édition de code et les éditeurs de mémoire. C'est au-dessus de ce que je considérerais personnellement comme le niveau moyen, et si vous voulez vous inquiéter de ce niveau, alors un serveur de confiance séparé qui fait tout le gros du travail est requis et le client se résumera essentiellement à être des périphériques d'affichage et d'entrée.

Matthew Scharley
la source
2
@ user185812: C'est généralement une bonne idée d'attendre au moins quelques heures avant de marquer une réponse acceptée. Bien que personnellement, je pense que ma réponse est assez bonne (je suis biaisée), d'autres auront probablement plus de commentaires et voir une réponse acceptée dissuade souvent les autres de répondre.
Matthew Scharley
@MatthewScharley - pas de soucis. ;)
Martin Sojka
11

Le client est entre les mains de l'ennemi. ( Les lois de la conception du monde en ligne )

Vraiment, la seule façon de battre la plupart des tricheurs est de faire du client un "client léger", c'est-à-dire: d'agir uniquement comme un périphérique d'entrée et de sortie, et de ne jamais lui donner plus d'informations qu'il n'en a besoin.

Cela n'arrêtera pas l'automatisation et cela n'empêchera pas la collecte et l'analyse passives d'informations, mais vous pouvez concevoir votre jeu de manière à ce que celles-ci n'aient pas d'impact significatif.

Cela n'empêchera pas les gens de se pirater les uns les autres via des messages mal formés s'appuyant sur le serveur - votre client doit se prémunir contre les messages du serveur de la même manière que vous protégeriez vos sites Web des attaques par injection SQL.

Puisque vous souhaitez également utiliser le même client pour le jeu solo, une solution serait d'exécuter un serveur local dans un processus / thread séparé et de le traiter en interne comme un paramètre client / serveur. Les "tricheurs" fonctionneraient alors côté serveur. Minecraft fait quelque chose de similaire, bien que ce ne soit en aucun cas le premier jeu à séparer le moteur de jeu de son interface de cette manière.

Lecture suggérée:

Martin Sojka
la source
2

Dans un jeu multijoueur de base, tricher dans le genre de Cheat-Engine ne fonctionnera tout simplement pas. Les clients envoient uniquement les données et les actions pour lesquelles vous les avez conçues. Habituellement, ce n'est pas beaucoup plus que ce que le joueur a "fait", par exemple dans quelle direction il court, s'il tire et ainsi de suite. Ainsi, les changements qu'il apporte à la mémoire n'affecteront que son propre jeu, mais les autres joueurs ne verront aucun changement, une soi-disant désynchronisation. La plupart des jeux détectent des désynchronisations comme ça et suppriment le joueur désynchronisé du jeu.

Maintenant, il existe également d'autres moyens de tricher, mais tout dépend de la façon dont votre jeu est conçu.

Pour se protéger des hacks les plus simples, qui sont des faux messages réseau, le serveur doit vérifier la validité de ces packages. "Ce gars vient de sauter 5 écrans? C'est impossible, refuser le paquet." (Notez que vous pouvez également suivre l'itinéraire entièrement synchronisé - ce qui signifie que tout est synchronisé et uniquement «quels boutons le joueur a-t-il appuyés.» - le type de messages est envoyé - ce qui rend les faux messages réseau inutiles par conception.)

La dernière façon de tricher en multijoueur est le piratage de la visibilité, qui modifie le client pour qu'il montre au joueur des données qu'il ne connaît pas. Les exemples pour cela ne montrent pas le brouillard de la guerre, être capable de regarder à travers les murs, afficher une mini-carte ou d'autres choses. Celles-ci sont impossibles à empêcher.

API-Beast
la source
Je ne suis pas d'accord sur les hacks de visibilité. Cela ne pourrait-il pas être évité en ne donnant pas les informations au client jusqu'à ce que son personnage en soit conscient? Ne vous méprenez pas, ce n'est peut-être pas un bon design. Mais c'est différent d'être impossible à empêcher.
xuincherguixe
@xuincherguixe Je pense que c'est impossible dans certaines circonstances. Par exemple, les deux clients jouent sous la même IP et le même port. Dans ce cas, seule la bonne volonté du client l'empêche de lire les données destinées à l'autre.
Wodzu
1

Pour éviter les hacks de base de Cheat Engine qui manipulent les valeurs de vos variables, vous devez masquer ces valeurs. En règle générale, Cheat Engine est utilisé pour identifier l'emplacement de la mémoire des variables intéressantes (par exemple, la quantité d'or ou de vie ou le niveau de mise à niveau d'une capacité) en effectuant une recherche pour la valeur connue de ladite variable, jouer plus du jeu et faire en sorte que la valeur changer, alors Cheat Engine ferait une nouvelle recherche à partir du résultat de la recherche précédente pour la nouvelle valeur. Cela permet au tricheur de zoomer sur l'emplacement de mémoire de la valeur, maintenant il peut changer la valeur de cet emplacement de mémoire en utilisant Cheat Engine.

Par exemple, j'ai 245 GOLD ... avec Cheat Engine, je fais une recherche de 245 et trouve de nombreux emplacements de mémoire. Ensuite, je joue un peu plus et porte mon or à 314, je recherche ensuite la sortie de recherche précédente pour la valeur 314 et trouve facilement l'emplacement de mémoire où GOLD est stocké.

Le moyen d'éviter cela est de ne jamais avoir la valeur réelle stockée dans un emplacement mémoire. Par exemple, je stocke la valeur dans un objet qui doit calculer la valeur réelle à la demande lorsqu'elle est requise. Disons donc que le joueur a 245 OR. S'ils recherchent un emplacement de mémoire avec la valeur 245, ils peuvent en trouver plusieurs, mais aucun d'entre eux ne sera l'emplacement de mémoire où la valeur d'or est réellement stockée, c'est parce que vous ne stockez pas la valeur 245 pour l'or. Lorsque le jeu a besoin de savoir combien d'or, il demandera à l'objet qui en détient la valeur, qui le calculera à la demande.

La question est donc maintenant: comment stockez-vous exactement une valeur d'une manière qui ne la révèle pas? Cela devient un peu délicat et moche et je suis sûr qu'il y a plusieurs façons de le faire. Ce que j'aime faire, c'est stocker un tableau booléen (ou tableau d'octets). La longueur du tableau peut être n'importe quoi, mais disons qu'elle est 13. Ensuite, vous avez un compteur qui représente combien de fois 13 entre dans cette valeur réelle. Donc, si nous voulons représenter 245, le compteur aurait une valeur de 18. Maintenant, le tableau aurait tous les booléens mis à true pour le reste de 245/13 ... essentiellement le module. Dans ce cas, c'est 11, donc les 11 premiers booléens du tableau seront définis sur true, les autres sur false. Pour récupérer la valeur, tout ce que vous devez faire est de multiplier le compteur par la longueur du tableau, puis ajoutez 1 pour chaque ensemble booléen à true (arrêt au premier faux). Maintenant, le nombre 245 ne serait jamais stocké nulle part et il serait difficile de trouver l'emplacement de mémoire qui devrait être manipulé pour modifier la quantité d'or. Vous souhaiterez peut-être définir la longueur du tableau sur différentes tailles (peut-être choisir au hasard un nombre entre une plage raisonnable) lorsque cet objet est créé.

EDIT: Ceci est utile pour le multijoueur et le solo. Il y a de la triche qui peut également être effectuée en multijoueur, où les valeurs dans les paquets peuvent être modifiées. Cela nécessiterait différentes techniques pour empêcher, comme la signature de chaque paquet.

Jose Martinez
la source
1
En règle générale, pour éviter la tricherie, les jeux multijoueurs calculent tout sur le serveur, donc la modification d'une valeur sur le client, ou dans un paquet envoyé au serveur, ne change rien au jeu réel. Mais encore, le reste de la réponse est intéressant.
Vaillancourt
@AlexandreVaillancourt Bon point. Je m'inquiète d'enliser les signatures de calcul du processeur du serveur. Je veux garder le serveur rapide en passant simplement des paquets entre les deux joueurs, mais je vais regarder de plus près maintenant que vous l'avez signalé.
Jose Martinez
Si vous envoyez uniquement les entrées du client au serveur, vous n'avez pas besoin de signer chaque paquet. Une fois sur le serveur, si l'entrée n'a pas de sens, elles sont simplement rejetées ou le client est expulsé pour avoir triché. Le serveur calcule l'état suivant du jeu, puis envoie le nouvel état à tous les joueurs, c'est généralement ainsi que la tricherie est évitée (vous ne vous débarrassez pas des robots comme celui-ci, mais au moins vous évitez la tricherie occasionnelle des joueurs) .
Vaillancourt
1
Pour éviter cela, vous laissez le serveur mettre à jour la nouvelle vie, puis envoyez la nouvelle vie au client. Tout est calculé sur le serveur, et laisse les clients être simplement des "terminaux stupides" pour toutes les choses importantes: le client sera responsable de capturer les entrées du lecteur ("cliqué à x, y à l'instant T", "hit bouton X au temps T "), en les envoyant au serveur et en recevant le nouvel état du serveur (" le joueur est maintenant en position X, Y "," le joueur a la vie ZZZ ") et en l'affichant sur le joueur.
Vaillancourt
1
Avec cela, le tricheur (l'homme au milieu) peut gâcher tout ce qu'il veut avec les paquets, cela ne changera pas l'état du jeu sur le serveur car le serveur s'assurera que les entrées sont valides ("hmm le client a cliqué à cinq endroits différents au cours des 0,03 dernières secondes, ce n'est pas normal, rejetons ces clics ") et exécutons toute la simulation elle-même.
Vaillancourt