第2章:网络层防护:DDoS攻击原理与防御、TCP/UDP洪水防护、IP黑白名单机制

大家好,我是你们的老朋友。今天咱们聊聊网络层防护,这是游戏服务器安全的第一道防线。说实话,我见过太多游戏刚上线就被打趴下的案例,原因就是网络层没守住。

DDoS攻击,说白了就是让服务器「忙死」。攻击者用大量垃圾流量塞满你的带宽,或者耗尽你的连接资源。正常玩家进不来,游戏直接瘫痪。我当年负责的一款MMO,开服当天就被打了200G的流量,那叫一个惨烈。

2.1 DDoS攻击原理

DDoS攻击分几种常见类型,咱们一个个说。

2.1.1 带宽耗尽型攻击

这种攻击最粗暴。攻击者用大量肉鸡(被控制的机器)同时向你的服务器发送大流量数据包。你的带宽是有限的,比如100Mbps,人家打过来1Gbps,那你的服务器就彻底堵死了。

我记得有一次,一个客户说他们的游戏突然卡得动不了。我一看流量监控,好家伙,UDP流量直接飙到了800Mbps。正常游戏哪有这么多UDP包?明显是攻击。

2.1.2 连接耗尽型攻击

这种更阴险。它不占你带宽,而是占你的连接数。比如TCP SYN Flood,攻击者发送大量伪造的SYN包,服务器会为每个SYN分配资源等待握手完成。但攻击者根本不完成握手,服务器资源就被耗尽了。

你想想看,一台服务器能同时处理的连接数是有限的。比如Linux默认的backlog是128,攻击者一秒发几万个SYN,你的服务器就再也无法接受新连接了。

2.1.3 应用层攻击

这种攻击针对游戏协议本身。比如发送大量合法的游戏请求,让服务器忙于处理这些请求而无法响应正常玩家。我遇到过有人写脚本模拟玩家登录,一秒发几千次登录请求,直接把认证服务器打崩了。

2.2 TCP/UDP洪水防护

好了,知道攻击原理了,咱们说说怎么防。我个人习惯把防护分成三层:网络层、传输层、应用层。今天重点说传输层。

2.2.1 TCP SYN Flood防护

SYN Flood是最常见的攻击方式。防御手段主要有以下几种:

防护手段 原理 优缺点
SYN Cookie 不分配资源,用Cookie验证 效果好,但增加CPU开销
缩短超时时间 减少半连接存活时间 简单有效,但可能误杀
反向探测 对可疑IP发送探测包 准确率高,但延迟大

我建议在Linux内核层面开启SYN Cookie:

# 开启SYN Cookie
echo 1 > /proc/sys/net/ipv4/tcp_syncookies

# 调整半连接队列大小
echo 1024 > /proc/sys/net/ipv4/tcp_max_syn_backlog

# 减少SYN-ACK重试次数
echo 3 > /proc/sys/net/ipv4/tcp_synack_retries

嗯,这里要注意:SYN Cookie虽然好用,但在高并发场景下会增加CPU开销。我建议只在检测到攻击时动态开启,平时关掉。

2.2.2 UDP Flood防护

UDP Flood更难防,因为UDP本身是无连接的。攻击者随便伪造源IP,发一堆UDP包过来。你的服务器得一个个处理,处理不过来就挂了。

我在项目中遇到过最狠的一次,攻击者用放大攻击。他伪造源IP为你的服务器IP,向DNS服务器发送查询请求,DNS服务器返回的数据比请求大几十倍,全部打到你服务器上。这叫反射放大攻击。

防御UDP Flood,我常用的手段:

  • 限速:对单个IP的UDP流量做限速,超过阈值直接丢包
  • 协议验证:只处理符合游戏协议的UDP包,其他全部丢弃
  • 源IP验证:对可疑IP发送探测包,验证其真实性

代码层面,可以在游戏服务器入口做过滤:

// 伪代码:UDP包过滤
bool FilterUDPPacket(udp_packet_t* pkt) {
    // 1. 检查包大小
    if (pkt->size > MAX_UDP_SIZE || pkt->size < MIN_UDP_SIZE) {
        return false;  // 丢弃
    }
    
    // 2. 检查协议头
    if (!IsValidGameProtocol(pkt->data)) {
        return false;  // 丢弃
    }
    
    // 3. 检查源IP频率
    if (GetIPFrequency(pkt->src_ip) > MAX_FREQ) {
        return false;  // 丢弃
    }
    
    return true;  // 放行
}
警告:UDP Flood防御一定要在网卡层面做第一道过滤,不要等到应用层才处理。否则CPU早就被耗光了。

2.3 IP黑白名单机制

IP黑白名单是最基础也是最有效的防护手段。说白了就是:白名单里的IP随便进,黑名单里的IP直接拦。

2.3.1 白名单机制

白名单适用于内部系统、管理后台、测试环境。比如你的运维管理平台,只允许公司VPN的IP段访问。其他IP一律拒绝。

我曾经犯过一个错误:把白名单写死在代码里。结果公司换IP段了,所有运维人员都连不上服务器。后来我改成从配置文件读取,再后来改成从配置中心动态获取。

// 白名单配置示例
{
    "whitelist": [
        "10.0.0.0/8",      // 内网段
        "192.168.1.0/24",  // 办公网段
        "114.114.114.114"  // 特定IP
    ],
    "mode": "strict"  // strict: 只允许白名单; loose: 白名单优先
}

2.3.2 黑名单机制

黑名单用于封禁恶意IP。比如检测到某个IP在短时间内发送了大量请求,就把它加入黑名单。

我建议黑名单分两级:

  • 临时黑名单:自动触发,封禁一段时间(比如30分钟)后自动解封
  • 永久黑名单:人工确认后加入,永久封禁

实现时要注意性能问题。黑名单如果太大,每次查表都会很慢。我一般用布隆过滤器(Bloom Filter)来做快速判断:

// 布隆过滤器示例
class IPBloomFilter {
    bitset<1024*1024> bits;  // 1M bits
    hash_func_t hash_funcs[3];
    
public:
    void Add(const string& ip) {
        for (auto& h : hash_funcs) {
            bits.set(h(ip) % bits.size());
        }
    }
    
    bool MightContain(const string& ip) {
        for (auto& h : hash_funcs) {
            if (!bits.test(h(ip) % bits.size())) {
                return false;  // 一定不在
            }
        }
        return true;  // 可能在
    }
};
小提示:布隆过滤器有误判率,但可以控制。我一般把误判率控制在0.1%以下。对于黑名单来说,偶尔误判一个正常玩家,总比放进来一个攻击者强。

2.3.3 动态黑白名单

静态黑白名单不够灵活。我建议实现动态黑白名单,根据实时流量自动调整。

比如,我写过一个简单的检测逻辑:

  1. 统计每个IP在1秒内的请求次数
  2. 如果超过阈值(比如100次/秒),加入临时黑名单
  3. 如果该IP在1小时内被加入黑名单超过3次,升级为永久黑名单
  4. 永久黑名单需要人工审核才能移除

这样做的好处是:攻击者刚动手就被封了,正常玩家偶尔手抖一下也不会被误伤。

2.4 实战经验总结

说了这么多,最后分享几点我的实战经验:

  • 不要只依赖一种防护手段:DDoS攻击手段多样,你得组合使用多种技术
  • 监控要到位:没有监控,你都不知道自己被打了。我习惯用Grafana搭实时流量看板
  • 做好容量规划:服务器带宽和连接数要有余量,别刚好卡在极限
  • 和云服务商配合:大流量攻击靠自己是扛不住的,得用云清洗服务

我曾经接手过一个项目,服务器被打了三天,运维团队居然没发现。为什么?因为他们没看流量监控。后来我加了告警,流量一异常就发短信、打电话。从那以后,再也没出现过被打不知道的情况。

好了,网络层防护就聊到这儿。下一章咱们讲传输层安全,聊聊如何防止中间人攻击和会话劫持。到时候见。