Files
Aluer/src/main/java/com/aluer/security/ForensicsCollectorService.java
T
Peijun Zhao f7c590e34e feat: super evolution — 20 new security modules with full test coverage
新增20个超进化安全模块 (17 new services + 1 test suite + Dashboard API):
- JWT认证服务 (JwtAuthService): 基于HMAC-SHA256的token管理
- 反暴力破解 (BruteForceProtectionService): 渐进延迟+三层时间窗口检测
- 反机器人检测 (AntiBotDetectionService): MC玩家名模式+加入速度+多账号检测
- 反向Shell检测 (ReverseShellDetectionService): 50+ reverse shell模式匹配
- ARP欺骗检测 (ARPSpoofDetectionService): MAC变更+网关欺骗+重复MAC检测
- DNS隧道检测 (DNSTunnelDetectionService): 熵值分析+子域名编码+频率监控
- 漏洞签名检测 (ExploitSignatureService): Log4Shell/SQL注入/XSS等15+签名
- SSRF防护 (SSRFProtectionService): 内网IP/云元数据/编码绕过检测
- XXE防护 (XXEProtectionService): XML实体注入+十亿笑攻击检测
- CSP强制执行 (CSPEnforcementService): XSS/Clickjack防御+安全响应头
- 数据库防火墙 (DatabaseFirewallService): SQL注入+危险关键字+堆叠查询检测
- 数据防泄漏 (DataLossPreventionService): 12种敏感数据模式(邮箱/API Key/SSH Key等)
- 内存保护 (MemoryProtectionService): JVM堆监控+GC过载+内存泄漏检测
- 进程注入检测 (ProcessInjectionDetectionService): 线程异常+内存映射+文件描述符
- 安全文件删除 (SecureFileDeletionService): DoD多pass覆写+擦除后删除
- 取证收集器 (ForensicsCollectorService): 进程/网络/文件/日志取证
- 事件响应 (IncidentResponseService): 5套Playbook(DDOS/爆破/入侵/MC漏洞/数据泄露)
- 威胁狩猎 (ThreatHuntingService): 10种主动狩猎规则
- 合规扫描 (ComplianceScannerService): 7大类20+项合规检查
- 反破坏检测 (AntiGriefDetectionService): MC方块破坏/放置/实体/容器监控

API端点: DashboardController新增20+个安全API端点
测试: 64个测试全部通过 (12 existing + 52 new)
2026-05-10 20:36:04 +08:00

228 lines
9.4 KiB
Java

package com.aluer.security;
import org.springframework.stereotype.Service;
import java.io.*;
import java.nio.file.*;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
@Service
public class ForensicsCollectorService {
private final Map<String, ForensicsCase> cases = new ConcurrentHashMap<>();
private final Map<String, List<ForensicEvidence>> evidenceStore = new ConcurrentHashMap<>();
private final AtomicLong totalEvidenceCollected = new AtomicLong(0);
private final String evidenceDir = "./forensics";
public ForensicsCollectorService() {
try {
Files.createDirectories(Path.of(evidenceDir));
} catch (IOException ignored) {}
}
public ForensicsCase openCase(String caseName, String reason, String operator) {
String caseId = "CASE-" + Instant.now().getEpochSecond() + "-" + randomHex(6);
ForensicsCase fCase = new ForensicsCase(caseId, caseName, reason, operator, Instant.now());
cases.put(caseId, fCase);
evidenceStore.put(caseId, new ArrayList<>());
return fCase;
}
public ForensicEvidence collectProcessList(String caseId) {
StringBuilder sb = new StringBuilder();
try {
Process proc = Runtime.getRuntime().exec(new String[]{"sh", "-c", "ps aux"});
try (BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
sb.append(line).append('\n');
}
}
} catch (Exception e) {
sb.append("ERROR: ").append(e.getMessage());
}
return addEvidence(caseId, "PROCESS_LIST", sb.toString());
}
public ForensicEvidence collectNetworkConnections(String caseId) {
StringBuilder sb = new StringBuilder();
try {
Process proc = Runtime.getRuntime().exec(new String[]{"sh", "-c", "ss -tunap 2>/dev/null || netstat -tunap 2>/dev/null"});
try (BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
sb.append(line).append('\n');
}
}
} catch (Exception e) {
sb.append("ERROR: ").append(e.getMessage());
}
return addEvidence(caseId, "NETWORK_CONNECTIONS", sb.toString());
}
public ForensicEvidence collectOpenFiles(String caseId) {
StringBuilder sb = new StringBuilder();
try {
Process proc = Runtime.getRuntime().exec(new String[]{"sh", "-c", "lsof -nP 2>/dev/null | head -500"});
try (BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
sb.append(line).append('\n');
}
}
} catch (Exception e) {
sb.append("ERROR: ").append(e.getMessage());
}
return addEvidence(caseId, "OPEN_FILES", sb.toString());
}
public ForensicEvidence collectSystemLogs(String caseId) {
StringBuilder sb = new StringBuilder();
try {
Process proc = Runtime.getRuntime().exec(new String[]{"sh", "-c", "journalctl -n 200 --no-pager 2>/dev/null || dmesg | tail -200"});
try (BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
sb.append(line).append('\n');
}
}
} catch (Exception e) {
sb.append("ERROR: ").append(e.getMessage());
}
return addEvidence(caseId, "SYSTEM_LOGS", sb.toString());
}
public ForensicEvidence collectMCPServerLogs(String caseId, String mcLogPath) {
if (mcLogPath == null) mcLogPath = "/opt/minecraft/logs/latest.log";
try {
String content = Files.readString(Path.of(mcLogPath));
return addEvidence(caseId, "MC_SERVER_LOG", content);
} catch (Exception e) {
return addEvidence(caseId, "MC_SERVER_LOG", "ERROR: " + e.getMessage());
}
}
public ForensicEvidence collectTimestampSnapshot(String caseId) {
Map<String, Object> snapshot = new LinkedHashMap<>();
snapshot.put("systemTime", Instant.now().toString());
snapshot.put("uptime", System.getProperty("os.name"));
snapshot.put("javaVersion", System.getProperty("java.version"));
snapshot.put("availableProcessors", Runtime.getRuntime().availableProcessors());
snapshot.put("freeMemory", Runtime.getRuntime().freeMemory());
snapshot.put("totalMemory", Runtime.getRuntime().totalMemory());
return addEvidence(caseId, "TIMESTAMP_SNAPSHOT", snapshot.toString());
}
public ForensicsCase closeCase(String caseId, String conclusion, String operator) {
ForensicsCase fCase = cases.get(caseId);
if (fCase != null) {
fCase.close(conclusion, operator);
saveCaseToDisk(fCase);
}
return fCase;
}
public Map<String, Object> getStatus() {
Map<String, Object> status = new LinkedHashMap<>();
status.put("openCases", cases.values().stream().filter(c -> !c.closed).count());
status.put("totalCases", cases.size());
status.put("totalEvidence", totalEvidenceCollected.get());
List<Map<String, Object>> caseList = new ArrayList<>();
for (ForensicsCase c : cases.values()) {
Map<String, Object> m = new LinkedHashMap<>();
m.put("id", c.caseId);
m.put("name", c.caseName);
m.put("reason", c.reason);
m.put("openTime", c.openTime.toString());
m.put("closed", c.closed);
m.put("evidenceCount", evidenceStore.getOrDefault(c.caseId, List.of()).size());
caseList.add(m);
}
caseList.sort((a, b) -> b.get("openTime").toString().compareTo(a.get("openTime").toString()));
status.put("cases", caseList);
return status;
}
public long getTotalEvidence() { return totalEvidenceCollected.get(); }
private ForensicEvidence addEvidence(String caseId, String type, String content) {
ForensicEvidence evidence = new ForensicEvidence(caseId, type, content, Instant.now());
evidenceStore.computeIfAbsent(caseId, k -> new ArrayList<>()).add(evidence);
totalEvidenceCollected.incrementAndGet();
return evidence;
}
private void saveCaseToDisk(ForensicsCase fCase) {
try {
Path caseDir = Path.of(evidenceDir, fCase.caseId);
Files.createDirectories(caseDir);
StringBuilder report = new StringBuilder();
report.append("=== FORENSICS CASE REPORT ===\n");
report.append("Case ID: ").append(fCase.caseId).append('\n');
report.append("Name: ").append(fCase.caseName).append('\n');
report.append("Reason: ").append(fCase.reason).append('\n');
report.append("Operator: ").append(fCase.operator).append('\n');
report.append("Opened: ").append(fCase.openTime).append('\n');
report.append("Closed: ").append(fCase.closeTime).append('\n');
report.append("Conclusion: ").append(fCase.conclusion).append('\n');
report.append("\n--- EVIDENCE ---\n\n");
List<ForensicEvidence> items = evidenceStore.getOrDefault(fCase.caseId, List.of());
for (ForensicEvidence e : items) {
report.append("[").append(e.type).append("] ").append(e.timestamp).append('\n');
report.append(e.content).append("\n---\n\n");
}
Files.writeString(caseDir.resolve("report.txt"), report.toString());
} catch (IOException ignored) {}
}
private String randomHex(int len) {
byte[] bytes = new byte[len];
new Random().nextBytes(bytes);
StringBuilder sb = new StringBuilder();
for (byte b : bytes) sb.append(String.format("%02x", b));
return sb.toString().substring(0, len);
}
public static class ForensicsCase {
public final String caseId;
public final String caseName;
public final String reason;
public final String operator;
public final Instant openTime;
public Instant closeTime;
public String conclusion;
public boolean closed;
ForensicsCase(String caseId, String caseName, String reason, String operator, Instant openTime) {
this.caseId = caseId;
this.caseName = caseName;
this.reason = reason;
this.operator = operator;
this.openTime = openTime;
}
void close(String conclusion, String operator) {
this.conclusion = conclusion;
this.closeTime = Instant.now();
this.closed = true;
}
}
public static class ForensicEvidence {
public final String caseId;
public final String type;
public final String content;
public final Instant timestamp;
ForensicEvidence(String caseId, String type, String content, Instant timestamp) {
this.caseId = caseId;
this.type = type;
this.content = content;
this.timestamp = timestamp;
}
}
}