Como dividir a lógica de logon e jogo ao escrever servidores?

9

Eu estou construindo um servidor de pôquer como o jogo, eu teria todos os logins e lógica de jogo para serem manipulados em um servidor, mas, com minha pesquisa na web, eu aprendi que isso não seria escalável e faria sentido dividir o trabalho em servidores de logon e jogo. Mas o que eu não entendo é que depois que lidei com a autenticação no servidor de logon e o cliente fez uma nova conexão com o servidor do jogo, como eu saberia qual cliente é qual? Não precisaria fazer o login novamente novamente e, assim, anular o propósito de ter um servidor para login? Existe alguma maneira de transmitir uma conexão entre processos e máquinas que eu não conheço? Desculpe meu pouco conhecimento de rede.

user342580
fonte
4
YAGNI: você não vai precisar disso. Não implemente uma otimização prematura. O login parece uma parte muito trivial do jogo, é improvável que dividi-lo traga benefícios; Depois que o jogo tiver usuários suficientes para você (você deve oferecer suporte a milhares de usuários em um único servidor, com outros apenas para redundância), poderá contratar alguns engenheiros de software que entendam esse tipo de coisa.
MarkR
Você aceitou uma resposta enganosa, deve reconsiderá-la com cuidado ou acabará com noções erradas em sua cabeça e com uma falsa sensação de segurança em seu código.
o0 '.
Gostei da resposta de Kylotan, porque não preciso ter uma conexão extra entre os servidores de jogos e o servidor de login, também posso ver o ponto de Philip de que um comprometimento da chave secreta é um comprometimento em todas as contas que estão sendo pagas. Implementarei as duas versões de login e perguntarei a um especialista em segurança quando eu receber meu código auditado. Minha pergunta parece bastante básica e eu esperava que a solução deles fosse uma solução padrão com a qual todos concordassem. Vai saber. Se apenas um especialista em segurança puder entrar nessa discussão e tomar uma decisão.
user342580
A rigor, passar o token de login entre seus servidores é mais seguro, desde que você tenha um canal seguro para fazer isso. Também é mais difícil de implementar, o que aumenta o risco de você errar. Um sistema de autenticação de mensagens baseado em hash deve ser perfeitamente seguro, a menos que alguém possa se apossar da sua chave secreta - e se eles puderem se apossar da sua chave através do acesso aos seus sistemas internos, você terá problemas que não serão corrigidos enviando o login tokens manualmente.
Kylotan

Respostas:

3

Embora a resposta de Philipp seja perfeitamente boa, existe uma maneira um pouco diferente que não requer uma conexão entre o servidor de login e o servidor do jogo, o que é útil se a conexão for difícil.

  1. Quando o usuário se autentica com sucesso no servidor de logon, ele recebe um endereço do servidor de jogo e um token de logon, como acima. No entanto, esse token consiste em 2 partes: a hora no servidor de login e um hash desse número, mais o nome de usuário, o endereço IP, o endereço IP ou o ID do servidor do jogo e uma chave secreta que somente você conhece.
  2. O cliente tenta fazer login no servidor de jogos fornecido enviando esse token. O servidor forma o mesmo hash de antes, com base nas informações no token de login, mais seu próprio endereço IP / ID e a chave secreta. Se esse hash corresponder ao do token, você saberá que o jogador foi autenticado corretamente. Depois verifique se a data não é muito antiga (por exemplo, mais de 1 minuto).

Isso funciona porque:

  • Não pode ser copiado e reutilizado, pois a data expira.
  • Não pode ser construído sem um novo login sem conhecer a chave secreta.
  • Ele não pode ser facilmente interceptado por outra pessoa (por exemplo, com um sniffer de pacote) e usado porque o endereço IP original é usado para construí-lo.
  • Ele não pode ser usado para uma conta diferente, pois o nome de usuário faz parte do hash.
  • Ele não pode ser usado para logins simultâneos em diferentes servidores de jogos, pois o endereço IP / ID do servidor faz parte do hash.

Ou, para simplificar, o hash garante que é quase impossível para o remetente falsificar seu token de login e, portanto, confiar nas informações no token.

Como em qualquer hash orientado a segurança, use a melhor função de hash que você pode obter - no momento, as pessoas parecem gostar de bcrypt, PBKDF2 e scrypt - e garanta que sua chave secreta seja muito longa para tornar a reprodução de força bruta menos prática.

Kylotan
fonte
Muito esperto, prefiro muito esta solução. Minha pergunta é então a chave secreta. Deve ser como uma frase secreta ou algo assim? E deveria ser diferente para cada usuário?
user342580
Isso não funciona ou, na verdade, é uma reimplementação oculta da resposta de @ Philipp. Ele falha porque assume que o servidor de login e o servidor de jogos conhecem a mesma chave secreta. Se os dois souberem a chave, um deles precisará entrar em contato com o outro para fornecê-la. Ou você precisa de um terceiro para enviá-lo aos dois. De qualquer forma, é tão fácil de detectar quanto antes.
o0 '.
@ Lohoris, a idéia é que você possui o login e o servidor do jogo e pode fornecer a chave secreta. Se você não era o proprietário dos dois servidores, como o servidor do jogo poderia confiar na autenticação do servidor de login?
Kylotan
@ user342580: Eu usaria uma frase longa de algum tipo. Ele não precisa ser diferente por usuário, mas se o fizer, isso não prejudicará. Desde que a função de hash criptográfico seja forte o suficiente e você a altere periodicamente, isso não deve importar.
Kylotan
@Kylotan exatamente, e como você lhes fornece a chave? Por que você considera mais segura a conexão de você com os servidores do que de servidor para servidor?
o0 '.
8
  1. Depois que o usuário se autenticar no servidor de logins, forneça um token (uma sequência exclusiva gerada aleatoriamente por muito tempo para ser adivinhada).

  2. O servidor de log escolhe um servidor de jogos. Envie o token, o nome de usuário e todos os outros dados relevantes sobre o usuário do servidor de logon para o servidor escolhido.

  3. Envie o token e o nome do host do servidor de jogos para o cliente. Em seguida, desconecte-o do servidor de logins.

  4. O cliente então se conecta ao servidor de jogos com seu nome de usuário e token.

  5. Quando o token do cliente corresponde ao que foi relatado pelo servidor de logins, você o aceita.

Observe que, para que isso seja seguro, os tokens precisam ser criados a partir de um gerador de números aleatórios criptograficamente seguro; cada token pode ser aceito apenas uma vez pelo servidor de jogos e os tokens não utilizados devem ser descartados após alguns minutos.

Philipp
fonte
Então, usar o bcrypt seria suficiente? Estou pensando em criar um token a partir do hash do tempo + nome de usuário + senha usando bcrypt.
user342580
Eu acho que sim. Pode-se adivinhar um token ao saber a senha, mas quando você a conhece, você pode simplesmente fazer o login da maneira normal.
Philipp
11
O bcrypt funciona desde que a entrada seja adequadamente aleatória e impraticável. Se você apenas usar o tempo, o invasor pode tentar prever o tempo, executar o bcrypt e obter o token. Certifique-se de usar um salt secreto com o tempo ou um randomizador seguro (por exemplo, / dev / random nos sistemas UNIX / Linux).
Sean Middleditch
A senha pode ter sido comprometida em outro site, por isso evito assumir que é um segredo adequado.
Sean Middleditch
11
@SeanMiddleditch Quando a senha é comprometida, toda a segurança é perdida de qualquer maneira. Um invasor que obteve a senha não tem motivos para adivinhar um token, porque ele pode obter um logon normalmente.
Philipp