TDD-07 反作弊与安全设计
文档类型:技术设计文档(Technical Design Document)
版本:1.0
日期:2026-07-02
关联文档:TDD-04《数据库表结构设计》、TDD-05《API接口设计》、GDD-02《底层核心机制》、GDD-03《战斗系统设计》、GDD-06《经济系统设计》、GDD-13《佣兵大厅与悬赏系统》、GDD-14《稀有宝物流转与拍卖系统》
1. 文档信息
| 项目 |
说明 |
| 目标 |
为《洪荒大陆》挂机手游定义反作弊与安全设计规范,覆盖服务端权威模型、异常行为检测、经济安全、举报惩罚、接口安全与数据安全六大领域。 |
| 读者 |
服务端开发、客户端开发、安全工程师、运维、QA |
| 技术栈 |
Nakama 3.x + Go 插件 + PostgreSQL 16 + Valkey + Nacos 2.x + Cocos Creator 3.x |
| 核心约束 |
无任务系统、无赛季重置、概率/机遇驱动、文字战报、ATB 行动条、功法加持、能量体系(非体力) |
2. 服务端权威模型
2.1 设计原则
本项目采用 服务端权威(Server-Authoritative) 架构:客户端仅负责展示与发起请求,所有涉及游戏状态变更的逻辑在服务端计算并持久化。客户端提交的数据仅作为"意图声明",不作为事实来源。
客户端 服务端 数据库/缓存
│ │ │
│── 请求(意图) ────────►│ │
│ │── 读取状态 ──────────►│
│ │◄─ 返回当前状态 ───────│
│ │ │
│ │── 校验 + 计算 ────────►│
│ │── 写入结果 ──────────►│
│ │ │
│◄─ 返回结算结果 ───────│ │
│ │ │
│── 仅做 UI 展示 ────────│ │
2.2 服务端必须校验的操作清单
以下操作必须由服务端完整计算,客户端不可参与任何判定逻辑:
| 操作类别 |
具体操作 |
校验要点 |
关联接口 |
| 战斗结算 |
PVE 战斗(游历/副本/遗迹)、PVP 战斗、悬赏追杀 |
服务端加载双方属性快照 → ATB 引擎计算 → 生成战报 → 写入 battles + battle_logs |
POST /api/v1/combats、POST /api/v1/combats/pvp |
| 突破渡劫 |
小境界突破、大境界渡劫、破界晋级 |
服务端校验修为/材料/护法条件 → 概率判定 → 更新 characters.realm_tier / minor_realm / world_tier |
POST /api/v1/characters/{id}/realm/breakthrough、POST .../tribulation、POST .../world-break |
| 经济交易 |
货币增减、交易行挂单/购买、拍卖出价、悬赏赏金、天机阁情报 |
服务端校验余额 → 原子扣款/加款 → 写入 economy_audit_logs → 同步 Valkey 钱包缓存 |
POST /api/v1/market/orders/{id}/buy、POST /api/v1/auctions/{id}/bids 等 |
| 地图移动 |
跨区域移动、进入副本/遗迹、破界传送 |
服务端校验 world_tier / realm_tier 解锁状态 → 更新 characters.world_tier |
POST /api/v1/instances/{id}/enter |
| 技能学习 |
功法升层、技能学习、玉简拓印、加持切换 |
服务端校验种族/境界/属性/SAN/材料条件 → 概率判定 → 写入 character_skills / character_manuals |
POST /api/v1/characters/{id}/manuals/{mid}/upgrade、POST .../skills/learn |
| 弟子派遣 |
弟子代派任务、领地产出 |
服务端计算成功率/死亡率 → 异步结算 → 写入 disciple_missions |
POST /api/v1/disciples/{id}/dispatch |
| 组织操作 |
创建/加入/退出组织、领地竞标、帮派资金 |
服务端校验权限/条件 → 原子更新 guilds / guild_members / guild_territories |
POST /api/v1/guilds、POST .../territories/bids |
| 社交关系 |
道侣/结义/师徒请求、关系解除 |
服务端校验互斥关系/冷却时间 → 写入 social_relations / lovers / sworn_brothers |
POST /api/v1/relations/{type}/requests |
2.3 客户端仅做展示与请求的原则
| 原则 |
说明 |
| 不信任客户端数值 |
客户端发送的属性值、伤害值、概率值全部忽略,服务端自行从数据库/缓存加载 |
| 不信任客户端时间 |
所有时间判定以服务端 timestamptz 为准,客户端时间仅用于 UI 倒计时展示 |
| 不信任客户端随机 |
概率判定(突破/渡劫/技能顿悟/掉落)全部使用服务端 CSPRNG(crypto/rand) |
| 不信任客户端状态 |
客户端报告的"战斗胜利""突破成功"等状态无效,必须由服务端判定并返回 |
| 客户端仅提交意图 |
客户端发送"我要对目标 X 使用技能 Y",服务端校验技能存在性/能量/CD/目标合法性后执行 |
2.4 客户端校验(可选,提升体验)
客户端可进行以下前置校验以减少无效请求,但服务端仍需独立校验:
- 当前能量是否足够(避免发送必定失败的请求)
- 目标是否在交互范围内
- 材料是否在背包中
- 冷却是否结束
关键:客户端校验失败仅阻止本地 UI 操作,不作为任何服务端逻辑的依据。
3. 异常行为检测
3.1 加速检测
3.1.1 时间回拨检测
| 检测项 |
实现方式 |
阈值 |
响应 |
| 客户端时钟偏移 |
登录时客户端上报本地时间戳,服务端计算偏差 abs(client_ts - server_ts) |
> 300 秒 |
记录日志,连续 3 次超阈值标记可疑 |
| 请求时间序列单调性 |
同一 character_id 的请求 X-Trace-Id 中嵌入服务端接收时间戳,检查是否递增 |
出现回退 |
标记异常,回退的请求拒绝处理 |
| 游戏内时间跳跃 |
对比两次请求的 game_timestamp 差值与现实间隔 |
游戏时间增量 > 现实间隔 × 3.5 |
触发告警,暂停游历/挂机产出 |
3.1.2 速度异常检测
| 检测项 |
实现方式 |
阈值 |
响应 |
| 地图移动速度 |
计算两次位置变更的 distance / time_elapsed |
> 角色最大移动速度 × 1.2 |
重置位置,标记异常 |
| 请求频率 |
基于 Valkey 滑动窗口计数器 rate:{character_id}:{path} |
超过 TDD-05 §2.5 定义的限流值 |
返回 429,累计触发次数 |
| 战斗间隔 |
检查两次战斗请求的时间间隔 |
< 战斗最短耗时(ATB 最少回合数) |
拒绝请求,记录日志 |
| 挂机产出速率 |
对比实际产出与理论产出 expected = base_rate × duration × modifiers |
实际 > 理论 × 1.3 |
截断超出部分,标记异常 |
3.1.3 请求频率异常检测
// Go 伪代码:滑动窗口限流器(基于 Valkey)
func CheckRateLimit(characterID, path string, limit int, window time.Duration) bool {
key := fmt.Sprintf("rate:%s:%s", characterID, path)
now := time.Now().UnixMilli()
windowStart := now - window.Milliseconds()
pipe := valkey.Pipeline()
pipe.ZRemRangeByScore(ctx, key, "0", fmt.Sprintf("%d", windowStart))
pipe.ZAdd(ctx, key, &valkey.Z{Score: float64(now), Member: uuid.New().String()})
pipe.ZCard(ctx, key)
pipe.Expire(ctx, key, window)
results := pipe.Exec(ctx)
count := results[2].(*valkey.IntCmd).Val()
return count <= int64(limit)
}
3.2 数据篡改检测
3.2.1 属性/货币/背包哈希校验
对客户端展示的关键数据附加校验哈希,服务端在关键节点验证一致性:
| 数据域 |
校验方式 |
触发时机 |
| 角色属性快照 |
HMAC-SHA256(character_id + base_stats_json + battle_stats_json + secret_salt) |
登录同步、战斗前加载 |
| 货币余额 |
HMAC-SHA256(character_id + currency_code + amount + secret_salt) |
每次货币变更后生成,客户端下次请求携带 |
| 背包物品 |
HMAC-SHA256(character_id + item_count_hash + secret_salt) |
物品变更后生成 |
注意:哈希校验仅用于客户端篡改检测,服务端始终以数据库数据为准。校验失败不直接封号,而是标记可疑并触发人工审核。
3.2.2 服务端内部一致性校验
| 校验项 |
实现方式 |
频率 |
| 货币守恒 |
currency_balances.amount = total_earned - total_spent(从 economy_audit_logs 聚合) |
每日凌晨批处理 |
| 背包守恒 |
inventories 中的物品数量变化应与 economy_audit_logs 中的物品流转记录一致 |
每日凌晨批处理 |
| 境界一致性 |
characters.realm_tier 应与 character_realms.is_current=true 的记录一致 |
实时校验(突破/渡劫时) |
| 装备合法性 |
equipments 引用的 inventory_id 应属于同一 character_id,且 bind_type 与穿戴状态一致 |
装备变更时 |
3.3 机器人挂机检测
3.3.1 行为模式分析
| 特征 |
正常玩家 |
疑似机器人 |
检测方式 |
| 操作间隔分布 |
随机波动,有高峰低谷 |
高度规律,近似固定间隔 |
统计操作间隔的标准差(σ < 阈值则可疑) |
| 活跃时长 |
有休息,单次 1~3 小时 |
24 小时不间断 |
检查连续在线时长 |
| 决策模式 |
有犹豫、有选择 |
固定路线、固定操作序列 |
序列熵分析(操作序列熵低于阈值则可疑) |
| 响应速度 |
对事件有合理反应时间 |
对随机事件瞬间响应 |
事件推送 → 响应延迟统计 |
| 设备指纹 |
正常设备特征 |
模拟器/多开特征 |
设备指纹库比对(见 §3.4.4) |
3.3.2 验证码策略
| 触发条件 |
验证码类型 |
说明 |
| 连续在线 > 8 小时 |
图形验证码 / 滑块 |
强制验证,失败则暂停游历产出 |
| 操作间隔标准差低于阈值 |
行为验证码(点选/拖拽) |
3 次失败标记为可疑 |
| 被举报 2 次以上(24 小时内) |
图形验证码 |
每次登录强制验证,持续 3 天 |
| 异常 IP 段批量注册 |
注册时强制验证码 |
结合设备指纹去重 |
3.3.3 机器学习辅助检测(长期规划)
| 阶段 |
内容 |
| 数据采集 |
采集正常玩家行为序列:操作间隔、路径选择、战斗决策、市场行为 |
| 特征工程 |
提取操作熵、时间分布特征、社交图谱密度、经济行为模式 |
| 模型训练 |
使用 Isolation Forest 或 LSTM-AutoEncoder 训练异常检测模型 |
| 线上部署 |
对可疑行为打分,超过阈值触发人工审核,不自动封号 |
3.4 协议攻击检测
3.4.1 重放攻击防护
| 机制 |
实现 |
| Nonce 校验 |
每个请求携带 X-Nonce: <uuid>,服务端在 Valkey 中存储已用 Nonce(TTL 5 分钟),重复 Nonce 拒绝处理 |
| Timestamp 校验 |
请求携带 X-Timestamp: <unix_ms>,服务端校验 abs(now - timestamp) < 60s,超出窗口拒绝 |
| Sequence Number |
高敏感操作(交易/拍卖/悬赏)使用递增 X-Sequence,服务端校验单调递增,跳跃过大拒绝 |
| Idempotency-Key |
所有扣费/扣材料操作要求 Idempotency-Key,服务端以 character_id + key 去重 24 小时(TDD-05 §5) |
// 请求头扩展(protobuf 定义)
message SecureRequestHeader {
string session_token = 1;
string nonce = 2; // UUID v4
int64 timestamp = 3; // Unix 毫秒
int64 sequence = 4; // 单调递增序号
string idempotency_key = 5; // 幂等键(写操作必填)
bytes signature = 6; // HMAC-SHA256 签名(高敏感操作)
}
3.4.2 中间人攻击防护
| 措施 |
说明 |
| 全链路 TLS 1.3 |
HTTPS / WSS / gRPC 全部启用 TLS 1.3,禁止降级到 TLS 1.2 以下 |
| 证书固定(Certificate Pinning) |
客户端内置服务端证书指纹,防止中间人伪造证书 |
| 请求签名 |
高敏感操作(交易/出价/悬赏)要求客户端对请求体做 HMAC-SHA256 签名,密钥由 Nakama session 派生(TDD-05 §5) |
| 响应签名 |
服务端对关键响应(战斗结算/突破结果/交易确认)附加签名,客户端验证完整性 |
3.4.3 伪造 Token 防护
| 机制 |
说明 |
| Nakama Session 签名 |
Token 由 Nakama 使用 HMAC-SHA256 签名,服务端校验签名完整性 |
| Token 绑定 |
Token 与 device_id + ip_geo 绑定,异地登录触发二次验证 |
| Token 吊销 |
异常行为检测到后,通过 Nakama Admin API 强制吊销 Token |
| Token 刷新 |
长期 Token(60 天)可被服务端主动过期,强制重新登录 |
3.4.4 设备指纹与多开检测
| 特征 |
采集方式 |
用途 |
device_id |
客户端生成并上报 |
账号绑定,防止刷号 |
| 设备型号 / OS 版本 |
客户端上报 |
模拟器检测 |
| 屏幕分辨率 / DPI |
客户端上报 |
多开检测(同一分辨率批量注册) |
| IP 地址 / 地理位置 |
服务端获取 |
异地登录检测、IP 黑名单 |
| 安装应用列表哈希 |
客户端采集(需用户授权) |
外挂工具检测 |
隐私合规:设备指纹采集需符合《个人信息保护法》,在隐私政策中明确告知,并提供关闭选项(关闭后功能受限)。
4. 经济安全
4.1 RMT(Real Money Trading)检测
4.1.1 异常交易模式检测
| 检测规则 |
触发条件 |
响应 |
| 单向大额转账 |
24 小时内 A → B 的交易行购买总额 > 5000 灵石,且 B → A 无反向交易 |
标记可疑,冻结双方交易功能 24 小时,触发人工审核 |
| 新号转金 |
创建 < 7 天的角色在交易行购买总额 > 2000 灵石 |
标记可疑,限制交易行购买额度 |
| 关联账号网络 |
多个账号之间形成闭环交易链(A→B→C→A) |
标记整组账号,触发人工审核 |
| 固定价格交易 |
同一卖家对同一买家以相同价格反复交易 |
标记可疑,检查是否为 RMT 通道 |
| 离线交易 |
卖家长时间不在线但持续有高价成交 |
标记可疑,检查是否为傀儡账号 |
4.1.2 RMT 检测评分模型
RMT_RISK_SCORE = (
单向交易金额占比 × 0.3 +
交易频率异常度 × 0.2 +
账号年龄因子 × 0.15 +
社交图谱稀疏度 × 0.15 +
价格偏离度 × 0.2
) × 100
阈值:
score < 40 → 正常
40 ≤ score < 70 → 标记观察
70 ≤ score < 90 → 标记可疑,限制交易
score ≥ 90 → 标记高危,冻结账号,触发人工审核
4.1.3 RMT 数据库表
-- RMT 检测记录表
CREATE TABLE rmt_detection_records (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
character_id uuid NOT NULL REFERENCES characters(id),
risk_score numeric(5,2) NOT NULL,
risk_level varchar(16) NOT NULL, -- normal / watch / suspicious / critical
trigger_rules jsonb NOT NULL, -- 触发的规则列表
related_ids uuid[], -- 关联的交易/订单 ID
status varchar(16) NOT NULL DEFAULT 'pending', -- pending / reviewing / confirmed / cleared
reviewer_id uuid, -- 审核人
review_note text,
created_at timestamptz NOT NULL DEFAULT now(),
reviewed_at timestamptz
);
CREATE INDEX idx_rmt_character ON rmt_detection_records(character_id, created_at);
CREATE INDEX idx_rmt_status ON rmt_detection_records(status, risk_level);
4.2 刷金检测
4.2.1 产出速率异常检测
| 检测维度 |
基线计算 |
异常阈值 |
响应 |
| 游历产出 |
base_rate × duration × race_modifier × realm_modifier |
实际 > 基线 × 1.5 |
截断超出部分,标记异常 |
| 副本产出 |
instance_reward × difficulty_coefficient × party_bonus |
实际 > 预期 × 1.3 |
截断,标记异常 |
| 挂机产出 |
gathering_rate × duration × talent_modifier |
实际 > 理论 × 1.5 |
截断,标记异常 |
| 悬赏收益 |
bounty_reward × completion_rate |
单日悬赏收益 > 基线 × 3 |
标记异常,限制接取 |
4.2.2 多号联动检测
| 检测规则 |
触发条件 |
响应 |
| 同 IP 批量注册 |
同一 IP 24 小时内注册 > 3 个账号 |
注册时强制验证码,标记关联 |
| 同设备多号 |
同一 device_id 绑定 > 2 个账号 |
标记关联,共享风控评分 |
| 多号向单号集中转金 |
> 3 个账号在 24 小时内向同一账号交易 |
标记目标账号,触发人工审核 |
| 多号协同刷副本 |
同一 IP 段的多个账号同时进入同一副本 |
标记异常,检查是否为工作室 |
4.2.3 产出监控看板指标
| 指标 |
计算方式 |
告警阈值 |
| 全服货币通胀率 |
(total_supply_today - total_supply_yesterday) / total_supply_yesterday |
> 5%/天 |
| 人均产出偏差 |
avg(player产出) / theoretical_avg |
> 1.5 |
| Top 1% 产出占比 |
top1%_产出 / total_产出 |
> 30% |
| 新号产出集中度 |
accounts_7d产出 / total_产出 |
> 20% |
4.3 洗钱检测
4.3.1 交易行价格操纵检测
| 检测规则 |
触发条件 |
响应 |
| 异常低价挂单 |
挂单价格 < 近 7 天同物品均价 × 0.3 |
标记可疑,限制成交,触发人工审核 |
| 异常高价购买 |
购买价格 > 近 7 天同物品均价 × 3.0 |
标记可疑,记录买家信息 |
| 自买自卖 |
卖家与买家为同一账号(或关联账号) |
拒绝成交,标记异常 |
| 批量低买高卖 |
短时间内大量低价收购后高价出售 |
标记可疑,检查是否为价格操纵 |
| 价格异常波动 |
物品价格在 1 小时内波动 > 50% |
触发告警,人工审核 |
4.3.2 拍卖自拍自买检测
| 检测规则 |
触发条件 |
响应 |
| 卖家 = 出价者 |
auctions.seller_id = auction_bids.bidder_id |
数据库约束拒绝 |
| 关联账号出价 |
卖家与出价者为关联账号(同设备/IP/交易历史) |
标记可疑,取消出价 |
| 保证金循环 |
拍卖失败后保证金退回 → 立即用于下一次出价 |
检查资金循环频率 |
| 价格虚高 |
拍卖成交价 > 近 7 天同物品均价 × 5.0 |
标记可疑,触发人工审核 |
4.3.3 经济异常自动响应
// 经济异常响应状态机
type EcoAnomalyResponse struct {
Level string // watch / restrict / freeze / ban
Actions []string
}
var anomalyResponses = map[string]EcoAnomalyResponse{
"watch": {
Level: "watch",
Actions: []string{"log_detail", "increase_monitoring"},
},
"restrict": {
Level: "restrict",
Actions: []string{"limit_trade_amount", "limit_trade_frequency", "require_captcha"},
},
"freeze": {
Level: "freeze",
Actions: []string{"freeze_trade", "freeze_withdraw", "notify_reviewer"},
},
"ban": {
Level: "ban",
Actions: []string{"freeze_account", "notify_admin", "create_ticket"},
},
}
5. 举报与惩罚系统
5.1 举报类型
| 举报类型 |
说明 |
证据要求 |
优先级 |
| 外挂/加速器 |
使用第三方工具加速/修改游戏 |
截图/视频 + 异常行为记录 |
高 |
| 辱骂/骚扰 |
聊天频道发布不当言论 |
聊天记录截图 |
中 |
| 诈骗 |
虚假交易/冒充GM/诱导转账 |
交易记录 + 聊天记录 |
高 |
| RMT |
现金交易游戏资源 |
交易异常记录 |
高 |
| 利用BUG |
利用游戏漏洞获取不当利益 |
详细复现步骤 |
紧急 |
| 其他 |
不当角色名/组织名等 |
截图 |
低 |
5.2 举报接口
| 项目 |
内容 |
| 功能 |
玩家提交举报 |
| REST |
POST /api/v1/reports |
| 请求参数 |
target_character_id(uuid)、report_type(string)、description(string)、evidence_urls([]string,可选)、battle_id(uuid,可选) |
| 限流 |
5 次/天/角色 |
| 错误码 |
9101(举报类型非法)、9102(目标不存在)、9103(今日举报次数已满)、9104(不可举报自己) |
5.3 举报数据表
CREATE TABLE player_reports (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
reporter_id uuid NOT NULL REFERENCES characters(id),
target_id uuid NOT NULL REFERENCES characters(id),
report_type varchar(32) NOT NULL, -- cheat / insult / fraud / rmt / bug_exploit / other
description text,
evidence_urls text[],
related_battle_id uuid,
related_trade_id uuid,
status varchar(16) NOT NULL DEFAULT 'pending', -- pending / reviewing / resolved / dismissed
priority smallint NOT NULL DEFAULT 2, -- 1=紧急 2=高 3=中 4=低
reviewer_id uuid,
review_result varchar(16), -- confirmed / insufficient_evidence / false_report
review_note text,
created_at timestamptz NOT NULL DEFAULT now(),
reviewed_at timestamptz
);
CREATE INDEX idx_reports_status ON player_reports(status, priority, created_at);
CREATE INDEX idx_reports_target ON player_reports(target_id, created_at);
5.4 人工审核流程
玩家举报
│
▼
自动分类 + 优先级排序
│
├── 紧急(利用BUG/RMT高危)──► 自动冻结可疑账号 ──► 24小时内人工审核
│
├── 高(外挂/诈骗)──► 48小时内人工审核
│
├── 中(辱骂)──► 72小时内人工审核
│
└── 低(其他)──► 7天内人工审核
│
▼
人工审核
│
├── 确认违规 ──► 执行惩罚 ──► 通知举报者
│
├── 证据不足 ──► 标记观察 ──► 通知举报者
│
└── 误报 ──► 驳回 ──► 恶意举报者扣信用分
5.5 惩罚梯度
| 惩罚等级 |
适用场景 |
执行方式 |
持续时间 |
| 警告 |
首次轻微违规(辱骂/不当名) |
站内信通知 |
永久记录 |
| 禁言 |
重复辱骂/刷屏 |
冻结聊天功能 |
1~7 天 |
| 交易限制 |
疑似 RMT/刷金 |
限制交易行/拍卖操作 |
3~30 天 |
| 功能封禁 |
使用外挂/严重 BUG 利用 |
封禁特定功能(PVP/副本/交易) |
7~90 天 |
| 临时封号 |
严重违规/屡教不改 |
冻结账号,禁止登录 |
7~180 天 |
| 永久封禁 |
极端违规(大规模 RMT/外挂开发/恶意攻击) |
永久冻结账号 + 设备黑名单 |
永久 |
惩罚数据库表
CREATE TABLE punishment_records (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
character_id uuid NOT NULL REFERENCES characters(id),
player_id uuid NOT NULL REFERENCES players(id),
punishment_type varchar(16) NOT NULL, -- warning / mute / trade_ban / feature_ban / temp_ban / perm_ban
reason text NOT NULL,
report_id uuid REFERENCES player_reports(id),
related_rule varchar(64), -- 违反的规则编号
start_at timestamptz NOT NULL DEFAULT now(),
end_at timestamptz, -- 永久封禁为 NULL
is_active boolean NOT NULL DEFAULT true,
issued_by varchar(32) NOT NULL, -- system / admin_id
appeal_status varchar(16) DEFAULT 'none', -- none / pending / approved / rejected
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX idx_punishment_character ON punishment_records(character_id, is_active);
CREATE INDEX idx_punishment_player ON punishment_records(player_id, is_active);
5.6 申诉机制
| 项目 |
说明 |
| 申诉入口 |
游戏内「客服中心」→「申诉」 |
| 申诉条件 |
被处罚后 7 天内可提交,每个处罚仅可申诉 1 次 |
| 申诉内容 |
申诉理由(文字)+ 补充证据(截图/视频链接) |
| 审核时限 |
3 个工作日内给出结果 |
| 申诉结果 |
维持原判 / 减轻处罚 / 撤销处罚 |
| 恶意申诉 |
连续 3 次申诉被驳回,后续申诉优先级降低 |
申诉接口
| 项目 |
内容 |
| REST |
POST /api/v1/appeals |
| 请求参数 |
punishment_id(uuid)、reason(string)、evidence_urls([]string) |
| 限流 |
1 次/天 |
| 错误码 |
9201(处罚不存在)、9202(已申诉过)、9203(申诉窗口已过) |
6. 接口安全
6.1 限流策略
限流在网关层(OpenResty/Traefik)基于 Token Bucket 实现,详见 TDD-05 §2.5。本节补充安全相关的限流细节。
6.1.1 限流维度
| 维度 |
说明 |
实现 |
| IP 维度 |
防止单 IP 批量请求 |
Valkey SET rate:ip:{ip} {count} EX 60 NX |
| 账号维度 |
防止单账号刷接口 |
Valkey ZSET rate:char:{id}:{path} 滑动窗口 |
| 接口维度 |
热点接口单独限流 |
按 path + method 组合配置 |
| 设备维度 |
防止多开刷量 |
device_id 维度限流 |
| 全局维度 |
防止 DDoS |
云防火墙 + WAF 全局限流 |
6.1.2 安全增强限流
| 场景 |
策略 |
| 登录失败 |
5 次失败后锁定 15 分钟,10 次失败后锁定 1 小时 |
| 注册 |
同 IP 每天最多 3 次注册 |
| 交易操作 |
新账号(< 7 天)交易行操作限流加倍 |
| 异常 IP |
被标记的 IP 段所有请求限流降至 1/10 |
6.2 防重放攻击
详见 §3.4.1。核心机制:
- Nonce + Timestamp:每个请求携带唯一 Nonce 和时间戳,服务端校验唯一性与时效性
- Sequence Number:高敏感操作使用递增序号
- Idempotency-Key:所有写操作幂等控制
// 防重放校验中间件
func AntiReplayMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
nonce := r.Header.Get("X-Nonce")
timestamp := r.Header.Get("X-Timestamp")
// 1. 校验 Nonce 唯一性
if !valkey.SetNX(ctx, "nonce:"+nonce, "1", 5*time.Minute).Val() {
writeError(w, 9004, "duplicate request")
return
}
// 2. 校验时间窗口
ts, _ := strconv.ParseInt(timestamp, 10, 64)
if abs(time.Now().UnixMilli()-ts) > 60000 {
writeError(w, 9005, "request expired")
return
}
next.ServeHTTP(w, r)
})
}
6.3 DDoS 防护
| 层级 |
措施 |
说明 |
| 网络层 |
云防火墙 |
腾讯云 DDoS 防护,SYN Flood / UDP Flood / ACK Flood 清洗 |
| 传输层 |
CDN |
静态资源通过 CDN 分发,隐藏源站 IP |
| 应用层 |
WAF |
OpenResty + lua-resty-waf,SQL 注入 / XSS / 路径遍历防护 |
| 业务层 |
限流 + 验证码 |
超限请求返回 429,可疑流量触发验证码 |
| 数据库层 |
连接池限制 |
PostgreSQL max_connections 限制,防止连接耗尽 |
6.3.1 WAF 规则
# OpenResty WAF 配置示例
lua_shared_dict waf_rules 10m;
init_by_lua_block {
local waf = require "resty.waf"
waf.init()
}
access_by_lua_block {
local waf = require "resty.waf"
local ctx = waf.new()
ctx:set_option("mode", "ACTIVE")
ctx:set_option("request_body_limit", 1048576) -- 1MB
ctx:exec()
}
6.4 SQL 注入 / XSS 防护
| 防护项 |
措施 |
| SQL 注入 |
所有数据库操作使用参数化查询(pgx / gorm prepared statement),禁止字符串拼接 SQL |
| XSS |
输出编码(HTML Entity / JSON Escape),CSP 头限制脚本来源 |
| CSRF |
API 使用 Token 认证(非 Cookie),天然免疫 CSRF |
| 路径遍历 |
文件操作限制在白名单目录,禁止 ../ 路径 |
| 命令注入 |
禁止 os.Exec 拼接用户输入,使用参数化调用 |
| SSRF |
内部服务调用使用白名单 URL,禁止用户指定目标地址 |
// 参数化查询示例(pgx)
func GetCharacter(db *pgxpool.Pool, characterID uuid.UUID) (*Character, error) {
var c Character
err := db.QueryRow(ctx,
`SELECT id, name, race_id, world_tier, realm_tier, minor_realm
FROM characters WHERE id = $1`, characterID,
).Scan(&c.ID, &c.Name, &c.RaceID, &c.WorldTier, &c.RealmTier, &c.MinorRealm)
return &c, err
}
6.5 CSP(Content Security Policy)头
add_header Content-Security-Policy "
default-src 'self';
script-src 'self' 'unsafe-inline' 'unsafe-eval';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
connect-src 'self' wss://*.honghuang.example.com https://api.honghuang.example.com;
font-src 'self';
object-src 'none';
base-uri 'self';
form-action 'self';
" always;
7. 数据安全
7.1 敏感数据加密
| 数据类型 |
加密方式 |
存储位置 |
说明 |
| 密码 |
bcrypt(cost=12) |
PostgreSQL players 表 |
仅账号系统使用,Nakama 内置处理 |
| 支付信息 |
AES-256-GCM |
独立支付数据库 |
充值记录加密存储,解密密钥独立管理 |
| Session Token |
HMAC-SHA256 签名 |
Nakama 内部 |
Token 本身不存储,仅存储签名 |
| 设备指纹 |
SHA-256 哈希 |
PostgreSQL players.device_id_hash |
不存储原始设备 ID |
| API 密钥 |
环境变量 / 密钥管理服务 |
服务端配置 |
不硬编码,不写入日志 |
| 数据库连接 |
TLS + 密钥文件 |
服务端配置 |
PostgreSQL 连接使用 SSL |
7.2 日志脱敏
| 日志类型 |
脱敏规则 |
示例 |
| 玩家 IP |
保留前两段,后两段替换为 *** |
192.168.***.*** |
| 设备 ID |
仅保留哈希值 |
sha256:a1b2c3... |
| 角色名 |
正常记录(非敏感) |
铁爪传 |
| 货币金额 |
正常记录(审计需要) |
1280 |
| 请求体 |
移除 Token / 密码字段 |
{"device_id": "***", "platform": "ios"} |
| 错误堆栈 |
移除文件路径中的用户名 |
/app/internal/handler/... |
// 日志脱敏中间件
func SanitizeLogMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 脱敏请求头
sanitizedHeaders := sanitizeHeaders(r.Header)
log.Info("incoming request",
zap.String("method", r.Method),
zap.String("path", r.URL.Path),
zap.String("ip", maskIP(r.RemoteAddr)),
zap.Any("headers", sanitizedHeaders),
)
next.ServeHTTP(w, r)
})
}
func maskIP(ip string) string {
// "192.168.1.100:8080" -> "192.168.***.***:***"
host, port, _ := net.SplitHostPort(ip)
parts := strings.Split(host, ".")
if len(parts) == 4 {
return parts[0] + "." + parts[1] + ".***.***:***"
}
return "***"
}
7.3 传输加密
| 场景 |
加密方式 |
说明 |
| 客户端 ↔ 网关 |
TLS 1.3 |
HTTPS / WSS |
| 网关 ↔ 服务端 |
mTLS |
内部服务间双向 TLS |
| 服务端 ↔ 数据库 |
SSL |
PostgreSQL sslmode=verify-full |
| 服务端 ↔ Valkey |
TLS |
Valkey 6.0+ 支持 |
| 服务端 ↔ Nacos |
HTTPS |
Nacos 2.x 配置传输 |
7.4 数据备份与恢复
| 备份类型 |
频率 |
保留策略 |
存储位置 |
| PostgreSQL 全量备份 |
每日凌晨 03:00 |
保留 30 天 |
对象存储(腾讯云 COS) |
| PostgreSQL WAL 增量 |
实时 |
保留 7 天 |
对象存储 |
| Valkey RDB 快照 |
每 6 小时 |
保留 3 天 |
本地 + 对象存储 |
| 配置备份 |
每次变更 |
永久 |
Git 仓库 |
7.5 GDPR / 个人信息保护合规
7.5.1 数据分类
| 数据类别 |
包含字段 |
处理依据 |
保留期限 |
| 账号信息 |
player_id, device_id_hash, platform |
合同履行 |
账号存续期间 + 3 年 |
| 游戏角色 |
character_id, name, race_id, 等级/属性 |
合同履行 |
账号存续期间 |
| 行为数据 |
登录日志, 操作日志, 战斗记录 |
合法利益(安全) |
12 个月 |
| 交易数据 |
充值记录, 交易行记录 |
法律义务(财务) |
5 年 |
| 设备信息 |
设备型号, OS 版本, IP |
合法利益(安全) |
6 个月 |
| 聊天记录 |
聊天内容 |
合法利益(举报审核) |
3 个月 |
7.5.2 用户权利实现
| 权利 |
实现方式 |
响应时限 |
| 知情权 |
隐私政策中明确告知数据收集范围与用途 |
首次安装时展示 |
| 访问权 |
提供数据导出接口 GET /api/v1/privacy/export |
30 天内 |
| 更正权 |
角色名修改、绑定手机修改 |
即时 |
| 删除权 |
账号注销接口 DELETE /api/v1/privacy/account |
30 天内完成数据删除(法律保留除外) |
| 撤回同意 |
关闭设备指纹采集(功能受限) |
即时 |
| 可携带权 |
数据导出为 JSON/CSV 格式 |
30 天内 |
7.5.3 账号注销流程
玩家申请注销
│
▼
校验条件
│
├── 有未完成的交易/拍卖 ──► 拒绝,提示先处理
│
├── 有未结束的组织关系 ──► 拒绝,提示先退出
│
└── 条件满足 ──► 进入 30 天冷静期
│
▼
30 天冷静期(可随时取消)
│
▼
执行删除
│
├── 删除:characters, inventories, currency_balances, 等游戏数据
│
├── 匿名化:players 表保留 player_id 用于审计,其他字段替换为匿名值
│
└── 保留:economy_audit_logs, punishment_records(法律义务)
8. 安全审计与监控
8.1 审计日志
| 日志类型 |
记录内容 |
保留期限 |
| 登录日志 |
player_id, ip, device_id_hash, login_time, login_result |
12 个月 |
| 操作日志 |
character_id, action, params_hash, result, timestamp |
12 个月 |
| 经济日志 |
economy_audit_logs(TDD-04 §5.4) |
12 个月 |
| 安全日志 |
异常行为检测结果、封禁记录、举报处理记录 |
24 个月 |
| 管理日志 |
GM 操作、配置变更、手动封禁 |
永久 |
8.2 监控告警
| 监控项 |
告警阈值 |
通知方式 |
| 登录失败率 |
> 10%(5 分钟窗口) |
企业微信 + 邮件 |
| 异常行为检测触发数 |
> 50 次/小时 |
企业微信 |
| 经济异常(通胀率) |
> 5%/天 |
企业微信 + 邮件 |
| API 错误率 |
> 5%(1 分钟窗口) |
企业微信 + 电话 |
| 数据库连接数 |
> 80% max_connections |
企业微信 |
| 内存使用率 |
> 85% |
企业微信 |
| 磁盘使用率 |
> 90% |
企业微信 + 电话 |
8.3 安全事件响应流程
安全事件发生
│
▼
自动检测 + 告警
│
├── P0(严重:数据泄露/服务中断)──► 15分钟内响应 ──► 1小时内止损 ──► 24小时内复盘
│
├── P1(高:大规模外挂/经济崩溃)──► 30分钟内响应 ──► 4小时内止损 ──► 3天内复盘
│
├── P2(中:个别外挂/RMT)──► 2小时内响应 ──► 24小时内处理
│
└── P3(低:轻微违规)──► 24小时内响应 ──► 7天内处理
9. 已确认决策记录表
| # |
决策 |
确认时间 |
| ✅S01 |
所有战斗结算(PVE/PVP/悬赏/追杀)完全服务端权威,客户端仅提交意图 |
2026-07-02 |
| ✅S02 |
突破/渡劫/破界的概率判定使用服务端 CSPRNG(crypto/rand),不使用客户端随机数 |
2026-07-02 |
| ✅S03 |
经济交易(交易行/拍卖/悬赏/天机阁)全部服务端原子操作,写入 economy_audit_logs |
2026-07-02 |
| ✅S04 |
地图移动/副本进入的服务端校验包含 world_tier / realm_tier / 解锁状态 / 钥匙/次数 |
2026-07-02 |
| ✅S05 |
技能学习/功法升层的服务端校验包含种族/境界/属性/SAN/材料/来源标签 |
2026-07-02 |
| ✅S06 |
防重放采用 Nonce + Timestamp + Sequence 三重机制,高敏感操作额外使用 Idempotency-Key |
2026-07-02 |
| ✅S07 |
全链路 TLS 1.3,客户端证书固定(Certificate Pinning) |
2026-07-02 |
| ✅S08 |
RMT 检测采用评分模型,score ≥ 90 自动冻结账号并触发人工审核 |
2026-07-02 |
| ✅S09 |
刷金检测基于产出速率基线对比 + 多号联动分析 |
2026-07-02 |
| ✅S10 |
洗钱检测覆盖交易行价格操纵 + 拍卖自拍自买 + 价格异常波动 |
2026-07-02 |
| ✅S11 |
举报系统支持 6 种类型,紧急举报自动冻结可疑账号,24 小时内人工审核 |
2026-07-02 |
| ✅S12 |
惩罚梯度 6 级:警告/禁言/交易限制/功能封禁/临时封号/永久封禁 |
2026-07-02 |
| ✅S13 |
申诉机制:处罚后 7 天内可申诉,每个处罚仅 1 次,3 个工作日出结果 |
2026-07-02 |
| ✅S14 |
限流按 IP/账号/接口/设备/全局五维度,网关层 Token Bucket 实现 |
2026-07-02 |
| ✅S15 |
日志脱敏:IP 保留前两段、设备 ID 仅存哈希、请求体移除 Token/密码 |
2026-07-02 |
| ✅S16 |
账号注销 30 天冷静期,删除游戏数据,匿名化账号信息,保留法律义务数据 |
2026-07-02 |
| ✅S17 |
敏感数据加密:密码 bcrypt、支付信息 AES-256-GCM、设备指纹 SHA-256 |
2026-07-02 |
| ✅S18 |
安全事件分级响应:P0(15分钟)/P1(30分钟)/P2(2小时)/P3(24小时) |
2026-07-02 |
10. 验收标准
| # |
验收条目 |
测试方法 |
预期结果 |
| 1 |
客户端伪造战斗胜利结果,服务端不接受 |
客户端篡改战斗结果字段发送请求 |
服务端独立计算,返回真实结果 |
| 2 |
客户端伪造突破概率,服务端不接受 |
客户端发送 success: true 字段 |
服务端独立判定,返回真实结果 |
| 3 |
客户端伪造货币余额,服务端不接受 |
客户端发送篡改后的余额哈希 |
服务端以数据库为准,哈希校验失败标记可疑 |
| 4 |
重放攻击被拒绝 |
重复发送同一 Nonce 的请求 |
第二次返回 9004 |
| 5 |
时间窗口外的请求被拒绝 |
发送 timestamp 偏差 > 60s 的请求 |
返回 9005 |
| 6 |
高频请求触发限流 |
短时间发送超过限流阈值的请求 |
返回 429,响应头包含限流信息 |
| 7 |
异常交易触发 RMT 检测 |
模拟单向大额转账行为 |
生成 rmt_detection_records,risk_level = suspicious |
| 8 |
举报系统正常工作 |
提交举报并检查状态流转 |
举报创建成功,状态为 pending |
| 9 |
惩罚系统正常执行 |
执行禁言惩罚 |
角色聊天功能被禁用,到期自动恢复 |
| 10 |
申诉流程正常 |
对处罚提交申诉 |
申诉创建成功,状态为 pending |
| 11 |
SQL 注入防护 |
在请求参数中注入 SQL 语句 |
请求被拒绝或参数被安全处理 |
| 12 |
XSS 防护 |
在角色名/聊天内容中注入脚本 |
输出被编码,脚本不执行 |
| 13 |
TLS 证书固定生效 |
使用伪造证书连接 |
连接被拒绝 |
| 14 |
日志脱敏正确 |
检查日志中的 IP 和设备 ID |
IP 后两段为 ***,设备 ID 为哈希值 |
| 15 |
账号注销流程正确 |
申请注销并等待冷静期 |
30 天后游戏数据被删除,账号信息被匿名化 |
| 16 |
经济守恒校验通过 |
运行每日批处理校验 |
currency_balances.amount = total_earned - total_spent 成立 |
| 17 |
机器人检测生效 |
模拟固定间隔操作模式 |
操作间隔标准差低于阈值时触发验证码 |
| 18 |
设备指纹采集合规 |
检查隐私政策和采集逻辑 |
隐私政策明确告知,关闭选项可用 |
11. 与关联文档的映射
| 关联文档 |
本安全设计承接点 |
| TDD-04 |
economy_audit_logs 用于经济守恒校验;rmt_detection_records / player_reports / punishment_records 新增表 |
| TDD-05 |
限流策略(§2.5)、认证方式(§2.2)、幂等控制(§5)在本文档扩展安全细节 |
| GDD-02 |
战斗结算服务端权威(✅1);概率/机遇驱动(✅37);死亡惩罚(✅25);充值体系(✅22) |
| GDD-03 |
战斗 ATB 引擎完全服务端计算;文字战报由服务端生成 |
| GDD-06 |
经济 Faucet/Sink 框架;货币分层;交易行/拍卖/天机阁交易安全 |
| GDD-13 |
佣兵委托/悬赏系统防刷检测 |
| GDD-14 |
拍卖双轨制安全;追杀令防滥用;黑吃黑检测 |
| GDD-16 |
社交关系防刷(道侣/结义/师徒请求频率限制) |
12. 版本记录
| 版本 |
日期 |
修订内容 |
作者 |
| 1.0 |
2026-07-02 |
初始版本:服务端权威模型、异常行为检测(加速/篡改/机器人/协议攻击)、经济安全(RMT/刷金/洗钱)、举报惩罚系统、接口安全、数据安全、审计监控、验收标准 |
Claude |
本文档阈值/参数均引用 Nacos 动态配置,服务端实现时以运行时配置为准,不硬编码。安全规则可根据运营数据持续调整。