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.


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.


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.


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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.