Javascript anti-trampas para navegador / juego HTML5

35

Estoy planeando aventurarme a hacer un RPG de acción para un solo jugador en js / html5, y me gustaría evitar hacer trampa. No necesito una protección del 100%, ya que no será un juego multijugador, pero quiero algún nivel de protección.

Entonces, ¿qué estrategias sugieres más allá de minificar y ofuscar?

No me molestaría en hacer una comprobación simple del lado del servidor, pero no quiero seguir el camino de Diablo 3 manteniendo todos mis cambios de estado del juego en el lado del servidor.

Como va a ser una especie de juego de rol, se me ocurrió la idea de hacer un inspector de estadísticas que verifique los cambios abruptos en sus valores, pero no estoy seguro de qué tan consistente y confiable puede ser.

¿Qué pasa con las variables y funciones escopes? Trabajar en escopes más pequeños siempre que sea posible es más seguro, pero ¿vale la pena el esfuerzo?

¿Hay alguna forma de que el javascript inspeccione su texto, como en una suma de verificación?

¿Hay soluciones específicas para el navegador? No me molestaría en restringirlo para Chrome solo en las primeras compilaciones.

Billy Ninja
fuente
¿Dónde se guardan sus datos, cómo se guardan sus datos?
DogDog
Es curioso que hables de Diable 3, la "forma de Diablo 1" era exactamente eso, confiando en el cliente. ¡Haz una búsqueda en Google si eres demasiado joven para recordar lo que sucedió por eso!
Valmond
Apoc, en este momento solo tengo una prueba de concepto y no he implementado ningún tipo de persistencia, pero planeo implementar algo de persistencia DB en las primeras compilaciones y / o almacenamiento local para que los jugadores no puedan seguir jugando desde donde se fueron. Sí, Valdmond jugué mi parte de Diablo en ese entonces. Pero no estoy construyendo un juego multijugador competitivo, o un AAA completamente marcado. Byte56, no estoy preocupado por robar mi código (¿quién querría esa basura de todos modos?)
Billy Ninja
desafortunadamente, tienes que seguir el camino de diablo 3, si realmente te preocupan los hacks / trucos
Noob Game Developer

Respuestas:

46

La respuesta corta es que no puedes hacerlo. Cualquier cosa que se ejecute del lado del cliente, especialmente desde la fuente, se puede modificar para derrotar sus tácticas de manera trivial. Si implementa un verificador del lado del cliente para buscar cambios abruptos, un usuario puede simplemente deshabilitar el verificador.

La buena noticia es que, en general, hay muy pocas trampas en los juegos para un jugador. La única excepción importante es para los juegos que tienen grandes comunidades "youtube highscore" como Line Rider, donde los jugadores compiten entre sí en YouTube.

Si estás apuntando a eso, o eres demasiado terco para aceptar que las personas podrían hacer trampa en el juego, o estás manteniendo puntuaciones altas (que es una forma de multijugador), entonces lo que debes hacer son todos los cálculos del lado del servidor . Sí, todo lo que importa. Ni siquiera puede repetir el lado del cliente de cálculo para intentar darle al usuario el puntaje y luego 'verificarlo' con el servidor porque el usuario puede simplemente deshabilitar el cheque y deshabilitar cualquier sistema que garantice que haya cheques.

Desearía que hubiera una mejor respuesta a esto, pero no la hay.

Dicho esto, hay cosas que puedes hacer para que sea un poco más difícil hacer trampa. No detendrán a nadie serio de hacerlo y lanzar un juego de herramientas para hacer trampa, pero los ralentizará:

  • Minifique y ofusque su JS, lo que hará que el código sea más difícil de leer. Puede desminificar y ordenar ofuscar, pero nunca puede recuperar los nombres correctos de variables y funciones, ni comentarios.
  • Hornee en valores con un idioma diferente. En este caso, puede usar PHP u otros lenguajes del lado del servidor para manejar variables de configuración estáticas. Si se supone que la distancia de salto siempre debe ser de 2 espacios, normalmente definiría una distancia de salto para el objeto jugador. No, maneje eso con PHP para que la fuente JS termine con 2s pegados en todo el código en un millón de lugares. Esto tiene el feliz efecto secundario adicional de poder acelerar tu JS también.
  • Con algo de práctica, dominarás la mezcla e incluso puedes personalizar tu JS para cada jugador. Que es otra forma de evitar las trampas. Si el código de cada jugador es diferente de alguna manera, entonces es más difícil escribir un truco que pueda ser parte de un juego de herramientas.
  • Finalmente, puede sumar la fuente de verificación en función de la identidad del jugador. Diga su dirección IP y / o nombre de usuario. Sabes cuál será la versión específica del jugador del JS, puedes hornear en una suma de verificación y requerir que sea la misma en el otro extremo. Fácil de deshabilitar como cualquier JS del lado del cliente, pero una vez más hace que sea un poco más difícil hacer un kit de herramientas.

Asi que. Como puede ver, probablemente no valga la pena seguir esta ruta. Es difícil. Requiere muchas prácticas de codificación realmente tontas y, en última instancia, sigue siendo relativamente fácil de derrotar. Tendrá que hacer todos los cálculos del lado del servidor para evitar trampas. O déjalo ir y acepta que sucederá un engaño

DampeS8N
fuente
El ejemplo del jinete de línea es bastante trivial para el lado del servidor, al permitir que el usuario cargue el mapa que ha dibujado y calcule la puntuación. Pero juegos como las salas de juego son casi imposibles de calcular el puntaje del lado del servidor sin un trabajo extenso.
orlp
@nightcracker Estás en lo correcto, sin embargo, incluso con algo como Line Rider, si solo verificas después de que el juego haya terminado, el video ya está hecho y los YouTubes ya están engañados. Debe cargar el mapa cuando el usuario vaya a presionar Reproducir, calcular la ruta que es trivial y luego enviarlo de vuelta. El juego no debería ser capaz de calcular el camino. (Si estamos hablando de hacerlo a prueba de trampas, lo que ese juego no es. Es bastante simple que las trampas son obvias para sus fanáticos)
DampeS8N
14

Ya respondí una pregunta como esa aquí , y lamento decirlo, pero:

No me molestaría en hacer una comprobación simple del lado del servidor, pero no quiero seguir el camino de Diablo 3 manteniendo todos mis cambios de estado del juego en el lado del servidor.

Es lo más malo que podrías haber dicho aquí. Si quieres hacer un motor "anti-trampa", tendrás que hacerlo. Puede agregar cualquier cosa que desee del lado del cliente, para facilitar el trabajo del lado del servidor, pero nunca debe confiar en el cliente. Toda la lógica que tenga debe ser al menos del lado del servidor. Puede reproducirlo del lado del cliente si lo desea, pero ninguna solución del lado del cliente lo hará.

Y, por cierto, si quieres encontrar la debilidad de tu programa, no lo ofusques, deja que la gente vea tu código y te diga "aquí, tienes un problema".

Eso es bueno para usted, para su código, para sus usuarios y para la comunidad.

dievardump
fuente
3
+1 para la autoridad del servidor, simplemente no funciona si intentas confiar en el cliente ...
Valmond
Es peligroso reproducir cosas del lado del cliente. Tenga cuidado incluso con eso, porque si todo se replica en el lado del cliente, el usuario puede hacer trampa desconectando los cheques con el servidor. Luego pueden jugar, grabar un video y convertirse en una estrella de YouTube. Esto solo es aplicable a los juegos para un jugador, que será este juego.
DampeS8N
Cuando hablo del lado del cliente, es para "cálculo de movimientos", "colisiones", etc. Esto se puede hacer en ambos lados, incluso en un juego de varios jugadores. Los cálculos del lado del servidor siempre deben considerarse prioritarios, pero esto puede ayudar cuando hay latencia del servidor para tenerlo también del lado del cliente. Pero para todo lo que es la lógica de "verificación de trampa", entonces estoy de acuerdo en que todo debería ser del lado del servidor.
dievardump
Sí, lo tengo Pero estoy haciendo el proyecto como un pasatiempo en el poco tiempo libre que tengo. Hacer ese tipo de comprobación del servidor reduciría mucho la complejidad del proyecto, lo que lo haría inviable. Bueno, seguiré avanzando con el proyecto sabiendo eso, y si comienza a hacerse más grande y serio de lo que podría llegar a tener un control serio del lado del servidor, probablemente con Node.js.
Billy Ninja
esta es la respuesta más apropiada para OP
Noob Game Developer
3

Bueno, un buen lugar para comenzar es usar la función Object.freeze (que permitirá la protección contra parches de objetos).

Esto "evita que se agreguen nuevas propiedades", "evita que se eliminen las propiedades existentes", "evita que se cambien las propiedades existentes, o su enumeración, configurabilidad o escritura"; cualquier cambio en el estado interno debe hacerse a través de los accesores. El siguiente ejemplo funciona en Chrome (debería funcionar en Firefox, aunque no sé sobre IE ...):

var b = {}
// Fill your object with whatever you want
b.a = "ewq"
// Freeze all changes
Object.freeze(b)
// Try to put new value. This wont throw any error, put wont work either, 
// as we shall see ...
b.b = "qwe"

// Values 
console.log(b.a); // outputs "eqw"
console.log(b.b); // outputs  undefined
fábula
fuente
55
Incluso esto solo reducirá la velocidad de un tramposo determinado. Si nada más puede robar la fuente, alojarla en su propia máquina y eliminar el código de congelación, y luego usar su archivo de hosts para engañar a su navegador para que piense que la nueva página es la anterior, volviendo a conectarla con el servidor.
DampeS8N
@ DampeS8N Sí, supongo que tienes razón.
fábula el
Como dije en el OP, solo quiero un cierto nivel de protección.
Billy Ninja
¡Esto no ayudará en absoluto! El usuario puede simplemente establecer un punto de interrupción del depurador en la primera función JS que se ejecuta e ingresar Object.freeze = function(o) {};en la consola JS.
Philipp
2

desafortunadamente, tienes que seguir el camino de diablo 3, si realmente te preocupan los hacks / trucos. si no lo está, entonces debe hacer controles básicos o se recomienda encarecidamente.

  • comprar cheques: si estoy comprando algo, debería tener suficiente oro
  • Sellchecks: si estoy vendiendo algo, necesito tener ese artículo en mis cheques comerciales de inventario, lo mismo que vender arma
  • Comprobaciones de equipo: si estoy equipando un arma, ¿la tengo / tengo?
  • damage checks - If I am attacking something (enemy), I can't hit more than the maximum damage my weapon could(here you should not expect the client to tell which weapon he has used because it should have been persisted earlier)
  • crafting checks - If I crafted something, do I have all ingredients/components required?

... and so on

1 point is little bit tricky is the hero's position, since you are not much worried about it you can leave it, but its better you do that too with a minimum check like one below

  • I am at place1 @ T1, I am at place2 T2, what is the minimum time it takes to travel from place1 to place2 and it matches my T2 - T1. You can have mapping of this from small to large depending on the map size. You should have list of at least major areas like, NPC - boss, NPC - enemy spawn area (not necessarily exact location)

Hope this helps, it sounds difficult but you need to learn to make real working games

Noob Game Developer
fuente
Great answer! I was writing a question on how to implement server checking, just to measure roughly how hard it is to implement server checking. You see, I don't wanna waste dozens of hours implementing a MMO-like backbone and at the end of the day it's still easily cheatable just by overriding some client request parameter or something like that. Or simply overdo what was supposed to be a simply fun game -waste effort on security instead of delivering more cool features or polish things.
Billy Ninja
1

Its basically not possible. It would be so easy to work around anything you put in place to prevent cheating.

The thing is with any software you distribute people can modify it in memory easily.

Besides if they want to cheat, let them. They're just ruining the game for themselves. There's no real practical use to cheat in this situation, you'd just destroy the gameplay for yourself.

tsturzl
fuente
1

I had an idea for a measure you could take to prevent/reduce cheating (in addition to other answers). You could have it set up so that the client is not given all the source code at one time, rather that every time the client wants to, say, purchase a new item in the store, that the client would have to send certain information to the server, and only recieve all the information for whatever they are purchasing if the information all matches up with what it's supposed to. If it doesn't, the server blacklists their IP or something.

You could use this in conjunction with what Dampes8n said about using different source versions, that if you can figure out a way to generate a lot of different versions, so that each user would be running an entirely different source version each time, that failing the check blacklists that source version, too, that it won't ever give out the correct item info for that source version ever again.

The main reason this would be effective is that if a hacker doesn't get the hack right the first time, this would make it much harder for them to modify the hack, because every time the hack doesn't work perfectly, they have to change their IP and write the hack all over again for the new source version.

AJMansfield
fuente
I'd be careful. The last thing you want to do is accidentally perma-ban a paying customer.
John McDonald
@JohnMcDonald True, that. Perhaps just killing that source version. That way if they accidentally trigger the trap, they just have to refresh the browser, while still making hackers recode all their hacks.
AJMansfield
0

Yes, it can't fully be done. Always have check on the server. Anything that has an impact on the game should require authorization from the server.

That is the extend to which I will repeat other answers.

However, we can do a lot more towards the end of preventing cheats than just checking on the server. Well, we might have to add some special server checks. However, be aware that client side checks are not worthless, they save bandwidth and server work when cheaters are not involved.

With that said:

  • Mitigate rough clients: Serve over HTTPS, use Cross-origin resource sharing (CORS), allow only the same origin, use subresource integrity. I suggest to implement a service worker to enforce it on all requests, which will also mean that the game won't work by simply moving it to HTTP (because without HTTPS there is no service worker, the server worker is doing the client part of CORS and the server expects CORS), and if they serve over HTTPS it won't work because the server will reject the other origin.
  • Mitigate scripting: Use authentication and require a token to do any action. Each update cycle the server should give the client a new token, and the token is consumed by doing whatever it does... doing anything requires a valid token, the token is always changing, and thus not viable to guess, and if the client sends the same token twice or sends a wrong token the server knows that something is up. For extra protection: create a Message authentication code (MAC) of the token with a secret key and add it to te cookie. Modifying the cookie will kill the session (and they need to guess the key), and modifying the token will make the MAC check fail.
  • Mitigate code modifications: Aside from subresource integrity (which modern browsers will also check in runtime), keep your variables under a limited scope (using let, self executing anonymous functions, and javascript modules). Also, not rely on the DOM (the DOM is for IO only, not storage, if you need to attach attributes wrap your DOM objects and add them to wrappers). This way, whatever you on console should not be able to reach game logic (unless you exploit some browser vulnerability). You might also consider using techniques to detect developer tools (these are specific per browser, and may not work in all cases or stop working in the future... thus, this is an arms race).
  • Something is up? Did the session break? Kick the player from the current match, request to login again. Consider a captcha... that also has the benefit of telling the user that "we know something rare is going on" (it was not a random server failure), and yes, that is a form of mitigation. Oh, and do not foget to log these. You need to be able to verify why they happened, both to prevent false postives and to answer support tickets.

Yes, this are all mitigations. We can still have a custom made browser that will not check integrity and let you reach and mess with variables in local scopes... then the game code will send the modified data with the right token, and that is where the server checks come into play.

Theraot
fuente