V5.0 安全模块大扩展:Meteor Client 全功能反作弊 + AI行为分析 + 服务器保护

新增 45 个安全模块,覆盖 Meteor Client 全部 hack 类别:

【反作弊基础扩展 6 模块】
- AntiTimerService: 游戏加速检测(移动tick间隔分析)
- AntiVelocityService: 击退修改检测(伤害后速度分析)
- AntiPhaseService: 穿墙检测(固体方块射线追踪)
- AntiBlinkService: 闪烁检测(伤害-断连-重连时序)
- AntiFastBreakService: 快速破坏检测(方块标准破坏时间对比)
- AntiElytraFlyService: 鞘翅飞行检测(速度/高度操控分析)

【Meteor Combat 10 模块】
- AntiCriticalsService: 自动暴击检测(跳跃/地面状态验证)
- AntiAutoCrystalService: 水晶Aura检测(放置/爆炸时序分析)
- AntiAutoTotemService: 自动图腾检测(副手装备速度分析)
- AntiSurroundService: 自动包围检测(脚下方块精确放置模式)
- AntiAutoTrapService: 自动陷阱检测(目标周围方块网格分析)
- AntiAutoArmorService: 自动装备检测(多槽位同tick交换)
- AntiChestSwapService: 自动胸甲交换检测(鞘翅-胸甲乒乓切换)
- AntiAutoLogService: 自动断线检测(伤害-断连500ms时序)
- AntiHitboxesService: 扩展碰撞箱检测(射线-边界边缘命中率)
- AntiBowAimBotService: 弓箭自瞄检测(移动目标精度分析)

【Meteor Movement 10 模块】
- AntiNoSlowService: 无减速检测(物品使用+移动速度组合)
- AntiSpiderService: 爬墙检测(无攀爬方块垂直上升)
- AntiStepService: 自动跨步检测(非跳跃1格上升)
- AntiPacketFlyService: 数据包飞行检测(连续悬浮/弹跳模式)
- AntiAirJumpService: 空中跳跃检测(离地跳跃包)
- AntiLongJumpService: 远跳检测(跳跃后水平速度衰减分析)
- AntiAntiHungerService: 免饥饿检测(活动量vs饥饿消耗率)
- AntiFastFallService: 快速下落检测(超终端速度持续下落)
- AntiVClipService: 垂直穿墙检测(固体方块间瞬移)
- AntiNoFallService 增强: 新增GroundSpoof/数据包地面/坠落累积/瞬移坠落检测

【Meteor World+Player 10 模块】
- AntiSpeedMineService: 加速挖掘检测(方块标准破坏时间对比)
- AntiFastUseService: 快速使用检测(物品冷却时间分析)
- AntiNoInteractService: 交互绕过检测(持剑开箱等异常操作)
- AntiAutoMineService: 自动挖掘检测(挖掘间隔方差/视角追踪)
- AntiVeinMinerService: 连锁挖矿检测(相邻矿石快速序列)
- AntiAutoToolService: 自动工具检测(同tick切工具+开挖)
- AntiFakePlayerService: 假人检测(心跳响应/交互缺失/移动模式)
- AntiPistonAuraService: 活塞光环检测(战斗上下文活塞激活率)
- AntiAnchorService: 锚定检测(受击零位移+封闭空间)
- AntiStashFinderService: 仓库扫描检测(网格区块加载+零交互)

【网络协议安全 5 模块】
- ProtocolStateValidator: 协议状态机验证(四态转换违规检测)
- TokenBucketRateLimiter: 令牌桶速率限制器(可复用速率控制基元)
- BotFingerprintDetector: 机器人指纹检测(五维行为指纹分析)
- NBTExploitPrevention: NBT漏洞防护(深度/大小/书页/告示牌验证)
- ConnectionHandshakeValidator: 握手完整性验证(协议版本/状态/主机名)

【服务器保护 4 模块】
- ChunkLoadRateLimiter: 区块加载限制器(WARN/LIMIT/BLOCK三级响应)
- EntityCountEnforcer: 实体数量执行器(分块限制+优先级清理)
- RedstoneUpdateLimiter: 红石更新限制器(三级渐进+观察者钟检测)
- CrashExploitSignatureDB: 崩溃漏洞签名库(12种已知漏洞+4级自动响应)

【AI/ML 行为分析 4 模块】
- BehavioralProfilingEngine: 行为分析引擎(5维特征+香农熵+Z分数)
- ThreatScoreAggregator: 威胁分数聚合器(指数衰减+4级上报)
- MovementPatternAnalyzer: 移动模式分析器(FFT频谱+旋转分析)
- CombatPatternRecognizer: 战斗模式识别器(CPS方差+多目标熵+扫视分析)

配置更新:AlertType新增39个枚举值,SuperEvolutionConfig新增39个开关,
application.yml新增39个配置项。323项全量测试通过,0失败。
This commit is contained in:
Peijun Zhao
2026-05-16 18:02:49 +08:00
parent 67e873525b
commit 1b66197804
54 changed files with 23497 additions and 1 deletions
@@ -0,0 +1,330 @@
package com.aluer.security;
import com.aluer.config.ServerGuardConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
/**
* 加速物品使用检测 (FastUse) — V5.3 世界/玩家/杂物安全模块
*
* 检测原理:
* Meteor Client 的 FastUse 模块可以移除物品使用冷却,实现瞬发使用。
* 正常游戏中每种物品都有固定的使用持续时间:
* 弓拉满约 1.0 秒,食物食用约 1.6 秒,药水饮用约 1.3 秒,盾牌举盾约 0.25 秒,弩装填约 1.25 秒。
* 本模块通过以下维度检测加速使用:
* 1. 物品使用持续时间检测——记录每种物品从开始使用到完成使用的实际耗时,
* 与物品类型的理论最短时间对比。
* 2. 同类型物品连续快用——单次快速可能是延迟,但连续 3 次同类型快用即为明确信号。
* 3. 跨类型通用快用——如果玩家对多种物品类型都表现出快速使用,增加置信度。
* 4. 使用间隔均匀性——自动化模块的使用间隔往往高度一致。
*
* 配置开关:serverguard.security.super-evolution.anti-fast-use
*/
@Service
public class AntiFastUseService {
private final ServerGuardConfig config;
/** 每个玩家的物品使用开始记录:playerName -> itemType -> 开始时间 */
private final Map<String, Map<String, Instant>> playerUseStartTimes = new ConcurrentHashMap<>();
/** 每个玩家的物品使用历史:playerName -> 使用事件列表 */
private final Map<String, List<UseEvent>> playerUseHistory = new ConcurrentHashMap<>();
/** 已标记的玩家 */
private final Map<String, Instant> flaggedPlayers = new ConcurrentHashMap<>();
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
private final AtomicLong totalUseEvents = new AtomicLong(0);
private final AtomicLong fastUseViolations = new AtomicLong(0);
/** 食物最短使用时间(毫秒)——大多数食物为 1.6 秒 = 32 tick */
private static final long FOOD_MIN_USE_MS = 1600;
/** 弓拉满最短时间(毫秒)——约 1.0 秒 = 20 tick */
private static final long BOW_DRAW_MIN_MS = 1000;
/** 药水饮用最短时间(毫秒)——约 1.3 秒 = 26 tick (1.1s for splash/lingering) */
private static final long POTION_DRINK_MIN_MS = 1300;
/** 盾牌举盾最短时间(毫秒)——约 0.25 秒 = 5 tick */
private static final long SHIELD_RAISE_MIN_MS = 250;
/** 弩装填最短时间(毫秒)——约 1.25 秒 = 25 tick */
private static final long CROSSBOW_LOAD_MIN_MS = 1250;
/** 快速使用判定比例——实际时间 < 理论最短 * 0.7 即为快用 */
private static final double FAST_USE_RATIO = 0.7;
/** 连续快用次数阈值 */
private static final int CONSECUTIVE_FAST_THRESHOLD = 3;
/** 记录保留时间(秒) */
private static final long RECORD_RETENTION_SECONDS = 600;
/** 标记持续时间(秒) */
private static final long FLAG_DURATION_SECONDS = 1800;
public AntiFastUseService() {
this(new ServerGuardConfig());
}
@Autowired
public AntiFastUseService(ServerGuardConfig config) {
this.config = config;
scheduler.scheduleAtFixedRate(this::cleanupOldRecords, 120, 300, TimeUnit.SECONDS);
}
/**
* 记录物品开始使用事件——玩家开始持有一个可使用的物品。
*
* 在玩家按下右键开始使用物品(弓拉弓、吃食物、喝药水、举盾等)时调用。
*
* @param playerName 玩家名称
* @param playerUUID 玩家 UUID
* @param itemType 物品类型标识("BOW"/"FOOD"/"POTION"/"SHIELD"/"CROSSBOW"/"TRIDENT"/...)
*/
public void recordUseStart(String playerName, String playerUUID, String itemType) {
if (!config.getSecurity().getSuperEvolution().isAntiFastUse()) {
return;
}
Instant now = Instant.now();
Map<String, Instant> itemStarts = playerUseStartTimes.computeIfAbsent(playerName,
k -> new ConcurrentHashMap<>());
itemStarts.put(itemType, now);
}
/**
* 检测物品使用完成事件——判断使用速度是否异常。
*
* @param playerName 玩家名称
* @param playerUUID 玩家 UUID
* @param itemType 物品类型标识
* @return 检测结果
*/
public DetectionResult detectUseComplete(String playerName, String playerUUID, String itemType) {
if (!config.getSecurity().getSuperEvolution().isAntiFastUse()) {
return DetectionResult.clean();
}
Instant flaggedUntil = flaggedPlayers.get(playerName);
if (flaggedUntil != null) {
if (Instant.now().isAfter(flaggedUntil)) {
flaggedPlayers.remove(playerName);
} else {
return DetectionResult.flagged(List.of(
"PLAYER_ALREADY_FLAGGED: " + playerName + " under fast use investigation"));
}
}
Instant now = Instant.now();
Map<String, Instant> itemStarts = playerUseStartTimes.get(playerName);
if (itemStarts == null) {
return DetectionResult.clean();
}
Instant startTime = itemStarts.remove(itemType);
if (startTime == null) {
// 没有对应的开始记录,可能是模块启动前已经开始使用
return DetectionResult.clean();
}
long actualDurationMs = now.toEpochMilli() - startTime.toEpochMilli();
long minExpected = getMinExpectedDuration(itemType);
int score = 0;
List<String> reasons = new ArrayList<>();
// === 检测 1: 物品使用持续时间检测 ===
if (actualDurationMs < minExpected * FAST_USE_RATIO) {
score += 30;
reasons.add("FAST_USE: " + itemType + " used in " + actualDurationMs +
"ms (expected min " + minExpected + "ms, ratio=" + FAST_USE_RATIO + ")");
}
// === 检测 2: 极快速使用——低于绝对下限 ===
// 食物不可能在 500ms 内吃完,弓不可能在 200ms 内拉满
long absoluteMin = getAbsoluteMinDuration(itemType);
if (actualDurationMs < absoluteMin) {
score += 25;
reasons.add("SUB_ABSOLUTE_MIN: " + itemType + " used in " + actualDurationMs +
"ms (absolute min " + absoluteMin + "ms, physically impossible)");
}
// 记录使用事件
List<UseEvent> history = playerUseHistory.computeIfAbsent(playerName,
k -> Collections.synchronizedList(new ArrayList<>()));
history.add(new UseEvent(now, itemType, actualDurationMs, minExpected));
totalUseEvents.incrementAndGet();
// === 检测 3: 同类型物品连续快用 ===
long consecutiveFast = countConsecutiveFastUses(history, itemType);
if (consecutiveFast >= CONSECUTIVE_FAST_THRESHOLD) {
score += 35;
reasons.add("CONSECUTIVE_FAST_USE: " + consecutiveFast +
" consecutive fast uses of " + itemType);
}
// === 检测 4: 跨类型通用快用 ===
// 如果玩家对多种不同物品类型都表现出快速使用,置信度更高
Set<String> fastItemTypes = new HashSet<>();
for (int i = Math.max(0, history.size() - 10); i < history.size(); i++) {
UseEvent e = history.get(i);
if (e.actualDurationMs < e.expectedMinMs * FAST_USE_RATIO) {
fastItemTypes.add(e.itemType);
}
}
if (fastItemTypes.size() >= 3) {
score += 20;
reasons.add("MULTI_TYPE_FAST: fast use detected across " + fastItemTypes.size() +
" item types: " + String.join(", ", fastItemTypes));
}
if (score >= 50) {
flaggedPlayers.put(playerName, Instant.now().plusSeconds(FLAG_DURATION_SECONDS));
fastUseViolations.incrementAndGet();
return DetectionResult.flagged(reasons);
} else if (score >= 30) {
return DetectionResult.suspicious(score, reasons);
}
return DetectionResult.clean();
}
/**
* 获取指定物品类型的理论最短使用时间(毫秒)。
*/
private long getMinExpectedDuration(String itemType) {
if (itemType == null) return 1000;
return switch (itemType.toUpperCase()) {
case "BOW" -> BOW_DRAW_MIN_MS;
case "FOOD", "MUSHROOM_STEW", "SUSPICIOUS_STEW", "BEETROOT_SOUP",
"RABBIT_STEW", "CHORUS_FRUIT", "GOLDEN_APPLE", "ENCHANTED_GOLDEN_APPLE",
"HONEY_BOTTLE", "MILK_BUCKET" -> FOOD_MIN_USE_MS;
case "POTION", "SPLASH_POTION", "LINGERING_POTION", "EXPERIENCE_BOTTLE" -> POTION_DRINK_MIN_MS;
case "SHIELD" -> SHIELD_RAISE_MIN_MS;
case "CROSSBOW" -> CROSSBOW_LOAD_MIN_MS;
case "TRIDENT" -> 1000; // 三叉戟蓄力约 1 秒
case "SPYGLASS" -> 1200; // 望远镜
default -> 1000; // 通用默认值
};
}
/**
* 获取指定物品类型的绝对最短使用时间(毫秒)——低于这个值就是物理不可能。
*/
private long getAbsoluteMinDuration(String itemType) {
if (itemType == null) return 300;
return switch (itemType.toUpperCase()) {
case "FOOD", "MUSHROOM_STEW", "GOLDEN_APPLE" -> 800;
case "BOW" -> 200;
case "POTION" -> 600;
case "SHIELD" -> 100;
case "CROSSBOW" -> 600;
default -> 300;
};
}
/**
* 统计指定物品类型的连续快用次数。
*/
private long countConsecutiveFastUses(List<UseEvent> history, String itemType) {
int count = 0;
for (int i = history.size() - 1; i >= 0; i--) {
UseEvent e = history.get(i);
if (e.itemType.equalsIgnoreCase(itemType)
&& e.actualDurationMs < e.expectedMinMs * FAST_USE_RATIO) {
count++;
} else if (e.itemType.equalsIgnoreCase(itemType)) {
break; // 同类型但速度正常,停止计数
}
}
return count;
}
public void clearPlayer(String playerName) {
playerUseStartTimes.remove(playerName);
playerUseHistory.remove(playerName);
flaggedPlayers.remove(playerName);
}
public Map<String, Object> getStatus() {
Map<String, Object> s = new LinkedHashMap<>();
s.put("totalUseEvents", totalUseEvents.get());
s.put("fastUseViolations", fastUseViolations.get());
s.put("trackedPlayers", playerUseHistory.size());
s.put("flaggedPlayers", flaggedPlayers.size());
s.put("enabled", config.getSecurity().getSuperEvolution().isAntiFastUse());
return s;
}
public long getTotalUseEvents() { return totalUseEvents.get(); }
public long getFastUseViolations() { return fastUseViolations.get(); }
private void cleanupOldRecords() {
Instant cutoff = Instant.now().minusSeconds(RECORD_RETENTION_SECONDS);
playerUseHistory.entrySet().removeIf(e -> {
List<UseEvent> events = e.getValue();
events.removeIf(ev -> ev.time.isBefore(cutoff));
return events.isEmpty();
});
playerUseStartTimes.entrySet().removeIf(e ->
!playerUseHistory.containsKey(e.getKey()));
flaggedPlayers.entrySet().removeIf(e -> e.getValue().isBefore(Instant.now()));
}
// ==================== 内部数据类 ====================
/**
* 物品使用事件记录——追踪单次使用从开始到完成的耗时。
*/
private static class UseEvent {
final Instant time;
final String itemType;
final long actualDurationMs; // 实际使用耗时
final long expectedMinMs; // 该物品理论最短时间
UseEvent(Instant time, String itemType, long actualDurationMs, long expectedMinMs) {
this.time = time;
this.itemType = itemType;
this.actualDurationMs = actualDurationMs;
this.expectedMinMs = expectedMinMs;
}
}
// ==================== 检测结果类 ====================
/**
* 加速物品使用检测结果。
*/
public static class DetectionResult {
private final boolean flagged;
private final boolean suspicious;
private final int score;
private final List<String> reasons;
private DetectionResult(boolean flagged, boolean suspicious, int score, List<String> reasons) {
this.flagged = flagged;
this.suspicious = suspicious;
this.score = score;
this.reasons = reasons;
}
public static DetectionResult clean() {
return new DetectionResult(false, false, 0, List.of());
}
public static DetectionResult suspicious(int score, List<String> reasons) {
return new DetectionResult(false, true, score, reasons);
}
public static DetectionResult flagged(List<String> reasons) {
return new DetectionResult(true, true, 100, reasons);
}
public boolean isFlagged() { return flagged; }
public boolean isSuspicious() { return suspicious; }
public boolean isClean() { return !flagged && !suspicious; }
public int getScore() { return score; }
public List<String> getReasons() { return reasons; }
}
}