¿Qué buenas maneras hay para evitar hacer trampa en los juegos de varios jugadores de JavaScript?
security multiplayer (8)
El servidor es el rey. Los clientes son hackeables
Lo que quieres hacer es dos cosas con tu websocket.
Envía acciones de juego al servidor y recibe el estado del juego del servidor.
Usted renderiza el estado del juego. y envías entradas al servidor.
- apuntar automáticamente: este es difícil de resolver. Tienes que ir por el realismo. Si un usuario golpea 10 disparos a la cabeza en 10ms, entonces lo pateas. Escribe un algoritmo de detección de trampas inteligente.
- asomarse fuera del área visible - resuelto solo enviando el área visible a cada cliente
- pirateo acelerado - resuelto manejando la entrada correctamente. Recibe un evento que el usuario a adelantó y usted controla qué tan rápido va.
NO puedes resolver estos problemas minificando el código. El código en el cliente está SOLAMENTE allí para manejar la entrada y la salida de la pantalla. TODA la lógica tiene que hacerse en el servidor.
Simplemente necesita escribir la validación del lado del servidor. Lo único es que la entrada de un juego es significativamente más difícil de validar que la entrada debido a la complejidad. Es exactamente lo mismo que harías para asegurar las formas.
Sin embargo, debes ser muy cuidadoso con tu detección de "entrada válida". No querrás patear / prohibir jugadores altamente habilidosos de tu juego. Es muy difícil alcanzar el equilibrio de la detección de robots demasiado floja y demasiado estricta en la detección de bots. Todo el reino de la detección de robots es muy difícil en general. Por ejemplo, Quake tenía una detección automática de objetivos que pateaba a los jugadores habilidosos en el día.
En cuanto a detener la conexión de un bots a su websocket, configure directamente un canal de verificación HTTP o HTTPS separado en su juego multijugador para mayor seguridad. Use múltiples canales Http / https / ws para validar a un cliente como "oficial", actuando como una especie de apretón de manos. Esto hará que la conexión al ws sea más difícil.
Ejemplo:
Piensa en un simple juego multijugador. Un juego de carreras basado en sala 2D. Hasta n usuarios van en un mapa plano de plataformas 2D y corren para ir de A a B.
Supongamos, por los argumentos, que tiene un sistema de seguridad infundada donde hay una authetication compleja que pasa por un canal HTTPS para que los usuarios no puedan acceder directamente a su canal de websocket y se vean obligados a pasar por el navegador. Es posible que tenga una extensión de Chrome que se ocupe de la autenticación y obligue a los usuarios a usar eso. Esto reduce el dominio del problema.
Su servidor enviará todos los datos visuales que el cliente necesita para representar la pantalla. No puedes ocultar estos datos. No importa lo que intentes, un pirata informático engañado puede tomar tu código y ralentizarlo en el depurador editándolo a medida que avanza hasta que todo lo que le queda es un envoltorio primitivo alrededor de tu websocket. Él te permite ejecutar toda la autenticación, pero no hay nada que puedas hacer para evitar que elimine el JavaScript que escribes al detenerlo. Todo lo que puede lograr con eso es limitar la cantidad de piratas informáticos lo suficientemente capacitados para acceder a su websocket.
Entonces, el hacker ahora tiene su websocket en un arenero cromado. Él ve la entrada. Por supuesto, su carrera se genera de forma dinámica y única. Si tuvieras una cantidad fija de ellos, entonces el hacker podría pre-diseñar la ruta de carrera óptima. Los datos que envía para visualizar este mapa pueden renderizarse más rápido que la interacción humana con su juego y los movimientos óptimos para ganar su juego de carreras se pueden calcular y enviar a su servidor.
Si intentas prohibir a los jugadores que reaccionaron demasiado rápido a los datos de tu mapa y los llaman robots, el hacker lo ajusta y agrega un retraso. Si tratas de prohibir a los jugadores que juegan demasiado perfectamente, entonces el hacker lo ajusta y juega menos, luego perfecciona usando números aleatorios. Si coloca trampas en su mapa en las que solo entran los robots algorítmicos, se pueden evitar aprendiendo sobre ellas, a través de prueba y error o un algoritmo de aprendizaje automático. No hay nada que puedas hacer para estar absolutamente seguro.
Solo tiene UNA opción para evitar completamente los piratas informáticos. Eso es para construir su propio navegador que no puede ser pirateado. Construya los mecanismos de seguridad en el navegador. No permita que los usuarios editen javascript en tiempo de ejecución en tiempo real.
Imagine un tirador espacial con un nivel de desplazamiento. ¿Qué métodos existen para evitar que un jugador malintencionado modifique el juego para su beneficio? Las cosas que podría hacer que son difíciles de limitar desde el lado del servidor son apuntar automáticamente, mirar fuera del área visible, piratear la velocidad y otras cosas.
¿Qué formas hay de prevenir esto? Supongamos que el servidor es cualquier idioma y que los clientes están conectados a través de WebSocket.
Siempre suponga que el código es 100% pirateable. Piense en maneras de evitar que un cliente completamente reescrito (con el propósito de hacer trampa) haga trampa. Estas pueden ser cosas como métodos para escribir un protocolo de juego seguro, detección en el lado del servidor, etc.
En el lado del servidor, hay 2 opciones:
1) Juego completo del lado del servidor
Cada cliente envía sus "acciones" al servidor. El servidor los ejecuta y devuelve datos relevantes. por ejemplo, un barco quiere moverse hacia el norte, el servidor calcula su nueva posición y la envía de regreso. El servidor también envía una lista de naves visibles (resolviendo maphacks), etcétera.
2) Juego completo del lado del cliente
Cada cliente aún envía sus acciones al servidor. Pero para reducir la carga de trabajo en el servidor, el servidor no ejecuta las acciones sino que las reenvía a todos los demás clientes. Los clientes luego resuelven todas las acciones simultáneamente. Como resultado, cada cliente debe terminar con un juego idéntico. Periódicamente, cada cliente envía sus datos absolutos (posiciones de envío, etc.) al servidor y el servidor comprueba si todos los datos del cliente son idénticos. De lo contrario, los juegos no están sincronizados y alguien debe estar pirateando.
La desventaja del segundo método es que algunos hacks no se detectan: un maphack por ejemplo. Un tramposo puede inyectar código para que lo vea todo, pero solo envía los datos que normalmente debería poder ver en el servidor.
-
En el lado del cliente, hay 1 opción: un componente de JavaScript que escanea el código del juego para ver si algo ha sido modificado (por ejemplo, código modificado para representar objetos que no son visibles pero envían datos de validación diferentes al servidor).
Obviamente, un pirata informático podría desactivar fácilmente este componente. Para solucionarlo, podría forzar al cliente a volver a cargar periódicamente el componente desde el servidor (el servidor puede verificar si el archivo solicitado por el usuario fue periódicamente). Esto introduce un nuevo problema: el pirata informático simplemente solicita periódicamente el componente a través de AJAX pero evita que se ejecute. Para evitar eso: haga que el componente se vuelva a descargar, pero una versión ligeramente modificada de sí mismo.
Por ejemplo: haga que el componente esté ubicado en yoursite / cheatdetect.js? Control = 5. El servidor generará un cheatdetect.js ligeramente modificado para que en la siguiente iteración, cheatdetect.js? Control = 22 (por ejemplo) se deba descargar. Si el mecanismo de control es suficientemente complicado, el hacker no podrá predecir qué número de control solicitará a continuación, y se debe ejecutar cheatdetect.js para continuar el juego.
La única manera en que puedo pensar en implementar esto es modificando su Javascript para que funcione como un cliente y luego diseñe un mecanismo de servidor central para validar los datos enviados desde ese cliente. Este es probablemente un gran cambio para implementar y lo más probable es que haga que su proyecto sea más complejo. Sin embargo, como se dijo anteriormente, si la aplicación se ejecuta completamente en el cliente, el cliente puede hacer prácticamente lo que quiera con su secuencia de comandos. La única forma de protegerlo es utilizar una máquina confiable para manejar la validación.
No hay nada que puedas hacer realmente para evitar que alguien modifique tu JS o escriba un script de GreaseMonkey. Sin embargo, puede hacer que sea difícil para ellos al minificar su secuencia de comandos y hacer que su código sea lo más críptico posible. Tal vez incluso lanzando algunos métodos falsos o variables que no hacen nada pero que se usan para rechazar a un atacante. Pero dado el tiempo suficiente, ninguno de estos métodos es completamente infalible, ya que una vez que su código llega al cliente, ya no es suyo.
No tienen que tocar el código del lado del cliente: podrían simplemente oler e implementar su protocolo Websocket y escribir un pequeño agente que simule ser un jugador humano.
Actualización: El problema tiene algunas partes, y no tengo respuestas en mi cabeza, pero las diversas opciones podrían evaluarse teniendo en cuenta estas preguntas:
- ¿Qué tan lejos estás dispuesto a ir para evitar hacer trampa? Si solo te importan las trampas casuales, ¿cuántas barreras son suficientes para desalentar al tramposo casual? ¿El programador intermedio de Javascript? Un experto serio? Considerando esto contra los beneficios de hacer trampa, ¿hay algo de verdadero valor en juego, como efectivo y premios, o simplemente reputación?
- ¿Cómo se puede tener la alta confianza de que un ser humano está proporcionando entradas para su juego? Por ejemplo, con una biblioteca de visión por computadora lo suficientemente buena, podría modelar tu juego en entradas de alimentación de máquina separadas a la computadora pretendiendo ser el mouse, pero esto tiene un costo relativamente alto (no vale mi tiempo).
- ¿Cómo se puede crear una cadena de confianza en su protocolo para que el conocimiento de (2) pueda pasarse al servidor y que su servidor tenga mucha confianza de que su código de cliente está enviando los mensajes?
Seguro que muchas de las barricadas que arrojas pueden desviarse, pero ¿cuál es el costo para el jugador y para ti? Ver " guerra de desgaste ".
Ofuscar el código expuesto de su cliente tanto como sea posible. Además, usa algo de magia.
Puede editar el javascript en el navegador y hacerlo funcionar. Algunas personas sugieren que haga una llamada para verificar con el servidor. Entonces, después de hacer una llamada al servidor, se validará en el servidor. Una vez validado, llegará al lado del cliente y realizará acciones. Pero creo que incluso esto no es infalible.
Por ejemplo,. para una acción de inicio de sesión básica: en angular al hacer una llamada al servidor, el programa de fondo valida el nombre de usuario y pwd y, si se valida, regresará al cliente y permitirá que el usuario inicie sesión usando angular.
Cuando digo login usando angular, voy a almacenar cosas en cookies, como objetos de usuario y otras cosas. Pero aún así, el usuario puede eliminar el código JS que realiza la llamada al back-end, devolver TRUE (donde sea necesario) e insertar el objeto del usuario (ficticio) en cookies y otros objetos (lo que sea necesario) e iniciar sesión. Es algo muy difícil de hacer, pero es factible. En muchos escenarios, esto no es deseable, incluso si lleva horas editar / piratear el código.
Esto es posible en aplicaciones de una sola página, donde los archivos JS no se vuelven a cargar para cada página. Para mitigar la posibilidad de ser pirateado, podemos usar códigos minificados. Y supongo que si acciones como esta se realizan en back-end (como iniciar sesión en Django) es mucho más seguro.
Por favor, corríjame si estoy equivocado.
Utilizaría una combinación de minificación y AJAX. Si no se cargan todas las funciones y datos en la página, sería más difícil hacer trampa.
Por otro lado, el modding resultó ser una herramienta muy rentable para empresas como Id Software. Tal vez permitir que el sistema sea modificado podría hacer que el juego sea mucho más agradable para la comunidad en general.