实战篇:安全体系综合实现
概述
本实战把五块安全能力拼成一套完整安全方案:协议加密(传输安全)、服务端权威(逻辑安全)、频次检测(反脚本)、防沉迷(合规)、日志审计(追溯)。以"签到领取 + 对战 + 充值"三个典型链路演示安全体系如何贯穿始终。
一、安全体系总览
1.1 五层防线
安全五层防线:
传输层:协议加密 + HMAC + 防重放(协议安全篇)
逻辑层:服务端权威 + 数值校验(服务端权威篇)
行为层:频次检测 + 异常模式(反脚本篇)
合规层:防沉迷 + 隐私脱敏(合规章节)
追溯层:全量日志 + TraceId + 告警(日志审计篇)
设计原则:
纵深防御(任何单层被破还有下层兜底)
服务端最终裁决(客户端永远不可信)
安全策略配置化(不写死在代码里)// 安全配置(统一管理)
security {
// 传输
encryptOps: [LOGIN, RECHARGE, TRADE] // 加密消息类型
replayWindowSec: 60 // 重放窗口
// 行为
freqLimit: { op: 100, window: 60s } // 频次上限
// 合规
minor: { dailyMin: 60min, curfew: [22, 8] }
}1.2 处理链路(网关 → 逻辑 → 日志)
请求处理管线:
网关:解密 → 验签 → 防重放 → TraceId 注入
逻辑:服务端权威校验 → 频次检测 → 业务执行 → 防沉迷检查
审计:操作日志 + 结果 + 异常告警二、链路一:签到领取(完整安全示例)
2.1 完整代码流程
// 网关层:解密 + 验签 + 防重放
byte[] body = decrypt(msg); // 1 解密
if (!verifyHmac(msg)) return reject; // 2 验签
if (!checkReplay(msg)) return reject; // 3 防重放
// 网关注入 TraceId 后转发逻辑服// 逻辑层:权威 + 频次 + 防沉迷 + 幂等
@Authoritative("SIGN_IN") // 声明该操作为权威操作
public SignResult signIn(long playerId) {
// 1 频次检测(防脚本狂点)
if (!freqLimiter.tryAcquire(playerId, "SIGN_IN")) {
log.warn("sign freq over", playerId);
throw new TooFastException();
}
// 2 防沉迷(未成年人签到不限制,但登录受限)
// 3 幂等(当日已签则直接返回已签到)
if (signDao.exist(playerId, today)) {
return SignResult.ALREADY; // 幂等,不重复发奖
}
// 4 原子置位 + 发奖(统一入口)
Long result = redis.call("SIGN_SET_BIT", playerId, today);
if (result == 1) { // 首次置位成功
currencyService.add(playerId, coin, 100, bizId);
return SignResult.SUCCESS;
}
return SignResult.ALREADY;
}// 统一货币入口(幂等)
public void add(long playerId, long amount, String bizId) {
// bizId 防重复发放
if (opLog.exist(bizId)) return; // 已处理
playerDao.incrCoin(playerId, amount); // 条件更新
opLog.record(bizId, playerId, amount); // 流水 + 日志
}2.2 测试要点
测试清单:
重复请求签到 → 只发一次奖(幂等)
请求频率超限 → 拒绝(频次)
篡改签到日期 → 服务器日期为准(权威)
重放旧包 → 拒绝(防重放)
未成年人时段登录 → 拒绝(防沉迷)三、链路二:对战结算(权威 + 防脚本)
3.1 对战流程
对战安全流程:
客户端上报操作(回合动作,不含结果)
服务器计算每回合结果(权威公式)
结算时校验:对局合法性 + 时长 + 行为
结果广播 + 入日志// 对战操作处理(防脚本示例)
public void onAction(long roomId, Action action) {
Player p = getPlayer(action.playerId);
// 操作频率(人类 APM 上限内)
if (p.actionPerSec() > 8) {
risk.mark(p, "APM 异常"); // 标记观察
return; // 不处理该操作
}
// 操作间隔规律性检测
if (isTooRegular(p.actionIntervals())) {
risk.mark(p, "节奏异常"); // 疑似脚本
}
// 权威:服务器计算动作结果并广播
RoomResult r = battleEngine.apply(roomId, action);
broadcast(roomId, r);
}// 结算(服务端权威 + 防沉迷时长联动)
public void settle(long roomId, SettleResult result) {
// 服务器计算结果,客户端只展示
saveBattle(result);
currencyService.add(result.winner, coin, result.reward, bizId);
// 未成年人累计游戏时长
if (player.isMinor()) {
playTimeService.add(playerId, battleDuration);
if (playTimeService.overLimit(playerId)) {
kick(playerId, "未成年人时长上限");
}
}
logAudit.op(playerId, "battle_settle", result);
}3.2 风险处置
风险处置联动:
频次超限 → 本次不处理 + 累计风险分
风险分达阈值 → 验证码 → 限收益 → 封禁
封禁事件 → 日志 + 风控表更新 + 通知四、链路三:充值(合规 + 审计)
4.1 充值校验
充值流程(合规重点):
客户端发起充值 → 网关安全校验
防沉迷:未成年人充值限额校验
支付渠道回调 → 校验签名 → 幂等发货
全程日志 + 流水(可审计)// 充值回调处理
public void onPayCallback(PayNotify notify) {
if (!verifyChannelSign(notify)) return; // 渠道签名
Player p = getPlayer(notify.playerId);
if (p.isMinor() && !rechargeAllowed(p, notify.amount)) {
refund(notify.orderId); // 未成年人超限退款
return;
}
// 幂等发货(订单号唯一)
if (orderDao.markPaid(notify.orderId)) {
currencyService.add(p.id, diamond, notify.amount,
"pay:" + notify.orderId);
logAudit.recharge(p.id, notify); // 审计日志
}
}4.2 审计查询
审计示例(Kibana 查询):
某玩家全部资金变动:playerId=88001 AND op:coin_change
可疑订单追溯:orderId = "xxx"(全链路日志)
异常告警:5min 内验签失败 > 阈值五、安全体系验收清单
验收清单(上线前全过):
[ ] 加密消息类型配置生效(登录/充值/交易)
[ ] HMAC 验签失败有日志 + 告警
[ ] 防重放窗口与 Redis 去重生效
[ ] 核心玩法结果全部服务器计算
[ ] 敏感操作二次校验 + 幂等
[ ] 频次限制 + 节奏检测 + 风险分
[ ] 未成年人实名/时长/充值限制生效
[ ] 敏感字段日志脱敏
[ ] 关键操作全量日志 + TraceId
[ ] 告警规则接入钉钉/企微常用验证手段:
抓包工具(Wireshark)看协议加密效果
篡改请求(自研客户端改包)验证服务端校验
脚本模拟高频操作验证频次拦截
未成年人账号验证时长/充值限制
全链路检索验证 TraceId 串联六、实现要点
安全体系核心:
五层防线(传输/逻辑/行为/合规/追溯)
三条链路贯穿(签到/对战/充值)
安全策略配置化 + 服务端最终裁决
日志留痕 + 告警闭环
常见坑:
单点安全(只做加密其他裸奔)
安全校验阻塞主流程(要异步化)
规则写死(政策/策略调整困难)
无复盘(告警了不处理不优化)
与其他系统衔接:
配置中心 → 安全策略热更新
监控 → 告警规则与面板
运营后台 → 封禁/申诉管理
全链路追踪 → 运维章节