Autenticação entre cliente, servidor central e player executou o servidor

8

Estou desenvolvendo um jogo de código aberto que usa um esquema cliente-servidor semelhante ao Minecraft. Controlaremos o servidor de autenticação central que verifica se uma conta é válida, enquanto os jogadores executam seus próprios servidores.

A autenticação do cliente é simples, mas como o servidor pode saber que o usuário é válido, sem ter acesso a credenciais ou token de sessão?

Por exemplo:

  • Cliente> Servidor de autenticação: envia credenciais do usuário.
  • Servidor de autenticação> Cliente: responde com um ID de sessão se o login for válido.

Em seguida, o cliente pode se conectar ao servidor, mas o servidor não tem como verificar se o cliente é quem diz. Esses servidores são executados por jogadores, o que facilita a modificação do servidor e a coleta de dados do usuário. (Somente o servidor de autenticação central pode ser confiável)

O servidor de autenticação pode aceitar conexões TCP, mas me pergunto se o HTTPS seria mais fácil nesse caso, pois obter uma resposta é mais fácil do que estabelecer um ouvinte de cada lado, especialmente para apenas algumas solicitações.

Cyral
fonte

Respostas:

3

Edit: Depois de postar isso, eu percebi que é quase a mesma resposta dada por Ali.S (ligeiramente diferente, mas a abordagem geral é a mesma.) Começou como algo completamente diferente.

Este método pressupõe que todas as comunicações estão sendo mantidas em uma série de túneis seguros. Como você consegue isso não importa. Eu sugeriria TLS, mas sou apenas eu.

  1. Cliente => Servidor do Jogo O cliente se conecta ao servidor do jogo e inicia uma sessão de login.
  2. Servidor de jogos => Servidor de autenticação O servidor de jogos se conecta ao servidor de autenticação e solicita um token de ID de sessão ao servidor de autenticação. Essa conexão é mantida aberta para escutar o êxito / falha do logon.
  3. Servidor de Jogo => Cliente O token da ID da sessão é enviado de volta ao cliente.
  4. Cliente => Servidor de autenticação O cliente envia a ID da sessão ao servidor de autenticação, juntamente com o nome de usuário e a senha do usuário, além de algumas informações sobre o servidor (IP, chave pública TLS, etc. Veja notas de rodapé)
  5. Servidor de autenticação => Servidor de jogos O servidor de autenticação envia informações sobre o logon para o servidor de jogos (estado de sucesso, nome de usuário, estatísticas, etc.) usando a ID da sessão fornecida pelo cliente.
  6. Servidor de jogos => Cliente O servidor de jogos informa ao cliente que a autenticação foi bem-sucedida e os deixa entrar.
  7. Todas as conexões, exceto a conexão inicial do cliente com o servidor do jogo, agora estão desativadas.

Como alternativa, você pode dar aos servidores de jogos uma porta dedicada para ouvir logins. Se você escolher essa rota, o fluxo ficaria assim:

  1. Cliente => Servidor de autenticação O cliente envia o nome de usuário, a senha e o IP do servidor para o servidor de autenticação.
  2. Servidor de autenticação => Servidor de jogo + Cliente Se o login for bem-sucedido, o servidor de autenticação envia um token exclusivo para o servidor e o cliente de jogo. Envie o IP do cliente também para o servidor do jogo, para que o token não possa ser roubado.
  3. Cliente => Servidor do Jogo O cliente envia o token para o servidor do jogo, onde é verificado e excluído no servidor do jogo. O servidor do jogo deixa o cliente entrar.

Essa segunda abordagem tornaria a implementação geral um pouco mais fácil.

Notas de rodapé:

A razão pela qual especifico que algumas informações devem ser enviadas sobre o servidor do jogo para o servidor de autenticação é para fortalecer o processo contra spoofs. O servidor pode verificar as informações para garantir que está autorizando a conexão que o player espera.

Os IDs de sessão não precisariam ser criptograficamente seguros, embora isso tornasse as conexões falsas um pouco mais difíceis se fossem.

Se você optar por seguir a rota TLS, poderá configurar um servidor de assinatura que assine todos os certificados usados ​​por sua infraestrutura e adicioná-lo como uma CA confiável no software cliente / servidor. Contanto que você não solte seu certificado de assinatura, você poderá fornecer uma autenticação decente.

Para minimizar os ataques de DoS, faça o tempo limite das conexões após 20 segundos ou menos. Se durar mais do que isso, algo está errado e você não precisa esperar 3 minutos aguardando o tempo limite da conexão por conta própria.

Kaslai
fonte
Observe que é provável que seu fluxo alternativo não funcione para clientes que estão atrás de dispositivos NAT "paralelos" (classificados como "estritos" pelo programa Xbox Live da Microsoft). E também pode ter problemas se dois clientes estiverem simultaneamente atrás do mesmo dispositivo NAT (dependendo das especificidades de como o dispositivo NAT lida com essa situação); isso ocorre porque o servidor do jogo pode ver um endereço IP + porta diferente do servidor de autenticação, apenas devido ao NAT. A primeira abordagem listada deve funcionar sem problemas em todos os casos.
Trevor Powell
Apenas para esclarecer a terminologia, o Cliente (o jogador) não teria requisitos especiais para o segundo fluxo. Somente o servidor do jogo precisaria de um mapeamento de porta dedicado para esse método. Como ele já está servindo o jogo em uma porta dedicada, isso não deve ser pedir demais. Todo o processo é iniciado pelo cliente, inicializando uma conexão com o servidor de autenticação, que qualquer dispositivo na Internet pode fazer, independentemente da rigidez do seu NAT.
Kaslai
Ao reler seu comentário, acho que vejo qual era o seu problema. No caso de um usuário utilizar algum tipo de balanceador de carga que, teoricamente, pode enviar a solicitação de autenticação por um IP e a solicitação de conexão do jogo por outro IP, isso pode ser resolvido usando a solução de Ali S.
Kaslai
Sim, era isso que eu pretendia destacar (mas talvez não tenha deixado claro). No NAT "estrito" (pela definição da Microsoft), o servidor de autenticação e o servidor de jogos não verão o mesmo IP: valores de porta para um único jogador; portanto, o servidor de autenticação não pode dizer ao servidor de jogo que IP / porta deve esperar ver. Esse problema também pode ocorrer com o NAT "moderado" (dependendo da implementação específica do NAT) se houver dois players atrás do dispositivo NAT, ambos tentando enviar do mesmo número de porta.
Trevor Powell
Ah, bem, eu estava pensando que o próprio IP deveria ser contabilizado. O porto realmente não importa; É apenas para impedir que terceiros maliciosos roubem o token e o usem em outro lugar. Realmente não importa se há vários usuários atrás do mesmo NAT, pois o token identificará o usuário real, portanto, não há problemas de colisão com os quais se preocupar.
Kaslai 30/05
2

O cliente deve ter uma chave privada e uma pública .

A chave privada deve ser o identificador exclusivo que o cliente recebe do servidor de autenticação. A chave pública também deve ser enviada ao cliente.

Antes que o cliente se conecte a um servidor de jogos, ele deve enviar uma mensagem com sua chave privada e o IP do servidor de jogos ao qual deseja se conectar, ao servidor de autenticação. O servidor de autenticação deve verificar e encontrar a correspondência para a chave privada e armazenar a chave pública em seus registros.

O servidor do jogo ao qual o cliente está se conectando deve enviar uma solicitação ao servidor de autenticação após obter a chave pública do cliente. Se o servidor de autenticação puder verificar se o cliente deseja se conectar ao IP do servidor do jogo, envie-o de volta para o cliente correto. O servidor do jogo deve permitir que o cliente se conecte.

A chave privada é usada apenas para autenticação do cliente, para que o servidor do jogo não obtenha o ID de autenticação real.

Estático
fonte
11
Eu acho que entendo o processo usado. Eu escrevi um tipo de fluxograma: i.pyratron.com/MXkZXU.png Essas informações parecem corretas?
Cyral
@ Cyy Isso parece correto.
Static
1

Existem várias soluções em que posso pensar, mas aqui está a mais segura:

  1. cliente se conectar ao servidor.
  2. cliente solicita uma ponte de autenticação.
  3. servidor se conecta ao servidor de autenticação, atuando como um proxy entre o player e o auth. servidor.
  4. cliente e servidor de autenticação, forme uma sessão SSL sobre essa ponte recém-formada.
  5. usando essa conexão segura pela ponte, o cliente efetua login no servidor de autenticação.
  6. O servidor de autenticação informa ao servidor do jogo se o logon foi bem-sucedido ou não, em alguma outra conexão TCP. então desconecta sua conexão de ponte / login.
  7. Agora, o cliente e o servidor do jogo podem retomar a comunicação (apenas) pela conexão já existente (usada para autenticação).

Observe que, nesse cenário, o servidor do jogo não tem como escutar, mesmo que toda a autenticação esteja passando por ele. pelo mesmo motivo, seu ISP não pode monitorar quais pacotes você envia para o Facebook ou são provenientes do facebook.

Ali1S232
fonte
Tecnicamente, o ISP tem acesso aos dados brutos.
Static
@HaroldSeefeld Tecnicamente, não os que passam pela conexão IPSec / HTTPS.
Ali1S232 23/05
1

A maneira como eu faria isso é fazendo com que o servidor Auth envie o token para o Cliente após o login, juntamente com a lista de servidores de jogos validados (para que o cliente possa ter certeza de que o servidor do jogo é válido).

Em seguida, o cliente enviaria o token para o servidor do jogo, que o enviaria ao servidor de autenticação para confirmar que este é o cliente válido.

Conecte-se:

  1. Cliente para servidor de autenticação: nome de usuário e senha criptografada
  2. Servidor de autenticação para o cliente: token

Mais tarde, ao ingressar em um servidor de jogos:

  1. Cliente para servidor do jogo: o token mencionado anteriormente
  2. Servidor de jogo para servidor de autenticação: novamente o token
  3. Servidor de autenticação para servidor de jogos: se o token for válido, sinal OK
  4. Servidor de jogo para o cliente: permite que o cliente ingresse
zoran404
fonte
0

Que tal assinar um token JWT com um segredo que apenas o servidor central de autenticação e player conhece? Permite assinar o json, que pode ser verificado posteriormente.

Ben Aubin
fonte
Isso não permitiria que servidores executados por jogadores roubassem as credenciais de seus usuários?
Idbrii 28/05
Não, existem 2 maneiras de fazer isso: 1 - o cliente solicita um jwt com o servidor, permitindo que o servidor roube a identidade, mas apenas no servidor (não é grande coisa) 2 - O JWT funciona apenas uma vez
Ben Aubin