lawless/docs/技术文档/TDD-07-反作弊与安全设计.md

866 行
41 KiB
Markdown

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

# 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
// 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 中存储已用 NonceTTL 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
// 请求头扩展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 刷新 | 长期 Token60 天)可被服务端主动过期,强制重新登录 |
#### 3.4.4 设备指纹与多开检测
| 特征 | 采集方式 | 用途 |
|------|----------|------|
| `device_id` | 客户端生成并上报 | 账号绑定,防止刷号 |
| 设备型号 / OS 版本 | 客户端上报 | 模拟器检测 |
| 屏幕分辨率 / DPI | 客户端上报 | 多开检测(同一分辨率批量注册) |
| IP 地址 / 地理位置 | 服务端获取 | 异地登录检测、IP 黑名单 |
| 安装应用列表哈希 | 客户端采集(需用户授权) | 外挂工具检测 |
> **隐私合规**:设备指纹采集需符合《个人信息保护法》,在隐私政策中明确告知,并提供关闭选项(关闭后功能受限)。
---
## 4. 经济安全
### 4.1 RMTReal 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 数据库表
```sql
-- 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 经济异常自动响应
```go
// 经济异常响应状态机
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 举报数据表
```sql
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/外挂开发/恶意攻击) | 永久冻结账号 + 设备黑名单 | 永久 |
#### 惩罚数据库表
```sql
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核心机制
1. **Nonce + Timestamp**每个请求携带唯一 Nonce 和时间戳服务端校验唯一性与时效性
2. **Sequence Number**高敏感操作使用递增序号
3. **Idempotency-Key**所有写操作幂等控制
```go
// 防重放校验中间件
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-wafSQL 注入 / XSS / 路径遍历防护 |
| **业务层** | 限流 + 验证码 | 超限请求返回 429可疑流量触发验证码 |
| **数据库层** | 连接池限制 | PostgreSQL `max_connections` 限制防止连接耗尽 |
#### 6.3.1 WAF 规则
```nginx
# 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禁止用户指定目标地址 |
```go
// 参数化查询示例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 CSPContent Security Policy
```nginx
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 敏感数据加密
| 数据类型 | 加密方式 | 存储位置 | 说明 |
|----------|----------|----------|------|
| 密码 | bcryptcost=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/...` |
```go
// 日志脱敏中间件
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_logsTDD-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 | 安全事件分级响应P015分钟/P130分钟/P22小时/P324小时 | 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 动态配置,服务端实现时以运行时配置为准,不硬编码。安全规则可根据运营数据持续调整。*