web-dev-qa-db-fra.com

Envoi d'un score élevé côté client à un serveur en toute sécurité

Je crée une application Web qui contient un simple jeu javascript. Une fois que le joueur a fini de jouer, le meilleur score est envoyé au serveur et enregistré.

Après une période spécifique, le joueur avec le meilleur score reçoit un prix.

Existe-t-il un moyen d'envoyer le score élevé en toute sécurité et d'empêcher le client d'envoyer de "faux" scores élevés?

Actuellement, nous utilisons:

  • Https.
  • Jeton aléatoire du serveur avant chaque partie et envoyé après la fin de la partie avec le score.
42
StationaryTraveller

Le serveur ne peut pas faire entièrement confiance aux données qu'il reçoit du client, il est donc difficile de valider des scores élevés.

Voici quelques options:

  1. Obscurcissez le code côté client et le trafic vers le serveur. C'est l'option la plus simple - il sera toujours possible de tricher, mais cela ne vaudra probablement pas le temps de personne.

  2. Envoyez une relecture complète ou partielle du jeu au serveur pour validation. Les mouvements du joueur peuvent être exécutés sur le serveur pour déterminer le score légitime. Cela fonctionnera pour certains jeux et pas pour d'autres.

  3. Déplacez la logique et la validation du jeu sur le serveur. Le client relaie simplement chaque mouvement vers le serveur, où il est validé et l'état du jeu mis à jour.

Cela dépend de la façon dont votre jeu fonctionne, de la probabilité que les gens trichent et de votre importance s'ils le font.

113
grc

Si votre attaquant était un attaquant intermédiaire dans la couche réseau, alors https serait suffisant. Mais malheureusement, votre attaquant est le client, donc c'est plutôt inutile.

Règle numéro un des jeux anti-triche: Ne faites jamais confiance au client! Le client est entre les mains de l'ennemi.

Les jeux Javascript s'exécutent dans le navigateur Web de l'utilisateur. Comme vous le savez sûrement en tant que développeur Web, chaque navigateur Web est de nos jours livré avec un débogueur intégré qui peut afficher et modifier toutes les variables pendant l'exécution d'une application. L'utilisateur peut simplement utiliser le débogueur pour modifier son score avant de le soumettre. Vous ne pouvez rien faire pour empêcher cela. Avec les jeux sur navigateur, vous ne pouvez même pas gifler un outil anti-triche tiers (qui sont de valeur douteuse et éthiquement discutable de toute façon).

La seule contre-mesure consiste à implémenter toutes les mécaniques de jeu à manipuler sur le serveur. Le client ne doit rien faire mais transmettre les commandes de l'utilisateur au serveur et visualiser le gameplay en fonction des messages du serveur. Le gameplay réel doit se produire sur le serveur où il est hors de portée des tricheurs.

Oui, cela signifie que vous devrez repenser l'architecture logicielle de votre jeu à partir de zéro. Cela signifie également que vous devrez ajouter du code de prédiction et d'interpolation pour rendre le décalage du réseau moins visible. Et cela signifie également que vous aurez besoin d'un matériel serveur bien meilleur et d'une meilleure connexion Internet pour vos serveurs. Mais quand vous voulez un jeu en ligne sans triche, c'est la seule option.

29
Philipp

Pour obtenir un score élevé de jeu sécurisé, vous avez besoin d'un " preuve de travail ", ou plutôt d'une preuve de jeu plus appropriée.

Une preuve de travail/jeu est toute donnée difficile à calculer avant de terminer le jeu, mais facile à calculer une fois le jeu terminé et facile à vérifier par le serveur. Par exemple, pour un jeu de Sudoku, une preuve de travail est la solution au puzzle.

Malheureusement, il n'existe aucun moyen générique d'intégrer un système de preuve de jeu approprié dans de nombreux jeux. Il n'est pas toujours possible d'intégrer une preuve de jeu sans modifier ou remanier le jeu, ou limiter la portée du classement aux seuls éléments où vous pouvez inclure une preuve de jeu suffisamment sécurisée.

La preuve de jeu sur un jeu commence par le serveur émettant la graine pour le RNG du jeu. Le client devra alors trouver une preuve de jeu qui correspond à la graine que le joueur a reçu. Dans de nombreux jeux, une preuve de jeu peut être formée en soumettant la solution du jeu au serveur avec la soumission de score élevé, dans d'autres, il peut être nécessaire d'enregistrer la session de jeu entière avec différents niveaux de détails selon le jeu et la preuve de jouer que vous utilisez.

Une preuve de jeu doit être résistante au rejeu (un joueur ne devrait pas être en mesure d'utiliser le jeu terminé d'un autre joueur pour rendre sa propre preuve de jeu plus facile à calculer). Cela limite la preuve de jeu aux jeux où il y a un certain hasard que les joueurs ne peuvent pas simplement réutiliser la preuve de jeu d'un autre joueur, mais aussi qu'il ne peut pas avoir trop de comportement non déterministe au point où la vérification du jeu devient impossible.

La preuve de jeu est également limitée. Par exemple, dans un jeu de Sudoku, il n'est pas possible de prouver le temps que prend le joueur pour résoudre le puzzle. La preuve de jeu ne peut pas non plus toujours faire la distinction entre le jeu joué par le joueur lui-même et le joueur ayant écrit un script qui a joué le jeu pour lui.

17
Lie Ryan

Je voulais juste mentionner qu'il existe une sorte de solution à ce problème mais qu'elle n'est probablement pas disponible pour vous; la solution est appelée "cryptage homomorphe" et elle permet à un client d'effectuer un calcul connu sans savoir exactement avec quelles valeurs ils calculent, et un serveur de vérifier donc la structure de la valeur calculée pour prouver que le client n'a pas simplement envoyer une chaîne aléatoire en retour, mais en fait construit à partir des plusieurs valeurs fournies.

Le problème est que c'est soit lent ou incomplet, avec "incomplet" signifiant "n'incorpore pas une gamme complète de primitives logiques". Il s'agit très souvent d'un système partiel permettant certaines opérations de chiffrement et de déchiffrement E (), D (), ainsi que certaines opérations compliquées ⊕ telles que

D (E (A) ⊕ E(B)) = A + B,

ou semblable.

Voyons donc comment cela résout le problème pour certains jeux. Considérons un jeu de type "lumières éteintes" où vous appuyez sur les hexs N d'une grille hexagonale et chacun bascule à la fois son état et les états de ceux qui l'entourent il. Il s'agit d'une algèbre commutative sur ces "presses" et donc il n'y aura pas plus de N presses au total dans une solution donnée, plus chaque hex ne dépend que de l'état initial plus les presses de son propre hex plus les 6 hex autour.

Étant donné que notre schéma de chiffrement homomorphe ne permet que +, pas XOR, nous donnons à chaque hex un compteur de 3 bits pour le nombre de fois où il a été inversé. (Le logiciel client réduira automatiquement chaque double pression d'un hex à une seule pression.) Les actions de retournement réelles sont donc des vecteurs de bits ressemblant à,

001 001 000 000 000 001 001 001 000 001 001 000 000 ... 000 00000000 00000001

En d'autres termes, ils ont 1 dans chacun de ces champs de 3 bits qu'il retourne, plus un 1 dans un compteur de 16 bits.

Nous chiffrons tous ces éléments avec un schéma de chiffrement homomorphe, envoyons chacun d'eux au client, et le client nous renvoie une valeur chiffrée calculée à partir de ces valeurs chiffrées que nous avons renvoyées. Nous déchiffrons ensuite cela et ET la valeur déchiffrée avec la chaîne de bits,

001 001 001 001 ... 001 11111111 00000000

et comparer avec l'état de jeu initial adjacent à 0 pour ces 8 bits de compteur.

S'ils nous envoient une valeur aléatoire, leur chance que nous l'acceptions est de 2- (N + 8) et donc leur seul moyen utile de réussir les tests est d'utiliser les valeurs que nous leur avons données dans une combinaison autorisée. Ils ont accès à certains mouvements que nous ne leur permettons pas directement en raison de débordements d'entiers, mais nous pouvons toujours rendre les champs plus larges que 3 bits pour les rendre plus coûteux pour le compteur à droite. Mais on ne nous a jamais transmis leurs pressions individuelles sur les boutons, encore moins rejouer l'histoire: nous avons accepté un vecteur disant "voici comment j'ai inversé la grille", qui est la "chose super précaire" dont tout le monde vous met en garde, mais nous l'ont fait de telle manière qu'ils ne peuvent pas faire les choses qui nous inquiètent sans avoir accès à une clé secrète.

Au lieu de cela, vous voyez ce genre de chose dans le vote cryptographique où vous voulez avoir l'assurance qu'une machine à voter ne donne pas spontanément 1000 votes à Alice.

8
CR Drost

Tout côté client peut être usurpé. Donc la réponse est non.

EDIT J'ai supprimé le mécanisme de sécurité que j'ai écrit ici car il n'assure que les sessions legitime ... mais les scores falsifiés peuvent être envoyés via les sessions legitime. Merci @Luke Park

5
OscarAkaElvis

Ma recommandation est plus une technique d'obscurcissement, et pourrait éventuellement être un obstacle frustrant pour de nombreux utilisateurs. Cependant, les utilisateurs avancés ou déterminés peuvent toujours analyser votre code source pour reproduire les résultats.

Utilisez un outil comme Hashids pour créer un hachage du score, et envoyez-le dans votre demande de serveur avec le score en clair. La valeur de chaîne de l'ID utilisateur peut être le sel utilisé pour coder un hachage du score, ce qui rend le hachage inutile s'il est partagé. Côté serveur, vous pouvez décoder ce hachage et comparer le résultat avec le score en clair envoyé pour vous assurer qu'il correspond comme prévu.

0
Ben Harrison