我有客户端连接到我的 WebSockets 游戏服务器来玩在线浏览器游戏。游戏服务器在玩家开始游戏时创建和销毁,因此每个服务器可以拥有不同的 IP 地址,而我无法控制。
我需要 WebSockets 是安全的 (WSS),所以我有一个带有 SSL 证书的 nginx 代理。客户端接收游戏服务器的 IP,但它不是直接连接(不安全),而是通过我的 nginx 服务器,以游戏服务器 IP 作为查询参数。
问题在于:现在任何人都可以使用我的 nginx 服务器代理到他们选择的任何 IP。我需要一种方法来确保 nginx 只代理到我的游戏服务器。
由于它是外部主机,我无法控制游戏服务器 IP,但我拥有游戏服务器代码。我的 nginx 代理由我托管,但游戏服务器由提供商托管。
我的计划是在游戏服务器和 nginx 上有一个共享密钥,并用它来加密所有流量,但我很难找到如何做到这一点。
以下是我目前所做的工作(基于关于这个要点):
我创建了自己的自签名 CA 证书:
openssl genrsa -des3 -out rootCA.key 4096
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.crt
我为游戏服务器创建了一个证书:
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
我对 nginx 服务器做了同样的事情(这需要吗?注意:不需要):
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
我的 nginx 配置如下:
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;
}
}
}
gameserver.key
我的游戏服务器是使用和 的WebSockets 服务器gameserver.csr
。
但是当我尝试时,nginx 错误日志显示:
upstream SSL certificate verify error: (18:self signed certificate) while SSL handshaking to upstream
我不确定这是否可行,我哪里做错了?唯一文章我发现提到这个错误表明游戏服务器证书不受信任,但我不知道原因。
我也不确定在创建证书时应该赋予什么值Common Name
(因为每个游戏服务器都有自己的 IP),以及这是否是个问题。
答案1
我建议为后端设置一个内部证书颁发机构,并要求您的后端可以通过该证书颁发机构进行验证,您可以引导这些证书以包含其 IP 或使用通用主机名覆盖 IP(我认为这就足够了)。
- 创建一个仅限内部的 CA,将其命名为“游戏服务器后端”
- 创建一个仅限内部的服务器证书,将其命名为“gameserver.auth.backend”
- 在你的 websocket 节点程序上使用 gameserver.auth.backend 作为证书
- 告诉 nginx 对此进行验证,用你指定的名称(而不是 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;
}
}
}