i007.cc

i007.cc

优先队列-降维打击

05.价值资料

如何设计防作弊系统

防作弊是游戏后端最有深度的话题之一,涉及服务器设计、统计检测、对抗博弈等多个维度。对 FC Mobile 这类有排名和经济系统的游戏来说,作弊问题直接影响玩家留存,面试很可能深入考察这块。


先把作弊类型分清楚

不同类型的作弊,防御思路完全不同:

客户端篡改:修改内存数值(金币、体力)、加速器(修改游戏时钟)、外挂注入(自动操作)、Root/越狱后绕过保护。

网络层攻击:抓包篡改请求、重放攻击(把一次购买请求发多次)、中间人修改响应数据。

逻辑层滥用:利用游戏规则漏洞刷资源、账号共享代打、两个账号互刷段位(Boosting)、故意输球操控排名(Tank)。

社会工程:盗号、黑产账号批量注册薅资源。

这几类的防御重心完全不同,先分清楚才能设计有针对性的系统。


第一道防线:服务器权威设计

这是最根本的,也是选择状态同步而非帧同步的重要原因之一。

原则:客户端永远不可信,所有关键逻辑在服务器执行。

cpp
// 错误做法:信任客户端发来的结果
void handle_match_result(Request& req) {
    int score = req.get_int("score");     // 客户端说我进了 50 球
    give_reward(player, score);           // 直接奖励——可以被任意篡改
}

// 正确做法:服务器自己算
void handle_match_result(Request& req) {
    auto& session = get_session(req.session_id);
    int score = session.server_computed_score;   // 服务器全程记录的分数
    give_reward(player, score);
}

 

具体落地:关键数值(金币、积分、体力)只在服务器存储和计算,客户端只做展示。玩家进球这件事,服务器要自己根据球的物理轨迹和守门员位置来判定,而不是听客户端汇报。


第二道防线:网络包完整性

防重放攻击

每个请求带上时间戳和随机 nonce,服务器验证:

cpp
struct Request {
    int64_t  timestamp;   // 请求时间
    string   nonce;       // 随机串,服务器记录已用过的
    string   payload;
    string   hmac;        // HMAC-SHA256(timestamp + nonce + payload, secret_key)
};

bool validate_request(const Request& req) {
    // 1. 时间窗口校验:超过 30s 的请求直接拒绝
    if (abs(now() - req.timestamp) > 30s) return false;

    // 2. nonce 查重:防止同一个包发两次
    if (nonce_cache.exists(req.nonce)) return false;
    nonce_cache.insert(req.nonce, TTL_60s);

    // 3. HMAC 校验:防止包体被篡改
    return verify_hmac(req, server_secret_key);
}

 

SSL Pinning

移动端把服务器证书的公钥硬编码进客户端,防止抓包工具做中间人解密。被 Root 的设备可以绕过,但提高了攻击门槛。


第三道防线:输入合法性校验

这一层针对”操作速度超出人类极限”这类作弊:

cpp
void validate_player_action(Player& player, Action& action) {
    auto now = current_tick();

    // 射门频率校验:人类不可能每秒射门 10 次
    if (now - player.last_shoot_tick < MIN_SHOOT_INTERVAL) {
        flag_suspicious(player, "shoot_too_fast");
        return;
    }

    // 移动距离校验:这帧的位移超出物理可能
    float max_possible_dist = player.speed * FIXED_DT * 1.1f;  // 10% 容差
    if (distance(action.new_pos, player.pos) > max_possible_dist) {
        flag_suspicious(player, "speed_hack");
        return;
    }

    // 时序校验:动作发生在未来(客户端时钟被调快)
    if (action.client_timestamp > now + MAX_CLOCK_DRIFT) {
        flag_suspicious(player, "time_manipulation");
        return;
    }
}

 

注意这里用的是”flag 可疑”而不是”立刻封禁”——误判的代价太高,单次异常不足以定罪。


第四道防线:统计异常检测

这是对抗”规则合法但行为异常”的手段,是真正考验系统设计能力的地方。

实时风控打分引擎

把玩家的各种行为指标实时聚合,输出一个风险分:

胜率异常维度:
  近 100 场胜率 > 95%?(正常玩家顶尖也难超 75%)
  连胜场次超过 50 场无败绩?

效率异常维度:
  场均进球数超过历史 3σ 之外?
  操作 APM(每分钟动作数)持续超出人类上限?

时间维度:
  连续游戏 20 小时无中断?(脚本特征)
  每局耗时极度稳定(正负 5 秒以内)?(机器人特征)

社交图谱维度:
  两账号频繁互相配对并且总是一赢一输?(Boosting)
  新账号资源快速转移给某账号?(洗号)

 

异步分析 Pipeline

不能把所有检测都放在请求链路上,重型分析要异步:

玩家操作 → 写 Kafka → 实时检测(轻量规则,<5ms)
                    → 流式聚合(Flink,计算滑动窗口统计)
                    → 离线分析(每日跑 ML 模型,输出可疑账号列表)
                    → 人工审核队列(高风险账号)

 

机器学习模型

大厂的防作弊最终都会引入 ML,把”哪些特征组合预示作弊”的问题交给模型去学。训练数据来自人工标注的确认作弊案例。特征工程是关键:行为序列的时间模式、玩家特征向量在高维空间中的离群程度等。


第五道防线:客户端环境检测

移动端特有,对抗 Root/越狱和模拟器:

cpp
// 伪代码:SDK 层做的检测
bool is_environment_trusted() {
    // Root / 越狱检测
    if (file_exists("/data/local/tmp/frida-server")) return false;
    if (can_write("/system/app"))                    return false;

    // 模拟器检测(PC 挂模拟器可能有外挂优势)
    if (build_fingerprint.contains("generic"))       return false;
    if (sensor_data.is_perfect_zero())               return false; // 真机陀螺仪不会完全为零

    // 内存完整性检测(检测关键函数是否被 hook)
    if (function_checksum(critical_func) != EXPECTED) return false;

    return true;
}

 

这层检测的结果不要在客户端直接告诉玩家(作弊者会针对性绕过),而是上报给服务器,作为风险评分的一个维度。


封禁策略:不要让作弊者知道他被检测到了

这是很多系统设计忽视的博弈思维。

延迟封禁:检测到作弊后不立刻封号,而是积累一到两周的证据,在某个批次统一处理。作弊者不知道哪个行为触发了检测,无法针对性调整。

影子封禁(Shadow Ban):账号表面上正常运行,但只会和其他作弊账号匹配,或者某些奖励被悄悄置为 0。作弊者以为自己没被发现,继续暴露更多作弊行为,同时对正常玩家没有影响。

分级处理

风险分 60-80:静默观察,加大采样率
风险分 80-95:限制部分功能(禁止排位、禁止交易)
风险分 95+  :进人工审核队列
人工确认     :永久封禁,关联账号一并处理

 

申诉机制:误判永远存在,尤其是 ML 模型。必须有人工申诉通道,防止误封正常玩家造成公关危机。


经济系统的专项保护

FC Mobile 有抽卡、金币、交易等经济系统,这是黑产的重点攻击目标:

幂等性设计:每个购买/奖励请求带唯一 order_id,服务器保证同一 order_id 只发放一次奖励,从根本上防止重放攻击。

异步到账:高价值奖励不立刻到账,进入一个 pending 状态,几分钟内通过风控校验后再实际发放,留出撤销窗口。

资源流向追踪:记录每一笔金币的来源和去向,方便溯源。黑产洗资源的链路在日志里一定会留下痕迹。


面试里怎么用这些知识

EA 问这道题,考察的不是你背了多少技术词汇,而是你有没有系统性的防御思维:客户端不可信所以要服务器权威;单点规则容易被绕过所以要多层防御;实时封禁会暴露检测逻辑所以要延迟处理;误判代价大所以要有人工审核兜底。

如果你在之前项目里做过相关工作,哪怕只是某一个层面(比如设计过幂等订单系统,或者做过异常行为监控),都可以展开说,结合具体的技术决策会更有说服力。

发表回复