TourDeJeu, le réseau des jeux en ligne alternatifs : jeux web multijoueurs, jeux par forum. En savoir +

Flux RSS des discussions du forum : pour les joueurs, et pour les créateurs et MJ
  Reply to this topicStart new topicStart Poll

> Jets De Dés Distribués
mini TilK
  Ecrit le : Mercredi 02 Août 2006 à 18h11
Quote Post


Newbie
*

Groupe : Membre
Messages : 7


Bonjour à tous,

Pour mon premier post, je souhaite discuter avec vous d'un problème que j'ai rencontré dans un jeu que je code actuellement.

Présentation du contexte

Je sais que je suis un peu "border-line" avec les jeux auquels on parle ici, mais je pense que je reste assez proche et que mon problème peut être rencontré dans les jeux par correspondance.

Donc je développe actuellement "Mountyhall Arena" (MHA), un jeu autour de Mountyhall. Le but de ce jeu est donc de permettre à des joueurs de Mountyhall de combattre l'un contre l'autre en dehors du jeu, c'est à dire que les personnages sont exportés de mountyhall pour pouvoir être utilisé dans MHA. Les actions de MHA n'ont donc aucun impact sur MH.

Nous avons donc un serveur qui tourne chez un des joueurs et autant de clients que de joueurs. Chacun se connecte à ce dernier. Afin d'accélérer les combats, ceux ci ont lieu en temps simulé : les joueurs jouent l'un après l'autre (donc en tour par tour), mais une horloge simule le temps qui passe : entre deux tours le temps avance infiniment vite, quand un joueur joue, il s'arrete.

Si vous voulez en savoir plus.

Le problème

Actuellement, tous les calculs sont fait par le serveur, les clients ne s'occupant que de l'affichage, donc tous les jets de dés sont également fait par le serveur.
Or ce projet étant libre, les sources sont disponible et il est possible, qu'un petit malin s'amuse à modifier le code du serveur pour que celui ci génère des nombres à son avantage (tout en restant plosibles). Par exemple, il pourrait s'arranger pour que tous ses jets de D6 soit égaux à 5 ou 6. Il pourrait de cette façon piper tous les jets.

La seule solution que je vois pour éviter cela est de distribuer les jets de dés, c'est à dire qu'au lieu que les jets soit fait sur une seule machine, ceux soit soit fait en partie sur le serveur et en partie sur un client.

Voila, je souhaiterais donc savoir si quelqu'un n'aurait pas des pointeurs ou des idées sur ce problème (c'est assez proche de la cryptographie, il doit bien y avoir des chercheurs dans ce domaine ici...).

Début de solution

J'ai réfléchi un peu sur la façon d'obtenir cela, et j'ai fini par trouver un bout de solution :

Imaginons par exemple que l'on est besoin de simuler un dé de 6.

Chacune des 2 parties (notons S le serveur et C le client) génère en nombre en 1 et 6 noté NS et NC, l'envoi à l'autre et la valeur finale N est
N= ( (NS+NC-1) %6 ) +1

Avantage de cette méthode : Si le serveur génère un nombre particulier, le résultat final pourra être n'importe quel nombre compris en 1 et 6 suivant la valeur générée par le client.

Néanmoins cette méthode oblige que les deux nombres soit envoyés simultanément. Or dans la réalité, ce ne peut pas être le cas.

Si le client veut tricher, il lui suffit d'attendre le chiffre du serveur, et il ne lui reste plus qu'à calculer NC en fonction du résultat final qu'il veut générer.

Pour empécher cela, j'ai donc pensé à une autre solution basé sur la premiere, que je modélise par un chronogramme :

S -----------------------Il faut générer un D6---------------------> C
S<------------Voila des informations sur mon nombre------------C
S--------------Voila des informations sur mon nombre---------->C
S<------------------------Voila mon nombre-------------------------C
S--------------------------Voila mon nombre----------------------->C
S-------Les info recues correspondent bien à ton nombre---->C
S<------Les info recues correspondent bien à ton nombre-----C
S--------------------------Le nombre final est----------------------->C
S<--------------------Je trouve la même chose---------------------C

Néanmoins pour que ceci marche, cela nécessite plusieurs contraintes :
* Que les informations envoyées ne permettent pas de retrouver le nombre qui a permis de les générer (cela doit donc être non inversible)
* Qu'il soit impossible de connaitre 2 nombres différents en 1 et 6 permettant de générer les mêmes informations

On début, j'avais pensé à utiliser l'exponnentielle modulaire, et par exemple donner comme info :
K^(51661561+mon nombre) = 517761 [M] (où M est fixe)

et donner K et mon nombre en même temps, mais il est facile à de générer des nombres ayant la meme info et étant différents.

Par exemple :
(L^60)^(0+1)=(L^30)^(0+2)=(L^20)^(0+3)=(L^15)^(0+4)=(L^12)^(0+5)=(L^10)^(0+6)

mad.gif


Donc si vous connaissez une méthode pour faire cela, si vous avez trouvé une façon de modifier ma solution pour que ca marche, si cela vous interesse ou si avez quelques pointeurs, n'hésitez pas à poster.

Merci d'avance...
PMEmail Poster
Top
the-gtm
Ecrit le : Mercredi 02 Août 2006 à 20h29
Quote Post


Pro
*

Groupe : Membre
Messages : 130


Ce que tu veux faire est impossible : tu veux vérifier qu'un tirage est bien aléatoire. Si c'est réellement aléatoire, il n'y a pas de règles et il est donc impossible de vérifier le résultat.

Ce à quoi je pense pour ton problème est un tiers de confiance, le serveur MHA par exemple. Ce tiers tire un nombre aléatoire N et l'encrypte avec deux clés K1 et K2, il obtient ainsi N.K1 et N.K2, deux messages encryptés. Il donne N.K1 et K2 au client et N.K2 et K1 au serveur.

Au moment où le jet doit être fait, le serveur donne sa clé au client et inversement. Chaucun peut donc décrypter le nombre aléatoire N et vérifier ce qu'annonce l'autre.

Pour encrypter, pas la peine de sortir l'artillerie lourde, un simple XOR bit à bit suffit.

Pour limiter les échanges avec le serveur MHA, celui ci peut générer des tranches de 100 (par exemple) nombres aléatoires d'un coup (il faut donc 2 x 100 clés pour les encrypter).

Le seul problème restant est de permettre au serveur MHA de faire lien entre le client et le serveur. Pour cela C et S peuvent convenir d'un numéro de partie, ils interrogent alors le serveur MHA pour avoir leurs 100 nombres et leurs 100 clés. Le serveur MHA crée le 100 nombres les 200 clés et associe le tout au numéro de la partie. Il est donc capable de donner au client et au serveur leurs chiffres et leurs clés.

La faille restante est de ne pas permettre au client de se faire passer pour le serveur (ou inversement), ce qui lui permettrait d'obtenir ses clés. Pour cela une identification par login/mot de passe suffit.
PMEmail Poster
Top
Grouik
Ecrit le : Mercredi 02 Août 2006 à 20h31
Quote Post


Kid
*

Groupe : Membre
Messages : 27


Hum, j'imagine que tu peux te baser sur le principe de la cryptographie asymétrique bien que ton problème soit différent.
En effet, tu ne cherches pas à protéger des informations d'un tiers mais des destinataires eux-même.


A première vue, un principe possible serait :


1. a. Alice génère deux clés. La clé publique et la clé privé.

1. b. Alice encode l'information à l'aide de la clé publique et envoie le résultat à Bob, ainsi que sa clé publique.

2. a. Bob génère deux clés. La clé publique et la clé privé.

2. b. Bob encode l'information à l'aide de la clé publique et envoi le résultat à Bob, ainsi que sa clé publique.


A ce stade, Alice et Bob disposent tous les deux des informations de l'autre, mais ne peuvent pas les lire.


3. a. Alice envoie sa clé privée à Bob, qui peut alors décoder l'information précédemment envoyée par Alice.

3. b. (normalement inutile, pour les paranos) Puisque Bob dispose maintenant de tous les éléments d'Alice, il peut réencoder / décoder l'information pour vérifier que ça colle.

4. a. Bob envoi sa clé privée à Alice, qui peut alors décoder l'information précédemment envoyée par Bob.

4. b. (normalement inutile, pour les paranos) Puisqu'Alice dispose maintenant de tous les éléments de Bob, elle peut réencoder / décoder l'information pour vérifier que ça colle.


Communiquer les clés privées ? Oui, puisqu'on se fiche qu'un tiers intercepte l'information... à se stade, les informations précédemment encodées peuvent être rendues publiques à la terre entière, y compris (et surtout) à Alice et Bob. Et même si l'un des 2 décode l'information de l'autre avant d'envoyer sa clé privée, il ne peut rien y faire (à moins de volontairement ne rien envoyer ou d'envoyer une mauvaise clé pour faire capoter l'échange <- problème à prendre en compte d'ailleurs).


Bon, cela impose de générer des clés différentes pour chaque échange.

Je ne suis pas spécialiste, mais vu que la cryptographie asymétrique est extrèmement courante, il doit bien exister des librairies de chiffrement pour générer les clés et encoder / décoder des informations dans à peu près tous les langages. Enfin, j'espère...


NdR : en fait je me demande s'il ne serait pas plus simple d'utiliser une bête clé symétrique...


--------------------
"Personnellement, c'est pas Dieu qui me dérange, c'est son putain de fan club..."
PMEmail Poster
Top
the-gtm
Ecrit le : Mercredi 02 Août 2006 à 21h31
Quote Post


Pro
*

Groupe : Membre
Messages : 130


Je n'ai peut être pas bien compris mais je ne vois pas en quoi ce protocole répond au problème. Tout ce qu'on fait Alice et Bob c'est de transférer à l'autre un message.

Le problème n'est pas dans la façon de le transférer mais dans le contenu même du message : le nombre aléatoire que m'envoie Alice est il réellement aléatoire ou a-t-elle pipé les dés ?

Si je ne connais pas le générateur aléatoire d'Alice (son algorithme et son état complet), je ne peux pas dire si le chiffre annoncé est le bon. Au contraire, si je connais ce générateur aléatoire, je peux le faire tourner chez moi (et donc vérifier le résultat), mais dans ce cas je connais à l'avance tous les tirages...
PMEmail Poster
Top
mini TilK
Ecrit le : Mercredi 02 Août 2006 à 22h01
Quote Post


Newbie
*

Groupe : Membre
Messages : 7


Merci de ta réponse Grouik, en effet, ton protocole a l'air de marcher et respecter les contraintes.
Par contre, générer deux paires de clés par lancer de dés, je suis pas sorti de l'auberge laugh.gif

the-gtm : Non, même si Alice pipe les dés, le nombre généré restera aléatoire. En effet, ne connaissant pas le nombre généré par Bob, elle ne sait pas de quel coté "piper" le dé.

Pour répondre à ta question, le but n'est pas de vérifier que le tirage est bien aléatoire, mais empécher un seuls des cotés d'influer sur le résultat dans le cas il ne peut y avoir de tiers de confiance.

Si je suis pas très clair, je vais esssayer de donner un exemple plus parlant :

Alice et Bob veulent jouer à un jeu à la con : chacun jette une piece et si les pièces ratérissent du même coté, Alice gagne, sinon Bob gagne. Bien sur Alice se trouve en Allemagne et Bob au Brésil.

Si Bob donne le résultat d'abord, il suffit à Alice de dire la même chose que Bob pour être sure de gagner à chaque fois. Une solution pourrait être de prendre la pièce en photo et donne donner à l'autre des informations partielles sur la photo : par exemple, le pixel [22,33] est de couleur gris clair, le [45,55] est rouge...
Il faut que de ces informations partielles, il soit impossible de savoir de quelle coté est la pièce sur la photo, mais il faut suffisament donner d'informations pour qu'il soit impossible pour Bob de prendre deux photos différentes (une pile, l'autre face) avec autant de pixels identiques.

Une fois les informations partielles échangées, on échange cette fois ci les vraies photos et on vérifie les informations partielles et on regarde qui a gagné.

Logiquement, c'est impossible pour Bob et Alice de tricher...
PMEmail Poster
Top
Manest
Ecrit le : Vendredi 04 Août 2006 à 06h42
Quote Post


Ouf
*

Groupe : Membre
Messages : 503


J'espere que je vais pas dire n'importe quoi et que j'ai bien tout compris.

En général quand on utilise une valeur aléatoire, c'est e nfait une valeur pseudo-aléatoire. En effet il faut au préalable initialiser le générateur avec une valeur (on fait souvent ca avec la date courante par exemple). En PHP on initialise la fonction rand avec srand.
En général c'est pratiquement pareil dans tous les langages.

Le grand interet de ca c'est pour les tests. Si t'initialise la fonction avec la même valeur tu aura toujours la même suite qui sortira (d'où le pseudo-aléatoire).

A partir de là, si ton serveur fait un truc du genre (en php) :

$date = time(); // Tu recupères la date courante
srand($date);
$D6 = rand(1, 6);

Tu as donc généré un jet de dés classique. Maintenant tu transmets au client :
$D6 et $date.

Le client recoit ces valeurs et fait la même chose afin de controler. Il reinitialise son srand avec la même valeur $date. Du coup son rand() devrait produire le même résultat. Il suffit de le comparer au $D6 envoyé par le serveur.

Pour être sur que le client n'a pas balancé n'importe quel valeur $date, et bien tu peux pas vraiment en fait (il est pas forcement à la même heure)... Il faudrait un tiers de confiance chargé de distribuer l'heure courante... Si c'est possible tu controles simplement que $date correspond à une date d'il y a moins de 5 secondes par exemple...

Mouai en fait je suis moins sur de moi en l'écrivant, je vais me coucher, vous me direz si je suis à coté de la plaque smile.gif


--------------------
PMEmail PosterUsers Website
Top
mini TilK
Ecrit le : Vendredi 04 Août 2006 à 11h03
Quote Post


Newbie
*

Groupe : Membre
Messages : 7


QUOTE (Manest @ 4 Aug 2006, 05:42 )
J'espere que je vais pas dire n'importe quoi et que j'ai bien tout compris.

En général quand on utilise une valeur aléatoire, c'est e nfait une valeur pseudo-aléatoire. En effet il faut au préalable initialiser le générateur avec une valeur (on fait souvent ca avec la date courante par exemple). En PHP on initialise la fonction rand avec srand.
En général c'est pratiquement pareil dans tous les langages.

Le grand interet de ca c'est pour les tests. Si t'initialise la fonction avec la même valeur tu aura toujours la même suite qui sortira (d'où le pseudo-aléatoire).

A partir de là, si ton serveur fait un truc du genre (en php) :

$date = time(); // Tu recupères la date courante
srand($date);
$D6 = rand(1, 6);

Tu as donc généré un jet de dés classique. Maintenant tu transmets au client :
$D6 et $date.

Le client recoit ces valeurs et fait la même chose afin de controler. Il reinitialise son srand avec la même valeur $date. Du coup son rand() devrait produire le même résultat. Il suffit de le comparer au $D6 envoyé par le serveur.

Pour être sur que le client n'a pas balancé n'importe quel valeur $date, et bien tu peux pas vraiment en fait (il est pas forcement à la même heure)... Il faudrait un tiers de confiance chargé de distribuer l'heure courante... Si c'est possible tu controles simplement que $date correspond à une date d'il y a moins de 5 secondes par exemple...

Mouai en fait je suis moins sur de moi en l'écrivant, je vais me coucher, vous me direz si je suis à coté de la plaque smile.gif

Et si le serveur fait :

while($D6!=6)
{
$date=time();
srand($date);
$D6 = rand(1, 6);
}

send($D6,$date);

Il est capable de générer des 6 qui vérifient les contraintes.
Donc c'est pas top comme méthode...

PS : petite remarque, en génral, il ne faut pas utiliser rand pour générer des nombres pseudo-alétoires en php, mais plutot mt_rand qui est plus rapide et a de meilleurs propriétés statistiques.
PMEmail Poster
Top
naholyr
Ecrit le : Vendredi 04 Août 2006 à 11h33
Quote Post


Ouf
*

Groupe : Membre
Messages : 423


QUOTE (mini TilK @ 2 Aug 2006, 18:11 )
Actuellement, tous les calculs sont fait par le serveur, les clients ne s'occupant que de l'affichage, donc tous les jets de dés sont également fait par le serveur.
Or ce projet étant libre, les sources sont disponible et il est possible, qu'un petit malin s'amuse à modifier le code du serveur pour que celui ci génère des nombres à son avantage (tout en restant plosibles). Par exemple, il pourrait s'arranger pour que tous ses jets de D6 soit égaux à 5 ou 6. Il pourrait de cette façon piper tous les jets.

Tu ne résoudras pas ce problème, ou d'autres finiront par faire leur apparition... La seule chose que tu dois vérifier, et qui te permet d'être définitivement tranquille, c'est que ton serveur n'a pas été falsifié tout simplement.

Je n'ai pas d'idée précise sur une façon de faire qui soit totalement impiratable, mais il faudrait que cette vérification soit faite par le client au moment où il se connecte. Ainsi si quelqu'un fait un serveur "piraté" il ne pourra se connecter que des clients ayant également une version modifié du programme (après tout ça n'est pas exclu, le projet étant libre, ce sera simplement un fork du projet initial, mais il est important que les clients du projet de départ ne puisse pas se connecter à un serveur forké à la sauvage).

Tu dois simplement fournir un serveur d'authentification, le client se connecte au serveur de jeu (potentiellement modifié), récupère des infos théoriquement infalsifiables (c'est là qu'il faut se poser la question) ainsi que son numéro de version, envoie ça au serveur d'authentification qui va se contenter de lui dire si oui ou non ce serveur est validé, posant au joueur la question s'il tente de se connecter sur un serveur non validé.
Cela peut être une piste de ce genre, mais quoi qu'il en soit tu ne t'en sortiras jamais sans un système d'authentification de la validité du serveur et des fichiers qui le composent.
PMEmail PosterUsers WebsiteICQYahoo
Top
Grouik
Ecrit le : Vendredi 04 Août 2006 à 15h58
Quote Post


Kid
*

Groupe : Membre
Messages : 27


Attention, si j'ai bien compris, il n'y a pas 1 serveur faisant les traitements et auquels des clients sont connectés, mais uniquement de 2 programmes identiques qui communiquent.

Je pense que mini TilK à appelé l'un "serveur" et l'autre "client" pour simplifier, le "serveur" étant l'un des 2 programmes (celui qui initie la partie ?) qui aurait en charge plus de traitements que l'autre programme. Mais on peut très bien imaginer que les 2 programmes font autant de travail l'un que l'autre (c'est pour ça que je préfère parler d'Alice et de Bob).

Donc pas de serveur, pas de tiers de confiance...

Le problème étant : comment empêcher un joueur de modifier son programme de manière à tricher sur des tirages aléatoires ?

Idée de mini TilK : faire faire les tirages par les 2 programmes et compiler les résultats (par exemple avec un bête modulo).

Du coup, le problème ne concerne pas la qualité aléatoire des tirages... à la limite, on pourrait demander à chaque joueur de donner le nombre qu'il veut : ne connaissant pas le nombre choisi par l'autre, il ne peut en déduire le résultat. Un chi-fou-mi numérique en quelque sorte.

Oui mais voilà, comment s'assurer qu'aucun des 2 programmes n'aura connaissance du nombre de l'autre avant de déterminer le siens ? Car à un moment, il faudra bien compiler les 2 nombres pour obtenir le résultat... d'où la problématique de mini TilK (j'ai correctement résumé ?).

L'ébauche de solution proposée : dans un premier temps, chacun génère et envoi à l'autre son nombre dans un coffre fort fermé à clé puis, seulement ensuite chacun envoie la clé -> d'où l'utilisation d'un algo de crypto (cf. ma précédente intervention).

Ca reste à creuser, en particulier :
- il est possible de faire plus simple en utilisant une clé symétrique plutôt qu'asymétrique, mais on se prive alors de la possibilité d'effectuer une vérification de contrôle a posteriori ;
- comment gérer le programme qui ferait exprès de faire capoter la transaction s'il s'apperçoit après avoir ouvert le coffre fort à sa disposition que le nombre qu'il a précédemment envoyé dans son coffre fort va le faire perdre ?
- sans doute d'autres problématiques qui ne se feront jour qu'en creusant...


--------------------
"Personnellement, c'est pas Dieu qui me dérange, c'est son putain de fan club..."
PMEmail Poster
Top
Haiken
Ecrit le : Vendredi 04 Août 2006 à 17h06
Quote Post


Ouf
*

Groupe : Membre
Messages : 360


QUOTE (mini TilK @ 2 Aug 2006, 17:11 )
S -----------------------Il faut générer un D6---------------------> C
S<------------Voila des informations sur mon nombre------------C
S--------------Voila des informations sur mon nombre---------->C
S<------------------------Voila mon nombre-------------------------C
S--------------------------Voila mon nombre----------------------->C
S-------Les info recues correspondent bien à ton nombre---->C
S<------Les info recues correspondent bien à ton nombre-----C
S--------------------------Le nombre final est----------------------->C
S<--------------------Je trouve la même chose---------------------C

Néanmoins pour que ceci marche, cela nécessite plusieurs contraintes :
* Que les informations envoyées ne permettent pas de retrouver le nombre qui a permis de les générer (cela doit donc être non inversible)
* Qu'il soit impossible de connaitre 2 nombres différents en 1 et 6 permettant de générer les mêmes informations

Je pense que ton approche est la bonne, il te manque juste une fonction de cryptage "non inversible"... (pas forcément besoin d'un cryptage clé publique/clé privée)
Ca se trouve dans les fonctions de Message Digest, par exemple le gentil md5() qui est disponible en PHP. Il est impossible de retrouver la chaîne d'origine à partir du "hash" (résultat) MD5.

S: nbS = nombre au hasard
S -----------------------Il faut générer un D6---------------------> C
S--------------mdS=md5(nbS)---------->C
C: nbC = nombre au hasard
S<------------mdC=md5(nbC)------------C
S<------------------------nbC-------------------------C
S--------------------------nbS----------------------->C
S: si md5(nbC)=mdC ==> OK sinon C triche
C: si md5(nbS)=mdS ==> OK sinon S triche

S et C : résultat D6 = f(nbC, nbS) avec par exemple f(nbS, nbC)=nbS+nbC%6

-----

A partir de là, je pense qu'il faut renforcer un peu l'algo. En effet, on pourrait potentiellement retrouver par "brute force" (tester tous les cas) le nombre nbC à partir de mdC. Il faut alors dans ce cas introduire un texte aléatoire qui ne sera transmise qu'avec le résultat, mais utilisé pour calculer le hash.
Ca nous donne :

S: nbS = nombre au hasard
S: txtS = chaine au hasard (uniqid)
S -----------------------Il faut générer un D6---------------------> C
S--------------mdS=md5(txtS.nbS)---------->C
C: int nbC = nombre au hasard
S: txtC = chaine au hasard (uniqid)
S<------------mdC=md5(txtC.nbC)------------C
S<------------------------txtC, nbC-------------------------C
S--------------------------txtS, nbS----------------------->C
S: si md5(txtC.nbC)=mdC ==> OK sinon C triche
C: si md5(txtS.nbS)=mdS ==> OK sinon S triche

S et C : résultat D6 = f(nbC, nbS) avec par exemple f(nbS, nbC)=nbS+nbC%6

(on se rapproche alors fortement de la solution de Grouik wink.gif )


--------------------
PMEmail Poster
Top
mini TilK
Ecrit le : Lundi 07 Août 2006 à 11h46
Quote Post


Newbie
*

Groupe : Membre
Messages : 7


Bon de retour de WE, je peux répondre aux messages :

Grouik > En effet tu résumes bien la situation, il ne peut y avoir de tiers de confiance, les noms client/serveur sont juste là pour distinguer le type de travail effectué.

Pour le problème du capotage de la transaction, ce la reste assez simple à mon avis : En cas de problème, l'utilisateur est averti que l'un des joueurs essaie de tricher. Il pourra donc prendre les mesures qui s'avèrent nécessaires.

Haiken : Le problème avec ta solution tient dans la "faiblesse" du md5. Beaucoup de collisions sont connues (deux valeurs différentes donnant le même hash), il suffit donc au tricheur de donner un hash problématique et suivant la valeur de l'autre choisir la bonne valeur initiale à fournir.

A mon avis, donner le hash n'est aps suffisant pour garantir une bonne sécurité, il faudrait par exemple fournir une partie du début de txtC pour rajoute un peu de sécurité...
PMEmail Poster
Top
Grouik
Ecrit le : Lundi 07 Août 2006 à 16h50
Quote Post


Kid
*

Groupe : Membre
Messages : 27


QUOTE (mini TilK @ 7 Aug 2006, 10:46 )
Pour le problème du capotage de la transaction, ce la reste assez simple à mon avis : En cas de problème, l'utilisateur est averti que l'un des joueurs essaie de tricher. Il pourra donc prendre les mesures qui s'avèrent nécessaires.

Pas si simple, un problème de transaction n'est pas forcément issue de la triche. Les causes peuvent être multiples et surtout non diagnosticables : va savoir qu'un routeur vient de tomber au noeud de Trifouille-les-Oies, ou plus basiquement qu'un joueur subit des problèmes de déconnexions à cause de son fournisseur d'accès adoré ! Ca pourrait même être un boggue lié au programme (si, si, il paraît que ça existe tongue.gif ).

Prudence donc, un joueur de bonne fois catalogué comme tricheur risque de rapidement faire la tronche...


--------------------
"Personnellement, c'est pas Dieu qui me dérange, c'est son putain de fan club..."
PMEmail Poster
Top
Haiken
Ecrit le : Lundi 07 Août 2006 à 18h41
Quote Post


Ouf
*

Groupe : Membre
Messages : 360


QUOTE (mini TilK @ 7 Aug 2006, 10:46 )
Haiken : Le problème avec ta solution tient dans la "faiblesse" du md5. Beaucoup de collisions sont connues (deux valeurs différentes donnant le même hash), il suffit donc au tricheur de donner un hash problématique et suivant la valeur de l'autre choisir la bonne valeur initiale à fournir.

A mon avis, donner le hash n'est aps suffisant pour garantir une bonne sécurité, il faudrait par exemple fournir une partie du début de txtC pour rajoute un peu de sécurité...

Dans ce cas, tu peux demander au client et serveur de s'échanger une première chaine txtInit

par exemple txtInitC fournit par le client :
le calcul du hash devient : mdS=md5(txtInitC.txtS.nbS)

non ?

c'est ce genre de choses qui est utilisé dans des algos d'authentification sécurisée il me semble


--------------------
PMEmail Poster
Top
mini TilK
Ecrit le : Mardi 08 Août 2006 à 10h00
Quote Post


Newbie
*

Groupe : Membre
Messages : 7


QUOTE (Haiken @ 7 Aug 2006, 17:41 )
Dans ce cas, tu peux demander au client et serveur de s'échanger une première chaine txtInit

par exemple txtInitC fournit par le client :
le calcul du hash devient : mdS=md5(txtInitC.txtS.nbS)

non ?

c'est ce genre de choses qui est utilisé dans des algos d'authentification sécurisée il me semble

En fait ca ne suffit, pas.

Le md5 possède certaines propriétés dont une qui nous dérange ici :
Si le md5(M)==md5(M')
alors md5(B.M.A)==md5(B.M'.A) où A et B peuvent être quelconque.

Donc dans ton cas, peut importe le textinitC que tu lui fournit, il est capable de trouver une collision comment par cette information s'il en connait déja une.

C'est aussi vrai pour beaucoup d'algorithmes de hashage, pffff

Par contre si on mixe textInitC et txtS (un bit de l'un puis un bit de l'autre) cela risque d'être plus dur à trouver des collisions. Par contre, ne serait-il pas trop facile de retrouver alors le nombre généré connaissant toutes ces informations...
PMEmail Poster
Top
naholyr
Ecrit le : Mardi 08 Août 2006 à 10h29
Quote Post


Ouf
*

Groupe : Membre
Messages : 423


QUOTE (mini TilK @ 8 Aug 2006, 10:00 )
Le md5 possède certaines propriétés dont une qui nous dérange ici :
Si le md5(M)==md5(M')
alors md5(B.M.A)==md5(B.M'.A) où A et B peuvent être quelconque.

Tu es sûr de ton coup là ? Tu devrais vérifier tes sources wink.gif
Tu peux d'ailleurs te persuader que cette propriété est fausse par toi-même en trouvant un simple contre-exemple :
- Trouve une collision MD5 pour deux chaines M et M' (je peux t'en fournir si tu veux) donc md5( M ) = md5( M' )
- Ajoute la même chaîne A au début de M et M', et la même chaîne B au début de M et M'. Tu verras que md5( A.M.B ) != md5( A.M'.B )

Pas d'inquiétude de ce côté là.

Edit: si malgré tout tu ne fais pas confiance à md5, tu peux utiliser les dernières fonctionnalités de hashage de php (dispo dans la 5.1.4, mais pas dans la 5.1.2). Voir par exemple la fonction hash_algos() pour plus de détails, ou mhash() pour une fonction moins touffue mais permettant tout de même sha1 ou sha256.

Edit: en fait ce dont tu parlais c'est une méthode découverte en 2004 par une équipe chinoise pour créer des collisions. Ils ont trouvé un bloc de texte particulier tel que si deux chaînes commencent par ce bloc, contiennent ensuite une portion aléatoire d'une taille définie pouvant être différente, puis à nouveau des blocs identiques, elles auront le même hash. C'est un cas particulier vraiment spécifique, et il ne permet pas de créer des chaînes ayant le md5 que l'on souhaite, donc ne remet nullement en question la fiabilité des tests ainsi menée, surtout si on PRECEDE la chaîne d'un sel (dans ce cas, on détruit illico toute possibilité d'appliquer la méthode découverte, puisque le bloc par lequel doivent commencer les chaînes est précédé d'une chaîne).
Ce dont tu parlais c'est donc qu'il existe un bloc A particulier, tel que quelque soit M et M' de la même longueur L donnée, et B une chaine quelconque, alors md5( A.M.B ) = md5( A.M'.B ), ce n'est carrément pas pareil wink.gif
PMEmail PosterUsers WebsiteICQYahoo
Top
mini TilK
Ecrit le : Mardi 08 Août 2006 à 11h56
Quote Post


Newbie
*

Groupe : Membre
Messages : 7


QUOTE (naholyr @ 8 Aug 2006, 09:29 )
Tu es sûr de ton coup là ? Tu devrais vérifier tes sources wink.gif
Tu peux d'ailleurs te persuader que cette propriété est fausse par toi-même en trouvant un simple contre-exemple :
- Trouve une collision MD5 pour deux chaines M et M' (je peux t'en fournir si tu veux) donc md5( M ) = md5( M' )
- Ajoute la même chaîne A au début de M et M', et la même chaîne B au début de M et M'. Tu verras que md5( A.M.B ) != md5( A.M'.B )


Pour la concaténation à droite MD5( M'+A )= MD5( M+A ), j'en suis quasiment sur juste par la définition du hash.

Si tu doutes : http://www.codeproject.com/dotnet/HackingMd5.asp
Il construisent sans problèmes deux fichiers différents ayant le même hash et ne produisant pas la même chose en sortie.

Pour la concaénation à gauche, je l'avais vu sur un article, j'essayerais de le retrouver après avoir mangé smile.gif

Edit : petite correction dùe à un mauvais copier coller smile.gif
PMEmail Poster
Top
naholyr
Ecrit le : Mardi 08 Août 2006 à 12h13
Quote Post


Ouf
*

Groupe : Membre
Messages : 423


QUOTE (mini TilK @ 8 Aug 2006, 11:56 )
Pour la concaténation à droite MD5( M+A )= MD5( M+B ), j'en suis quasiment sur juste par la définition du hash.

Si tu doutes : http://www.codeproject.com/dotnet/HackingMd5.asp
Il construisent sans problèmes deux fichiers différents ayant le même hash et ne produisant pas la même chose en sortie.

Pour la concaénation à gauche, je l'avais vu sur un article, j'essayerais de le retrouver après avoir mangé smile.gif

Non non, md5(M+A) n'est pas égal à md5(M+B ), c'est uniquement si md5(M) = md5(M'), alors md5(M+A) = md5(M'+A). Ce n'est pas la même chose, et c'est donc directement brisé par l'ajout d'un sel à gauche.
Il faut déjà trouvé un M et M' qui sortent une collision, il n'y en a pas des masses (à peine 200 ou 300 répertoriés, donc tu peux même les stocker en base et vérifier que le début de ta chaîne ne coincide pas avec une collision wink.gif). Dans tous les cas, ces collisions ne sont pas un problème pour sha-1 par exemple. Tu peux donc très bien si tu veux absolument te rassurer stocker sha-1(M)+md5(M). Dans le cas ou sha-1 soit cassé par une collision, ton md5 se portera très bien, et vice-versa. Avant qu'on trouve une collision qui permette de casser ça, je pense que ton appli fera partie de la préhistoire.

Mais bon, md5 pour vérifier l'intégrité de petites données (toutes les collisions trouvées sont assez lourdes, bien plus que les 1024 caractères qu'on manipule au maximum en général dans ce type d'échange) est absolument suffisant. md5 n'est pas cracké, on a trouvé quelques cas particuliers permettant éventuellement d'abuser la vérification par hashage.
PMEmail PosterUsers WebsiteICQYahoo
Top
mini TilK
Ecrit le : Mardi 08 Août 2006 à 14h10
Quote Post


Newbie
*

Groupe : Membre
Messages : 7


Bon j'ai fini de manger et lu pas mal d'articles :

Le plus interessant à mon avis est celui ci :
http://www.cits.rub.de/MD5Collisions/
avec de slides explicatifs :
http://www.cits.rub.de/imperia/md/content/...s/rump_ec05.pdf

En gros, ils disent qu'il est possible de générer pour une entête donnée appelée A, deux strings R1 et R2 différentes tels que

MD5( A + R1) = MD5( A + R2 )

On peut donc concaténer B alors :

MD5( A + R1 + B ) = MD5( A + R2 + B )

Donc en fait je m'étais trompé dans mon énoncé de tout à l'heure, il devient :

Pour tout A, il est possible de calculer R1 et R2 tel que pour tout B on ai :
MD5( A + R1 + B ) = MD5( A + R2 + B )

Ce qui revient à dire dans notre cas si R1 et R2 sont calculables rapidement (l'info date de 2005 et ils disent plusieurs heures), il est donc possible de rendre un peu moins aléatoires les jets de dés...
PMEmail Poster
Top
naholyr
Ecrit le : Mardi 08 Août 2006 à 14h19
Quote Post


Ouf
*

Groupe : Membre
Messages : 423


Bon, je vois que tu es définitivement faché avec md5 laugh.gif

Voici plusieurs solutions imparables actuellement, en tous cas pas en moins de quelques jours et pas avant quelques années biggrin.gif :
- sha1(sel+string)+md5(sel+string)
- longueur(string)+':'+md5(sel+string)
- voire longueur(string)+':'+sha512(sel1+string)+':'+md5(sel2+string) laugh.gif

Mais je maintiens que ce n'est pas la bonne voie. Soit le serveur ne tourne pas sur la machine de l'utilisateur, et dans ce cas il n'y a rien à pirater, soit le serveur tourne effectivement sur la machine de l'utilisateur et alors tu es en train de te prendre la tête sur les jets de dés alors que d'autres problèmes se poseront plus tard, jusqu'à ce que tu fasses la vérification ultime : valider le serveur en lui-même.
PMEmail PosterUsers WebsiteICQYahoo
Top
MégaBeber
Ecrit le : Dimanche 13 Août 2006 à 22h54
Quote Post


Newbie
*

Groupe : Inscrits
Messages : 1


je suis entièrement d'accord avec naholyr. ce n'est pas la bonne voie.

supposons que ce protocole soit trouvé et mis en oeuvre dans ton soft. supposons que je sois un vilain petit tricheur. je me contenterai simplement de tirer un nouveau nombre aléatoire à l'issu des échanges avec le client; ou avant peu importe. L'idée est que je me plie au protocole, mais que je n'utilise pas le nombre sur lequel on est censés être d'accord.

la seule solution que je vois (mais comme elle est plutôt lourde, je te souhaite d'en trouver une autre) est, comme le suggère naholyr, de valider le serveur par les clients. et pour ca, réaliser tous les calculs également sur les clients, uniquement dans le but de contrôler qu'ils sont d'accord avec le serveur.

exemple : le joueur 1 attaque le joueur 3
C1 --> S : j'attaque C3
S : réalise l'action tout seul dans son coin
S --> C* : C1 a attaqué C3, succès, C3 perd n points de vies .....
C* : réalise l'action tout seul dans son coin. si le résultat diffère de celui du serveur => corruption (du client OU du serveur)

ca introduit qqs contraintes :
  • clients et serveur doivent manipuler les mêmes données,
    • le serveur doit transmettre toutes les données initiales du jeu (germe du tirage aléatoire compris) à tous les clients en début de partie
    • les clients doivent mettre à jour leurs données internes après chaque action (pour rester cohérent avec le serveur),
    • chaque client doit rejouer toutes les actions, mêmes si elles ne le concernent pas (pour rester cohérent avec le serveur d'une part, et pour rester synchro sur les tirages aléatoires d'autre part).
  • clients et serveur doivent avoir la même implémentation,
    • le plus simple est de versionner le soft, et de s'assurer que clients et serveur aient la même version (phase d'init de la partie par exemple),
    • il faut qu'ils génèrent les mêmes nb aléatoires.
Je suppose que la fct random ne varie pas d'une jvm à l'autre, mais c'est à vérifier, et si ce n'est pas le cas, il faut écrire ta propre fct (on trouve des exemples d'implémentations , chapitre 7)
Le versionnage du soft peut sembler un peu hors-sujet, mais ca permet d'éviter une mauvaise qualification de problème (dire qu'il s'agit de triche alors que c'est une correction de bug par exemple), et ca permet de les anticiper (détection dès le début de la partie, alors que la triche ne pourra être détectée qu'en cours de partie).

avec tout ca, un tricheur ne peut plus modifier le déroulement d'une partie. par contre, il peut toujours corrompre les données initiales, avant de les envoyer aux clients. pour éviter ca, je pense qu'il suffit que chaque client vérifie que les données qui le concerne sont bien celles qu'il a envoyé au serveur. Je n'ai pas poussé très loin ma réflexion la dessus, mais si le serveur veut toujours corrompre les données, ca l'oblige à gérer plusieurs jeux de données, et je pense que ca devient vite ingérable quand on avance dans une partie (apparition d'incohérences ...)

Remarque: cette solution fait l'hypothèse que la plupart des joueurs utiliseront une version "valide" du soft. si tous les joueurs d'une même partie utilisent la même version modifiée, les clients n'y verront que du feu!

voila, en espérant ne pas répondre à côté de la question ...
PMEmail Poster
Top
« Sujets + anciens | Programmer | Sujets + récents »

Reply to this topicStart new topicStart Poll