
Tenho clientes se conectando ao meu servidor de jogos WebSockets para um jogo de navegador online. Os servidores de jogos são criados e destruídos quando os jogadores iniciam os jogos e, portanto, cada servidor pode ter um endereço IP diferente que não posso controlar.
Preciso que os WebSockets sejam seguros (WSS), por isso tenho um proxy nginx com um certificado SSL. O cliente recebe o IP do servidor do jogo, mas em vez de se conectar diretamente (inseguro) ele passa pelo meu servidor nginx com o IP do servidor do jogo como parâmetro de consulta.
Aqui está o problema: agora qualquer pessoa pode usar meu servidor nginx para fazer proxy para qualquer IP que escolher. O que eu preciso é de uma maneira de garantir que o nginx esteja apenas fazendo proxy parameuservidores de jogos.
Não tenho controle dos IPs do servidor do jogo, pois é um host externo, mas possuo o código do servidor do jogo. Meu proxy nginx é hospedado por mim, mas os servidores do jogo são hospedados por um provedor.
Meu plano era ter uma chave secreta compartilhada no servidor do jogo e no nginx e criptografar todo o tráfego com ela, mas estou lutando para descobrir como isso poderia ser feito.
Aqui está o que fiz até agora (com basenesta essência):
Criei meu próprio certificado CA autoassinado:
openssl genrsa -des3 -out rootCA.key 4096
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.crt
Criei um certificado para o servidor do jogo:
openssl genrsa -out gameserver.key 2048
openssl req -new -key gameserver.key -out gameserver.csr
openssl x509 -req -in gameserver.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out gameserver.crt -days 500 -sha256
Fiz o mesmo para o servidor nginx ( isso é necessário? nota: não é necessário):
openssl genrsa -out nginx.key 2048
openssl req -new -key nginx.key -out nginx.csr
openssl x509 -req -in nginx.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out nginx.crt -days 500 -sha256
Minha configuração do nginx é algo assim:
http {
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 443 ssl;
# these are for game client
ssl_certificate /etc/letsencrypt/live/mywebsite.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mywebsite.com/privkey.pem;
location / {
if ( $arg_host != "" ) {
proxy_pass https://$arg_host:$arg_port;
}
proxy_ssl_certificate nginx.crt;
proxy_ssl_certificate_key nginx.key;
proxy_ssl_trusted_certificate rootCA.crt;
proxy_ssl_verify on;
proxy_ssl_verify_depth 2;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_read_timeout 86400;
}
}
}
Meu servidor de jogo é um servidor WebSockets usando gameserver.key
e gameserver.csr
.
No entanto, quando tento, os logs de erros do nginx mostram:
upstream SSL certificate verify error: (18:self signed certificate) while SSL handshaking to upstream
Não tenho certeza se isso pode funcionar e onde errei? Oúnico artigoDescobri que mencionar esse erro sugere que o certificado do servidor do jogo não é confiável, mas não consigo entender o porquê.
Também não tenho certeza de qual valor devo colocar ao Common Name
criar certificados (já que cada servidor de jogo está em seu próprio IP) e se isso é um problema ou não.
Responder1
O que eu sugeriria é configurar uma autoridade de certificação interna para os back-ends e exigir que seus back-ends possam ser verificados com essa autoridade de certificação. Você pode inicializar esses certificados para incluir seu IP ou substituir o IP por um nome de host comum (o que eu acho que seria satisfazer).
- crie uma CA apenas interna, chame-a de "Gameserver Backend"
- crie um certificado de servidor apenas interno, chame-o de "gameserver.auth.backend"
- use gameserver.auth.backend como seu certificado em seu programa de nó websocket
- diga ao nginx para validar isso, substituindo o nome comum pelo que você especificou (em vez do IP)
http {
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 443 ssl;
# these are for game client
ssl_certificate /etc/letsencrypt/live/mywebsite.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mywebsite.com/privkey.pem;
location / {
if ( $arg_host != "" ) {
proxy_pass https://$arg_host:$arg_port;
}
proxy_ssl_verify on;
proxy_ssl_verify_depth 2;
proxy_ssl_name gameserver.auth.backend;
proxy_ssl_server_name on;
proxy_ssl_trusted_certificate GameserverCA.crt;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_read_timeout 86400;
}
}
}