¿Cómo dividir el inicio de sesión y la lógica del juego al escribir servidores?

9

Estoy construyendo un servidor de juegos de póquer, iba a tener todos los inicios de sesión y la lógica del juego para ser manejados en un servidor, pero de mi investigación en la web, aprendí que esto no escalaría, y tendría sentido dividir el trabajo en un servidor de inicio de sesión y juegos. Pero lo que no obtengo es que después de manejar la autenticación en el servidor de inicio de sesión y hacer que el cliente establezca una nueva conexión con el servidor del juego, ¿cómo podría saber qué cliente es cuál? ¿No tendría que volver a iniciar sesión de nuevo y, por lo tanto, anular el propósito de tener un servidor para iniciar sesión? ¿Hay alguna forma de pasar una conexión a través de procesos y máquinas que no conozco? Disculpe mi poco conocimiento de las redes.

usuario342580
fuente
44
YAGNI: no lo vas a necesitar. No implemente una optimización prematura. Iniciar sesión suena como una parte muy trivial del juego, es poco probable que dividirlo proporcione algún beneficio; Una vez que su juego tenga suficientes usuarios que le interesen (debería poder admitir a miles de usuarios en un solo servidor, con otros solo por redundancia), podrá contratar a algunos ingenieros de software que entiendan este tipo de cosas.
MarkR
Aceptaste una respuesta engañosa, debes reconsiderarla cuidadosamente, o terminarás con nociones equivocadas en tu cabeza y con una falsa sensación de seguridad en tu código.
o0 '.
Me gustó la respuesta de Kylotan porque no tengo que tener una conexión adicional entre los servidores del juego y el servidor de inicio de sesión, también puedo ver el punto de Philip de que un compromiso de la clave secreta es un compromiso en todas las cuentas que es de carga. Implementaré ambas versiones de inicio de sesión y le preguntaré a un experto en seguridad cuando audite mi código. Mi pregunta parece bastante básica y esperaba que fuera una solución estándar en la que todos estuvieran de acuerdo. Imagínate. Si solo un experto en seguridad puede entrar en esta discusión y tomar una decisión.
user342580
Estrictamente hablando, pasar el token de inicio de sesión entre sus servidores es más seguro, siempre que tenga un canal seguro para hacerlo. También es más difícil de implementar, lo que aumenta el riesgo de que te equivoques. Un sistema de autenticación de mensajes basado en hash debe ser perfectamente seguro a menos que alguien pueda obtener su clave secreta, y si puede obtener su clave a través del acceso a sus sistemas internos, tiene problemas que no se solucionarán enviando el inicio de sesión fichas de forma manual.
Kylotan

Respuestas:

3

Aunque la respuesta de Philipp es perfectamente buena, hay una forma ligeramente diferente que no requiere una conexión entre el servidor de inicio de sesión y el servidor del juego, lo cual es útil si dicha conexión es difícil.

  1. Cuando el usuario se autentica con éxito en el servidor de inicio de sesión, se le envía una dirección de servidor de juego y un token de inicio de sesión como se indicó anteriormente. Sin embargo, este token consta de 2 partes: el tiempo en el servidor de inicio de sesión y un hash de ese número más su nombre de usuario, su dirección IP, la dirección IP o ID del servidor del juego y una clave secreta que solo usted conoce.
  2. El cliente intenta iniciar sesión en el servidor de juego proporcionado enviando este token. El servidor forma el mismo hash que antes, según la información en el token de inicio de sesión más su propia dirección IP / ID y la clave secreta. Si este hash coincide con el del token, sabes que el jugador se autenticó correctamente. Luego verifique que la fecha no sea demasiado antigua (p. Ej., Más de 1 minuto).

Esto funciona porque:

  • No se puede copiar y reutilizar ya que la fecha caducará.
  • No se puede construir sin un nuevo inicio de sesión sin conocer la clave secreta.
  • No puede ser fácilmente interceptado por otra persona (por ejemplo, con un sniffer de paquetes) y utilizado porque la dirección IP original se utiliza para construirlo.
  • No se puede usar para una cuenta diferente ya que el nombre de usuario forma parte del hash.
  • No se puede usar para inicios de sesión simultáneos en diferentes servidores de juegos, ya que la dirección ID / IP del servidor forma parte del hash.

O, para decirlo de manera más simple, el hash asegura que es casi imposible que el remitente haya falsificado su token de inicio de sesión, por lo que se puede confiar en la información del token.

Al igual que con cualquier hash orientado a la seguridad, use la mejor función de hash que pueda obtener, en este momento a la gente parece gustarle bcrypt, PBKDF2 y scrypt, y asegúrese de que su clave secreta sea muy larga para que la reproducción de la fuerza bruta sea menos práctica.

Kylotan
fuente
Muy inteligente, prefiero esta solución. Mi pregunta es entonces la clave secreta. ¿Debería ser como una frase de paso o algo así? ¿Y debería ser diferente para cada usuario?
user342580
Esto no funciona o, en realidad, es una re-implementación oculta de la respuesta de @ Philipp. Falla porque supone que tanto el servidor de inicio de sesión como el servidor del juego conocen esa misma clave secreta. Si ambos conocen la clave, uno de ellos debe comunicarse con el otro para proporcionarla. O necesita un tercero para enviárselo a ambos. De cualquier manera, es tan sniffable como antes.
o0 '.
@Lohoris, la idea es que poseas tanto el inicio de sesión como el servidor del juego y puedas proporcionarles la clave secreta. Si no poseía ambos servidores, ¿cómo podría el servidor de juegos confiar en la autenticación del servidor de inicio de sesión de todos modos?
Kylotan
@ user342580: usaría una frase larga de algún tipo. No tiene que diferir por usuario, pero si lo hiciera, eso no estaría de más. Siempre que la función de cifrado hash sea lo suficientemente fuerte y la cambie periódicamente, no debería importar.
Kylotan
@Kylotan exactamente, y ¿cómo les proporciona la clave? ¿Por qué considera más segura la conexión de usted a los servidores que la de un servidor a otro?
o0 '.
8
  1. Después de que el usuario se haya autenticado en el servidor de inicio de sesión, dele un token (una cadena única, generada aleatoriamente, demasiado larga para ser adivinada).

  2. El servidor de inicio de sesión elige un servidor de juegos. Envíe el token, el nombre de usuario y todos los demás datos relevantes sobre el usuario desde el servidor de inicio de sesión al servidor que seleccionó.

  3. Envíe el token y el nombre de host del servidor de juegos al cliente. Luego desconéctelo del servidor de inicio de sesión.

  4. El cliente luego se conecta al servidor de juegos con su nombre de usuario y token.

  5. Cuando el token del cliente coincide con el que acaba de informar el servidor de inicio de sesión, lo acepta.

Tenga en cuenta que para que esto sea seguro, los tokens deben crearse a partir de un generador de números aleatorios criptográficamente seguro, cada token solo puede ser aceptado una vez por el servidor de juegos y los tokens no utilizados deben descartarse después de unos minutos.

Philipp
fuente
Entonces, ¿sería suficiente con bcrypt? Estoy pensando en crear un token a partir del hash del tiempo + nombre de usuario + contraseña usando bcrypt.
user342580
Supongo que sí. Se podría adivinar un token cuando se conoce la contraseña, pero cuando se conoce la contraseña, se puede iniciar sesión normalmente.
Philipp
1
bcrypt funciona siempre que la entrada sea adecuadamente aleatoria e inestimable. Si solo usa el tiempo, el atacante puede intentar predecir el tiempo, luego ejecutar bcrypt y obtener el token. Asegúrese de utilizar una sal secreta con el tiempo o un aleatorizador seguro (por ejemplo, / dev / random en sistemas UNIX / Linux).
Sean Middleditch
La contraseña podría haber sido comprometida en otro sitio, por lo que evitaría asumir que es un secreto adecuado.
Sean Middleditch
1
@SeanMiddleditch Cuando la contraseña se ve comprometida, toda la seguridad se pierde de todos modos. Un atacante que obtuvo la contraseña no tiene ninguna razón para adivinar un token, porque podría obtener uno ingresando de la manera normal.
Philipp