[java] garantir l'intégrité d'un client

J’ai un problème de sécurité avec un programme java en cours de développement.

A ma gauche j’ai un serveur, peu importe ce qui tourne dessus, il ne sert qu’à enregistrer les données qu’on lui communique avec un minimum de vérification.
A ma droite j’ai un client Java (qui existera à la fois sous forme d’applet et de programme stand-alone) qui va envoyer des données au serveur.

Pour aider à visualiser la situation, il s’agit d’un jeu. Mon problème est que toute la logique du jeu (application des règles, calcul des résultats des actions du joueur etc.) est située côté client. Une fois un coup effectué, le client envoit l’info au serveur qui l’enregistre.
Si j’ai tous les moyen nécessaires pour garantir que l’envoi des infos est bien effectué par le jouer qui s’est loggé et pas par quelqu’un d’autre, je ne vois pas en revanche comment faire pour garantir que le joueur en question n’a pas hacké le client pour pouvoir jouer des coups interdits en temps normal.

Ma question est donc la suivante: existe-il un moyen de faire, au runtime, une sorte de signature des jar composant mon application afin que le client l’envoie au serveur pour prouver qu’il s’agit bien d’un client non-modifié ? Le mécanisme inverse de la signature d’applet en quelque sorte.

J’ai bien conscience que dans la théorie mon problème est insoluble: le joueur ayant toute lattitude pour modifier le client, il peut aussi hacker le mécanisme de vérification. Mais en utilisant la signature come clé pour transmettre les infos, je pourrais déjà obliger le hacker à modifier son appli dès que les jars changent de signature (ce qui risque d’arriver souvent).

Je ne suis pas sûr d’avoir été très clair dans mon exposé, donc si vous avez des questions, allez-y, j’ai besoin d’idées là :stuck_out_tongue:

Je connais pas trop le pb, mais il me semble que le Jar, c’est un format de compression ? C’est du zip non ? Dans ce cas, le jar doit avoir un CRC qui permet de vérifier son intégrité. Tu peux peut-être regarder ce CRC pour voir s’il n’a pas changé.
Il n’empêche, pourquoi ne pas faire ces calculs côté serveur ?

[quote name=‹ kaneloon › date=’ 9 Mar 2005, 10:43’]Il n’empêche, pourquoi ne pas faire ces calculs côté serveur ?
[right][post=« 339482 »]<{POST_SNAPBACK}>[/post][/right][/quote]
Parce qu’implémenter le moteur d’un jeu c’est beaucoup plus facile à faire en java sur un client qu’en php sur un serveur mutulisé aux performances incertaines :stuck_out_tongue:
Le fait de gérer les « règles du jeu » côté client n’est malheureusement pas négociable.

Hum, on peut modifier un .class comme ça avec un éditeur de texte? Si non, cela me parait simple, tu ne mets que les .class dans le jar et le tour est joué. Je ne vois pas comment le joueur aurait toute latitude pour modifier un binaire…

[quote name=‘LeBaronNoir’ date=’ 9 Mar 2005, 10:58’]Je ne vois pas comment le joueur aurait toute latitude pour modifier un binaire…
[right][post=“339492”]<{POST_SNAPBACK}>[/post][/right][/quote]
Ca se décompile un binaire (surtout en java je crois), sinon y a toujours moyen de le bidouiller (et le bytecode java doit pas etre le plus difficile a comprendre)…
Tu crois qu’ils font comment les warezboyz?

Oui le format jar c’est du zip tout con. Un jar contient toutes les classes du programme compilé en byte-code ainsi que les ressources.
Les classes sont au format *.class, format super pas inpénétrable, voire même super facilement décompilable (par exemple avec DJ Java Decompiler).

Tu peux donc utiliser un “obfuscator” (je connait pas la traduction francaise) qui permet de protéger tes *.class contre la décompilation.

Au hasard :

RetroGuard Java Obfuscator : http://www.retrologic.com/

Java Source Code Obfuscator : http://www.semdesigns.com/Products/Obfusca…Obfuscator.html

Par contre, je n’ai aucune idée de la qualité de ces softs, mais ca rendra la tache des éventuels tricheurs plus difficile.

L’obfuscation est prévue, et je pense qu’elle en découragera certains, mais ça ne rend pas le programme indécompilable pour autant :stuck_out_tongue:
Mon problème se pose en considérant que le hacker a réussi à décompiler le code (ce qui est malheureusement plutôt facile en java).

Tu pourrais partir du principe que de toute façon ton programme sera cracké, dans ce cas là, tu peux faire en sorte de faire des patchs qui corrigent certains exploit…C’est plus de boulot mais c’est un moyen couramment utiliser.
Dans le même temps, repérer les gens qui cheat et les virer de ta base (Blizzard style), c’est aussi très efficace.

A mon avis tu n’arriveras jamais à prévenir toutes les erreurs (par exemple, est ce que des gens ne pourraient pas utiliser un programme tiers qui leur sert de hack ?), alors autant les corriger au fur et à mesure qu’elles arrivent.

my 2 cents

Pas vraiment simple comme problème. Déjà tu pourrais regarder du côté des systèmes de signature de jar. exemple trouvé avec google : http://java.sun.com/j2se/1.5.0/docs/guide/…olsSummary.html

Ensuite, tu peux envisager de chiffrer les données échangées avec des clés, mais si tu ne maîtrises pas les deux bouts du tuyau, ta solution sera forcément limitée.

Le coup du jar signé (si c’est faisable facilement, j’en suis pas très sur, because certificats payants pour les autorités commerciales, etc) te prémuniera déjà contre les problèmes de modification de ton code, ensuite, il sera facile de protéger tes échanges de données.

[quote name=‘Styx31’ date=’ 9 Mar 2005, 14:35’]Le coup du jar signé (si c’est faisable facilement, j’en suis pas très sur, because certificats payants pour les autorités commerciales, etc) te prémuniera déjà contre les problèmes de modification de ton code, ensuite, il sera facile de protéger tes échanges de données.
[right][post=“339572”]<{POST_SNAPBACK}>[/post][/right][/quote]
Oui mais non. Le système de signature garantit à l’utilisateur que le jar qu’il utilise est bien celui promis par le serveur. Moi je veux faire l’inverse: garantir qu serveur que le client qui se connecte est une version non modifiée de mon code.

[quote name=‘Styx31’ date=’ 9 Mar 2005, 14:35’]Ensuite, tu peux envisager de chiffrer les données échangées avec des clés, mais si tu ne maîtrises pas les deux bouts du tuyau, ta solution sera forcément limitée.
[right][post=“339572”]<{POST_SNAPBACK}>[/post][/right][/quote]
Pour les données échangées, pas de problème, c’est crypté et ça marche. Le problème c’est si le joueur bidouille les données avant de les envoyer.

/invoke Glop

GloP, il va te dire de faire tout ça en C# :P".

Arf non je vais juste te dire que t’es baise et que y a juste pas moyen. Tu peux commencer a essayer de limiter la casse en faisant un truc du genre, a la procedure d’authentification:

  • client: bonjour je veux me loguer je suis machin avec le pass truc pour la version client 1.0.2439
  • serveur: bonjour voici du sel sous forme d’une chaine de 10 char au hasard: « WHKHWIERH », et un index de debut et de fin au hazard aussi pris en dessous de la taille connue du .jar
  • client: ca roule, je fais le MD5 de mon .jar entre ces deux index + le sel et je te le renvois
  • serveur: c’est bien ca a quoi je m’attend, go

Maintenant si tu decompile et que tu as le droit de recompiler et d’executer la version modifiee c’est limite trivial de renvoyer ce qu’il faut.

En C# a priori le probleme ne se pose pas de la meme maniere :stuck_out_tongue: tu peux signer une assembly avant de l’envoyer avec ta clef privee, et si la signature est pas la bonne au lancement, elle s’execute pas. Une assembly signee est donc pas modifiable et ca fait parti du framework. Beaucoup plus chiant de modifier une assembly a la volee car ca implique que tu es capable de tout recompiler (meme les autres DLL parceque tu peux forcer le linkage a se faire qu’avec les DLL signees en question) a partir du code desassemble et c’est pas si simple que ca en a l’air (par rapport a changer le bytecode pour renvoyer toujours « 100 » a un lance de D100). En C# pour vraiment faire chier tu pourrais envisager d’envoyer une micro assembly au login qui fait un calcul different a chaque fois et qui linke seulement avec l’assembly a la bonne signature, et si ca marche c’est bon. Ca serait ptet le plus beton a mon avis en y reflechissant que 10 secondse… Ptet que recemment dans Java il y a un truc similaire mais je me souviens de rien de ce genre. Enfin bon rien ne t’empeche de re-ecrire un client de zero ou de tout recompiler avec ta propre signature et d’envoyer ce que tu veux.

Tu peux pas faire confiance a ton client, y a juste pas moyen, tout les calculs a risque de hack/triche doivent se faire cote serveur :stuck_out_tongue:

Ça rejoins les conclusions auxquelles l’autre codeur du projet et moi étions arrivés. :stuck_out_tongue:

On va donc se contenter d’essayer de brouiller les pistes à coup d’obfuscation, de grains de sels et de checksums, et bien sûr d’une politique intraitable de suppression des comptes louches avec exposition du cadavre sur la page d’accueil prendant trois semaine.

Et puis dans 5 ans, pour le prochain jeu, peut-être que j’aurais appris le C# :stuck_out_tongue: