在线游戏DoS攻防实战:从IP白名单到代理服务器架构

开源在线游戏DDraceNetwork长期遭受DoS攻击,本文详细介绍了应对策略,包括HTTPS白名单机制、iptables规则配置、专用服务器部署、代理服务器架构设计,以及IPv6和Steam中继等防护方案的技术实现细节。

在线游戏遭受DoS攻击的最新进展

在8个月前的上一篇文章中,我描述了我们的开源在线游戏DDraceNetwork如何在大约8年内(基本上自成立以来)一直遭受DoS攻击。最近攻击变得更加严重,迫使我们研究更多应对方法。由于许多玩家最近提出了建议,我写下这篇博客文章来总结我们正在尝试的方法,并再次寻求帮助。

攻击特征分析

这些流量图来自我们运行的两个服务器,请注意对数x轴。每个峰值代表一次传入的DoS攻击,正如您所看到的,其中一些攻击持续了近一天。

最近的攻击在传入带宽方面相对较弱,使用伪造的IP地址模仿我们基于UDP的连接过程。

最初CPU会过载,因为服务器突然需要尝试处理每秒数十万次的连接尝试。由于我们的游戏服务器主要运行在廉价的VPS上,并且每个游戏服务器都是单线程运行的,因此很容易以这种方式使系统过载。

HTTPS白名单防护机制

为了防止欺骗,我们收集所有玩家的IP地址并将这些地址加入白名单。由于我们也开发游戏客户端,我们可以修改客户端通过HTTPS连接到服务器进行白名单验证。游戏服务器上用于此白名单的iptables规则和ipset设置如下所示:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
ipset create official iphash
ipset create whitelist-ip iphash
iptables -N serverinfo
iptables -A serverinfo -m hashlimit --hashlimit-above 40/s --hashlimit-mode dstport --hashlimit-name si_dstport -j DROP
iptables -N game
iptables -A game -m set --match-set official src -j ACCEPT
iptables -A game -m set --match-set whitelist-ip src -m u32 --u32 "38=0x67696533" -j serverinfo
iptables -A game -m set --match-set whitelist-ip src -m u32 --u32 "38=0x66737464" -j serverinfo
iptables -A game -m set --match-set whitelist-ip src -j ACCEPT
# 在没有攻击时仍允许非白名单玩家
iptables -A game -m limit --limit 10000 -j ACCEPT
iptables -A game -j DROP
iptables -A INPUT -p udp -m udp --dport 8000:9000 -j game

为了持续更新白名单,我们运行一个简单的脚本:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#!/bin/sh
rm -f whitelist whitelist.old
touch whitelist.old
while true; do
  curl -o whitelist $WHITELIST_URL
  LC_ALL=C comm -23 whitelist whitelist.old | while read line; do
    ipset add whitelist-ip $line
  done
  mv whitelist whitelist.old
  sleep 20
done

启动DDNet客户端约20秒后,玩家现在被加入白名单,可以加入遭受欺骗性DoS攻击的服务器。我们在经常受攻击的服务器上采用了这种方法。

技术挑战与限制

几天后,ipset就会耗尽空间。由于我们每天有约25,000名独立玩家,ipset默认的最大元素大小65536相当紧张。为了解决这个问题,我们将不得不增加限制或自动删除较旧的条目。

为了使这项工作可靠,我们必须禁用HTTPS访问的IPv6,因为我们的游戏服务器目前仅支持IPv4,收集IPv6地址没有帮助。

一个不幸的发现是,一些ISP不再提供固定的IPv4地址,而是根据协议和端口通过不同的IPv4地址隧道传输其本机IPv6流量。因此我们在基于HTTPS的白名单中获得一个IP地址,但通过UDP连接到游戏服务器时获得另一个IP地址。至少有一家以色列ISP正在这样做。

专用服务器方案

对于某些服务器,这种白名单机制还不够,因为托管商的DoS保护机制会启动并开始积极阻止UDP流量。这包括合法流量,并导致所有玩家在游戏服务器上超时。我尝试与几家托管商讨论这个问题,但这是设计使然,因为他们不支持我们的游戏协议,并希望保护自己的基础设施以及其他客户。至少他们目前没有将我们踢出,这在过去曾发生过,当时针对我们的多次DoS攻击影响了他们的其他客户。

因此,对于某些位置,我们已升级到专用服务器,托管商不太关心我们耗尽传入网络连接和CPU数小时。不幸的是,很难找到提供超过1 Gbit/s网络带宽且仍符合我们每月100欧元预算的托管商。

攻击者当然注意到这些服务器不容易被击垮,因此他们转而采用不同类型的攻击,耗尽我们微不足道的2 Gbit/s网络。

小型托管公司的尝试

欧洲的一些小型托管公司提出通过提供带有自定义DoS保护的免费服务器来帮助我们。我们接受了两个这样的提议,但都没有取得太大成功。

对于第一个,我们从未设法让合法流量通过他们的防火墙。

对于第二个,在没有攻击时一切似乎都正常,但在DoS攻击期间,一些玩家数据包总是被错误标记。此外,网络堆栈出现问题,导致我们基于MariaDB的SQL连接超时。不幸的是,我们在代码中没有正确处理此错误,最终丢失了合法玩家的排名。

最终我们没有继续使用这两家托管商,但花了几个小时尝试与他们一起设置防火墙。我对每个提供自定义DoS保护的付费托管商都有类似的经历。

专业DoS保护公司

当然也有大公司为基于UDP的应用程序提供自定义DoS保护。其中一家公司提出免费帮助我们解决我们的问题,自上一篇文章以来我一直与他们保持联系。不幸的是,一切进展非常缓慢,我几周来推动事情进展的许多请求都没有得到答复,所以我想我们无法每月支付数千欧元的事实毕竟很重要。到目前为止,这里还没有可用的自定义DoS保护,但我会每隔几周继续联系他们。

代理服务器架构设计

未来,我们考虑在游戏服务器和玩家之间设置代理服务器,而不是将我们的真实游戏服务器直接暴露给玩家。这将允许我们为玩家子集运行多个代理,并尝试隔离攻击者可能产生的影响。

这也可能允许我们通过Steam数据报中继(SDR)代理Steam玩家的流量,尽管实现这一点需要更多工作。上一篇文章后,Valve的某人联系我们,一旦代理服务器实现准备好,我们可能会跟进此事。Valve在这里提供帮助真的很酷,即使对于我们这样的免费游戏也是如此。

我们不能完全通过Steam的服务器切换到SDR,因为我们希望DDNet作为开源游戏保持可玩性。作为解决方案,我们可以为开源玩家提供常规的开源代理,为Steam玩家提供单独的基于SDR的代理。

IPv6服务器方案

一个不太有把握的想法是使用仅IPv6的服务器。我们尚未尝试过这一点,也许我们的攻击者在IPv6上的IP欺骗能力较低。这也可以与代理服务器很好地结合,提供一个额外的仅IPv6代理服务器。

为每个位置运行所有这些代理服务器肯定会增加成本,但这可能是我们目前最好的前进道路。每个服务器位置的设置将如下所示:

1
2
3
4
5
6
7
8
9
digraph D {
  node [shape="box"];
  "OS Player 1" -> "IPv4 Proxy" -> "Game Server";
  "OS Player 2" -> "IPv4 Proxy";
  "OS Player 3" -> "IPv6 Proxy" -> "Game Server";
  "OS Player 4" -> "IPv6 Proxy";
  "Steam Player 1" -> "SDR Proxy" -> "Game Server";
  "Steam Player 2" -> "SDR Proxy";
}

结论

如果您有任何建议,或以前处理过类似问题,我们有兴趣听取您的意见。您可以通过dennis@felsing.org联系我,也可以在DDNet Discord上作为deen#5910联系我,或在IRC上联系(Quakenet上#ddnet中的deen)。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计