提交Git

This commit is contained in:
Peijun Zhao
2026-05-10 12:59:00 +08:00
commit b0aaea9fb3
2544 changed files with 545276 additions and 0 deletions
@@ -0,0 +1,316 @@
package com.aluer.security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicLong;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Component
public class APIRateLimitService {
private static final Logger logger = LoggerFactory.getLogger(APIRateLimitService.class);
private final Map<String, RateLimitRule> rules = new ConcurrentHashMap<>();
private final Map<String, ClientRateLimit> clientLimits = new ConcurrentHashMap<>();
private final Queue<RateLimitEvent> eventLog = new ConcurrentLinkedQueue<>();
private final AtomicLong totalRequests = new AtomicLong(0);
private final AtomicLong limitedRequests = new AtomicLong(0);
private final AtomicLong blockedRequests = new AtomicLong(0);
private static final int DEFAULT_LIMIT_PER_MINUTE = 60;
private static final int DEFAULT_LIMIT_PER_HOUR = 1000;
private static final int DEFAULT_LIMIT_PER_DAY = 10000;
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public APIRateLimitService() {
initializeDefaultRules();
logger.info("API Rate Limit Service initialized");
}
private void initializeDefaultRules() {
addRule("default", DEFAULT_LIMIT_PER_MINUTE, DEFAULT_LIMIT_PER_HOUR, DEFAULT_LIMIT_PER_DAY);
addRule("login", 10, 50, 100);
addRule("register", 5, 20, 50);
addRule("message", 30, 200, 500);
addRule("file-upload", 10, 50, 100);
addRule("api-critical", 100, 500, 2000);
logger.info("Initialized {} rate limit rules", rules.size());
}
public void addRule(String name, int limitPerMinute, int limitPerHour, int limitPerDay) {
RateLimitRule rule = new RateLimitRule(name, limitPerMinute, limitPerHour, limitPerDay);
rules.put(name, rule);
}
public RateLimitResult checkRateLimit(String clientId, String endpoint) {
RateLimitResult result = new RateLimitResult();
result.setClientId(clientId);
result.setEndpoint(endpoint);
result.setTimestamp(LocalDateTime.now());
totalRequests.incrementAndGet();
ClientRateLimit clientLimit = clientLimits.computeIfAbsent(clientId, k -> new ClientRateLimit(clientId));
RateLimitRule rule = rules.getOrDefault(endpoint, rules.get("default"));
if (clientLimit.isPermanentlyBlocked()) {
result.setAllowed(false);
result.setReason("Client is permanently blocked");
result.setBlocked(true);
blockedRequests.incrementAndGet();
logEvent(clientId, endpoint, "BLOCKED", "Permanently blocked");
return result;
}
if (!clientLimit.checkLimit(rule)) {
result.setAllowed(false);
result.setReason("Rate limit exceeded");
result.setLimited(true);
limitedRequests.incrementAndGet();
clientLimit.incrementViolationCount();
if (clientLimit.getViolationCount() >= 10) {
clientLimit.setPermanentlyBlocked(true);
blockedRequests.incrementAndGet();
logEvent(clientId, endpoint, "PERMANENT_BLOCK", "Too many violations");
} else {
logEvent(clientId, endpoint, "LIMITED", "Rate limit exceeded");
}
return result;
}
clientLimit.recordRequest();
result.setAllowed(true);
result.setRemainingMinute(clientLimit.getRemainingRequests("minute"));
result.setRemainingHour(clientLimit.getRemainingRequests("hour"));
result.setRemainingDay(clientLimit.getRemainingRequests("day"));
logEvent(clientId, endpoint, "ALLOWED", "Request allowed");
return result;
}
public void unblockClient(String clientId) {
ClientRateLimit clientLimit = clientLimits.get(clientId);
if (clientLimit != null) {
clientLimit.reset();
logger.info("Client {} has been unblocked", clientId);
}
}
public void setClientLimit(String clientId, int minuteLimit, int hourLimit, int dayLimit) {
ClientRateLimit clientLimit = clientLimits.computeIfAbsent(clientId, k -> new ClientRateLimit(clientId));
clientLimit.setCustomLimits(minuteLimit, hourLimit, dayLimit);
}
public Map<String, Object> getStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("totalRequests", totalRequests.get());
stats.put("limitedRequests", limitedRequests.get());
stats.put("blockedRequests", blockedRequests.get());
stats.put("activeClients", clientLimits.size());
stats.put("rulesConfigured", rules.size());
return stats;
}
public Map<String, ClientRateLimit> getClients() {
return new HashMap<>(clientLimits);
}
public List<RateLimitEvent> getRecentEvents(int limit) {
List<RateLimitEvent> events = new ArrayList<>();
int count = 0;
for (RateLimitEvent event : eventLog) {
if (count++ >= limit) break;
events.add(event);
}
return events;
}
private void logEvent(String clientId, String endpoint, String action, String details) {
RateLimitEvent event = new RateLimitEvent(clientId, endpoint, action, details, LocalDateTime.now());
eventLog.offer(event);
if (eventLog.size() > 5000) {
eventLog.poll();
}
}
public static class RateLimitRule {
private final String name;
private final int limitPerMinute;
private final int limitPerHour;
private final int limitPerDay;
public RateLimitRule(String name, int limitPerMinute, int limitPerHour, int limitPerDay) {
this.name = name;
this.limitPerMinute = limitPerMinute;
this.limitPerHour = limitPerHour;
this.limitPerDay = limitPerDay;
}
public String getName() { return name; }
public int getLimitPerMinute() { return limitPerMinute; }
public int getLimitPerHour() { return limitPerHour; }
public int getLimitPerDay() { return limitPerDay; }
}
public static class ClientRateLimit {
private final String clientId;
private volatile int requestsThisMinute = 0;
private volatile int requestsThisHour = 0;
private volatile int requestsThisDay = 0;
private volatile long minuteStartTime;
private volatile long hourStartTime;
private volatile long dayStartTime;
private volatile int violationCount = 0;
private volatile boolean permanentlyBlocked = false;
private Integer customMinuteLimit;
private Integer customHourLimit;
private Integer customDayLimit;
public ClientRateLimit(String clientId) {
this.clientId = clientId;
this.minuteStartTime = System.currentTimeMillis();
this.hourStartTime = System.currentTimeMillis();
this.dayStartTime = System.currentTimeMillis();
}
public synchronized boolean checkLimit(RateLimitRule rule) {
resetIfNeeded();
int minuteLimit = customMinuteLimit != null ? customMinuteLimit : rule.getLimitPerMinute();
int hourLimit = customHourLimit != null ? customHourLimit : rule.getLimitPerHour();
int dayLimit = customDayLimit != null ? customDayLimit : rule.getLimitPerDay();
return requestsThisMinute < minuteLimit &&
requestsThisHour < hourLimit &&
requestsThisDay < dayLimit;
}
public synchronized void recordRequest() {
resetIfNeeded();
requestsThisMinute++;
requestsThisHour++;
requestsThisDay++;
}
private void resetIfNeeded() {
long now = System.currentTimeMillis();
if (now - minuteStartTime > 60000) {
requestsThisMinute = 0;
minuteStartTime = now;
}
if (now - hourStartTime > 3600000) {
requestsThisHour = 0;
hourStartTime = now;
}
if (now - dayStartTime > 86400000) {
requestsThisDay = 0;
dayStartTime = now;
}
}
public int getRemainingRequests(String timeframe) {
resetIfNeeded();
RateLimitRule rule = new RateLimitRule("default", 60, 1000, 10000);
int minuteLimit = customMinuteLimit != null ? customMinuteLimit : rule.getLimitPerMinute();
int hourLimit = customHourLimit != null ? customHourLimit : rule.getLimitPerHour();
int dayLimit = customDayLimit != null ? customDayLimit : rule.getLimitPerDay();
switch (timeframe) {
case "minute": return Math.max(0, minuteLimit - requestsThisMinute);
case "hour": return Math.max(0, hourLimit - requestsThisHour);
case "day": return Math.max(0, dayLimit - requestsThisDay);
default: return 0;
}
}
public void incrementViolationCount() { violationCount++; }
public void reset() {
violationCount = 0;
permanentlyBlocked = false;
requestsThisMinute = 0;
requestsThisHour = 0;
requestsThisDay = 0;
}
public void setCustomLimits(int minute, int hour, int day) {
this.customMinuteLimit = minute;
this.customHourLimit = hour;
this.customDayLimit = day;
}
public String getClientId() { return clientId; }
public int getViolationCount() { return violationCount; }
public boolean isPermanentlyBlocked() { return permanentlyBlocked; }
public void setPermanentlyBlocked(boolean blocked) { this.permanentlyBlocked = blocked; }
}
public static class RateLimitResult {
private String clientId;
private String endpoint;
private boolean allowed;
private boolean limited;
private boolean blocked;
private String reason;
private int remainingMinute;
private int remainingHour;
private int remainingDay;
private LocalDateTime timestamp;
public String getClientId() { return clientId; }
public void setClientId(String clientId) { this.clientId = clientId; }
public String getEndpoint() { return endpoint; }
public void setEndpoint(String endpoint) { this.endpoint = endpoint; }
public boolean isAllowed() { return allowed; }
public void setAllowed(boolean allowed) { this.allowed = allowed; }
public boolean isLimited() { return limited; }
public void setLimited(boolean limited) { this.limited = limited; }
public boolean isBlocked() { return blocked; }
public void setBlocked(boolean blocked) { this.blocked = blocked; }
public String getReason() { return reason; }
public void setReason(String reason) { this.reason = reason; }
public int getRemainingMinute() { return remainingMinute; }
public void setRemainingMinute(int remaining) { this.remainingMinute = remaining; }
public int getRemainingHour() { return remainingHour; }
public void setRemainingHour(int remaining) { this.remainingHour = remaining; }
public int getRemainingDay() { return remainingDay; }
public void setRemainingDay(int remaining) { this.remainingDay = remaining; }
public LocalDateTime getTimestamp() { return timestamp; }
public void setTimestamp(LocalDateTime timestamp) { this.timestamp = timestamp; }
}
public static class RateLimitEvent {
private final String clientId;
private final String endpoint;
private final String action;
private final String details;
private final LocalDateTime timestamp;
public RateLimitEvent(String clientId, String endpoint, String action, String details, LocalDateTime timestamp) {
this.clientId = clientId;
this.endpoint = endpoint;
this.action = action;
this.details = details;
this.timestamp = timestamp;
}
public String getClientId() { return clientId; }
public String getEndpoint() { return endpoint; }
public String getAction() { return action; }
public String getDetails() { return details; }
public LocalDateTime getTimestamp() { return timestamp; }
}
}
@@ -0,0 +1,438 @@
package com.aluer.security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicLong;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
@Component
public class AdvancedMalwareDetectionService {
private static final Logger logger = LoggerFactory.getLogger(AdvancedMalwareDetectionService.class);
private final Map<String, MalwareSignature> signatures = new ConcurrentHashMap<>();
private final Map<String, BehavioralProfile> behavioralProfiles = new ConcurrentHashMap<>();
private final Queue<MalwareAlert> alertQueue = new ConcurrentLinkedQueue<>();
private final Map<String, List<HeuristicResult>> scanHistory = new ConcurrentHashMap<>();
private final AtomicLong totalScans = new AtomicLong(0);
private final AtomicLong threatsDetected = new AtomicLong(0);
private static final int MAX_SCAN_HISTORY = 1000;
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public AdvancedMalwareDetectionService() {
initializeSignatures();
logger.info("Advanced Malware Detection Service initialized");
}
private void initializeSignatures() {
addSignature("WIN32_TROJAN_GENERIC", "Trojan.Generic", "HIGH", "eicar_test_file", "Known trojan signature");
addSignature("WIN32_WORM_CONFICKER", "Worm.Conficker", "CRITICAL", "conficker_.*", "Conficker worm");
addSignature("WIN32_RANSOMWARE_CRYPTO", "Ransomware.CryptoLocker", "CRITICAL", "crypto_locker", "CryptoLocker ransomware");
addSignature("WIN32_BACKDOOR_TITAN", "Backdoor.Titan", "HIGH", "titan_.*", "Titan backdoor");
addSignature("WIN64_ROOTKIT_FLYPRO", "Rootkit.FlyPro", "HIGH", "flypro_.*", "FlyPro rootkit");
addSignature("WIN32_ADWARE_YOUNEE", "Adware.YooNear", "LOW", "yoonee_.*", "Adware component");
addSignature("WIN32_KEYLOGGER_SPYWARE", "Keylogger.SpyWare", "HIGH", "keylog.*", "Keylogger detection");
addSignature("WIN32_BOTNET_ZOMBIE", "Botnet.Zombie", "HIGH", "zombie_.*", "Botnet zombie");
addSignature("WIN32_MINER_COIN", "Miner.CoinHive", "MEDIUM", "coinhive.*", "Cryptocurrency miner");
addSignature("WIN32_EXPLOIT_KIT", "ExploitKit.EK", "HIGH", "exploit_.*", "Exploit kit");
addSignature("LINUX_MALWARE_MIRAI", "Linux.Mirai", "CRITICAL", "mirai_.*", "Mirai botnet");
addSignature("LINUX_ROOTKIT_DIAMONDER", "Linux.Rootkit.Diamond", "HIGH", "diamond_.*", "Diamond rootkit");
addSignature("LINUX_MINER_LINUX", "Linux.Miner.Xmrig", "MEDIUM", "xmrig.*", "XMRig miner");
addSignature("LINUX_BACKDOOR_BEAST", "Linux.Backdoor.Beast", "HIGH", "beast_.*", "Beast backdoor");
logger.info("Initialized {} malware signatures", signatures.size());
}
public void addSignature(String id, String name, String severity, String pattern, String description) {
MalwareSignature sig = new MalwareSignature(id, name, severity, pattern, description);
signatures.put(id, sig);
}
public ScanResult scanFile(String fileName, byte[] fileContent, String fileHash) {
ScanResult result = new ScanResult();
result.setFileName(fileName);
result.setFileHash(fileHash);
result.setTimestamp(LocalDateTime.now());
totalScans.incrementAndGet();
MalwareSignature matchedSig = matchSignature(fileHash, fileName);
if (matchedSig != null) {
result.setThreatDetected(true);
result.setThreatName(matchedSig.getName());
result.setThreatSeverity(matchedSig.getSeverity());
result.setThreatDescription(matchedSig.getDescription());
threatsDetected.incrementAndGet();
triggerAlert(fileName, matchedSig);
logger.warn("MALWARE DETECTED: {} in file {}", matchedSig.getName(), fileName);
return result;
}
List<HeuristicResult> heuristics = runHeuristicAnalysis(fileContent, fileName);
for (HeuristicResult hr : heuristics) {
if (hr.isSuspicious()) {
result.addHeuristicResult(hr);
result.setThreatDetected(true);
result.setThreatName("Heuristic Detection");
result.setThreatSeverity("MEDIUM");
threatsDetected.incrementAndGet();
}
}
List<HeuristicResult> history = scanHistory.computeIfAbsent(fileHash, k -> new ArrayList<>());
history.addAll(heuristics);
if (history.size() > MAX_SCAN_HISTORY) {
history.subList(0, history.size() - MAX_SCAN_HISTORY).clear();
}
return result;
}
private MalwareSignature matchSignature(String fileHash, String fileName) {
for (MalwareSignature sig : signatures.values()) {
try {
Pattern pattern = Pattern.compile(sig.getPattern(), Pattern.CASE_INSENSITIVE);
if (pattern.matcher(fileHash).matches() || pattern.matcher(fileName).matches()) {
return sig;
}
} catch (Exception e) {
}
}
return null;
}
private List<HeuristicResult> runHeuristicAnalysis(byte[] content, String fileName) {
List<HeuristicResult> results = new ArrayList<>();
if (content == null || content.length == 0) {
return results;
}
HeuristicResult entropyResult = analyzeEntropy(content);
if (entropyResult != null) {
results.add(entropyResult);
}
HeuristicResult packingResult = analyzePacking(content);
if (packingResult != null) {
results.add(packingResult);
}
HeuristicResult suspiciousStringsResult = analyzeSuspiciousStrings(content);
if (suspiciousStringsResult != null) {
results.add(suspiciousStringsResult);
}
HeuristicResult suspiciousPatternsResult = analyzeSuspiciousPatterns(content);
if (suspiciousPatternsResult != null) {
results.add(suspiciousPatternsResult);
}
return results;
}
private HeuristicResult analyzeEntropy(byte[] content) {
double entropy = calculateEntropy(content);
HeuristicResult result = new HeuristicResult();
result.setType("ENTROPY");
result.setScore((int)(entropy * 100));
if (entropy > 7.5) {
result.setSuspicious(true);
result.setReason("Very high entropy: " + String.format("%.2f", entropy) + " (possible encryption or packing)");
} else if (entropy > 6.5) {
result.setSuspicious(true);
result.setReason("High entropy: " + String.format("%.2f", entropy) + " (possible obfuscation)");
}
return result;
}
private double calculateEntropy(byte[] data) {
if (data == null || data.length == 0) return 0;
int[] frequency = new int[256];
for (byte b : data) {
frequency[b & 0xFF]++;
}
double entropy = 0;
int length = data.length;
for (int count : frequency) {
if (count > 0) {
double probability = (double) count / length;
entropy -= probability * (Math.log(probability) / Math.log(2));
}
}
return entropy;
}
private HeuristicResult analyzePacking(byte[] content) {
HeuristicResult result = new HeuristicResult();
result.setType("PACKING");
int nullBytes = 0;
int nonAscii = 0;
for (int i = 0; i < Math.min(content.length, 10000); i++) {
if (content[i] == 0) nullBytes++;
if ((content[i] & 0xFF) > 127) nonAscii++;
}
double nullRatio = (double) nullBytes / content.length;
double nonAsciiRatio = (double) nonAscii / content.length;
if (nullRatio > 0.3 && nullRatio < 0.7) {
result.setSuspicious(true);
result.setScore(70);
result.setReason("Suspicious null byte ratio: " + String.format("%.2f", nullRatio * 100) + "%");
} else if (nonAsciiRatio > 0.3) {
result.setSuspicious(true);
result.setScore(60);
result.setReason("High ratio of non-ASCII bytes: " + String.format("%.2f", nonAsciiRatio * 100) + "%");
}
return result;
}
private HeuristicResult analyzeSuspiciousStrings(byte[] content) {
String[] suspiciousPatterns = {
"http://", "https://", "ftp://",
"cmd.exe", "powershell", "bash", "/bin/sh",
"reg add", "reg delete", "regedit",
"CreateRemoteThread", "VirtualAlloc", "WriteProcessMemory",
"LoadLibrary", "GetProcAddress", "WinExec",
"http.request", "http.response",
"eval(", "exec(", "system(",
"base64_decode", "gzinflate", "str_rot13"
};
HeuristicResult result = new HeuristicResult();
result.setType("SUSPICIOUS_STRINGS");
int matchCount = 0;
String contentStr = new String(content);
for (String pattern : suspiciousPatterns) {
if (contentStr.toLowerCase().contains(pattern.toLowerCase())) {
matchCount++;
}
}
if (matchCount > 5) {
result.setSuspicious(true);
result.setScore(Math.min(100, matchCount * 10));
result.setReason("Found " + matchCount + " suspicious string patterns");
}
return result;
}
private HeuristicResult analyzeSuspiciousPatterns(byte[] content) {
HeuristicResult result = new HeuristicResult();
result.setType("SUSPICIOUS_PATTERNS");
int score = 0;
if (content.length > 1024 * 1024) {
score += 30;
}
int consecutiveRepeating = 0;
for (int i = 1; i < Math.min(content.length, 10000); i++) {
if (content[i] == content[i-1]) {
consecutiveRepeating++;
} else {
consecutiveRepeating = 0;
}
if (consecutiveRepeating > 100) {
score += 20;
break;
}
}
if (score > 0) {
result.setSuspicious(true);
result.setScore(score);
result.setReason("Suspicious binary patterns detected");
}
return result;
}
public void updateBehavioralProfile(String identifier, String behavior, int severity) {
BehavioralProfile profile = behavioralProfiles.computeIfAbsent(identifier, k -> new BehavioralProfile(identifier));
profile.addBehavior(behavior, severity);
}
private void triggerAlert(String fileName, MalwareSignature signature) {
MalwareAlert alert = new MalwareAlert(
fileName,
signature.getName(),
signature.getSeverity(),
signature.getDescription(),
LocalDateTime.now()
);
alertQueue.offer(alert);
if (alertQueue.size() > 1000) {
alertQueue.poll();
}
}
public Map<String, Object> getStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("totalScans", totalScans.get());
stats.put("threatsDetected", threatsDetected.get());
stats.put("signaturesLoaded", signatures.size());
stats.put("activeProfiles", behavioralProfiles.size());
stats.put("alertQueueSize", alertQueue.size());
long critical = signatures.values().stream().filter(s -> "CRITICAL".equals(s.getSeverity())).count();
long high = signatures.values().stream().filter(s -> "HIGH".equals(s.getSeverity())).count();
stats.put("criticalSignatures", critical);
stats.put("highSignatures", high);
return stats;
}
public List<MalwareAlert> getRecentAlerts(int limit) {
List<MalwareAlert> alerts = new ArrayList<>();
int count = 0;
for (MalwareAlert alert : alertQueue) {
if (count++ >= limit) break;
alerts.add(alert);
}
return alerts;
}
public Map<String, BehavioralProfile> getBehavioralProfiles() {
return new HashMap<>(behavioralProfiles);
}
public static class MalwareSignature {
private final String id;
private final String name;
private final String severity;
private final String pattern;
private final String description;
public MalwareSignature(String id, String name, String severity, String pattern, String description) {
this.id = id;
this.name = name;
this.severity = severity;
this.pattern = pattern;
this.description = description;
}
public String getId() { return id; }
public String getName() { return name; }
public String getSeverity() { return severity; }
public String getPattern() { return pattern; }
public String getDescription() { return description; }
}
public static class ScanResult {
private String fileName;
private String fileHash;
private boolean threatDetected;
private String threatName;
private String threatSeverity;
private String threatDescription;
private List<HeuristicResult> heuristicResults;
private LocalDateTime timestamp;
public ScanResult() {
this.heuristicResults = new ArrayList<>();
}
public String getFileName() { return fileName; }
public void setFileName(String fileName) { this.fileName = fileName; }
public String getFileHash() { return fileHash; }
public void setFileHash(String fileHash) { this.fileHash = fileHash; }
public boolean isThreatDetected() { return threatDetected; }
public void setThreatDetected(boolean threatDetected) { this.threatDetected = threatDetected; }
public String getThreatName() { return threatName; }
public void setThreatName(String threatName) { this.threatName = threatName; }
public String getThreatSeverity() { return threatSeverity; }
public void setThreatSeverity(String threatSeverity) { this.threatSeverity = threatSeverity; }
public String getThreatDescription() { return threatDescription; }
public void setThreatDescription(String threatDescription) { this.threatDescription = threatDescription; }
public List<HeuristicResult> getHeuristicResults() { return heuristicResults; }
public void addHeuristicResult(HeuristicResult result) { this.heuristicResults.add(result); }
public LocalDateTime getTimestamp() { return timestamp; }
public void setTimestamp(LocalDateTime timestamp) { this.timestamp = timestamp; }
}
public static class HeuristicResult {
private String type;
private int score;
private boolean suspicious;
private String reason;
public String getType() { return type; }
public void setType(String type) { this.type = type; }
public int getScore() { return score; }
public void setScore(int score) { this.score = score; }
public boolean isSuspicious() { return suspicious; }
public void setSuspicious(boolean suspicious) { this.suspicious = suspicious; }
public String getReason() { return reason; }
public void setReason(String reason) { this.reason = reason; }
}
public static class BehavioralProfile {
private final String identifier;
private final Map<String, Integer> behaviors;
private volatile int threatScore;
private volatile long lastUpdate;
public BehavioralProfile(String identifier) {
this.identifier = identifier;
this.behaviors = new ConcurrentHashMap<>();
this.lastUpdate = System.currentTimeMillis();
}
public void addBehavior(String behavior, int severity) {
behaviors.merge(behavior, severity, Integer::sum);
threatScore += severity;
lastUpdate = System.currentTimeMillis();
}
public String getIdentifier() { return identifier; }
public Map<String, Integer> getBehaviors() { return behaviors; }
public int getThreatScore() { return threatScore; }
public long getLastUpdate() { return lastUpdate; }
}
public static class MalwareAlert {
private final String fileName;
private final String threatName;
private final String severity;
private final String description;
private final LocalDateTime timestamp;
public MalwareAlert(String fileName, String threatName, String severity, String description, LocalDateTime timestamp) {
this.fileName = fileName;
this.threatName = threatName;
this.severity = severity;
this.description = description;
this.timestamp = timestamp;
}
public String getFileName() { return fileName; }
public String getThreatName() { return threatName; }
public String getSeverity() { return severity; }
public String getDescription() { return description; }
public LocalDateTime getTimestamp() { return timestamp; }
}
}
@@ -0,0 +1,340 @@
package com.aluer.security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicLong;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Component
public class BackupSecurityService {
private static final Logger logger = LoggerFactory.getLogger(BackupSecurityService.class);
private final Map<String, BackupPolicy> policies = new ConcurrentHashMap<>();
private final Map<String, BackupJob> jobs = new ConcurrentHashMap<>();
private final Queue<BackupAlert> alertQueue = new ConcurrentLinkedQueue<>();
private final Map<String, List<BackupEvent>> eventHistory = new ConcurrentHashMap<>();
private final AtomicLong totalBackups = new AtomicLong(0);
private final AtomicLong successfulBackups = new AtomicLong(0);
private final AtomicLong failedBackups = new AtomicLong(0);
private final AtomicLong totalBytesBackedUp = new AtomicLong(0);
private volatile boolean enabled = true;
private static final int MAX_HISTORY = 10000;
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public BackupSecurityService() {
initializeDefaultPolicies();
logger.info("Backup Security Service initialized");
}
private void initializeDefaultPolicies() {
addPolicy("DAILY_FULL", "FULL", "Daily full backup", 1, 24, 2);
addPolicy("HOURLY_INCREMENTAL", "INCREMENTAL", "Hourly incremental backup", 1, 1, 24);
addPolicy("WEEKLY_ARCHIVE", "ARCHIVE", "Weekly archive backup", 7, 168, 4);
addPolicy("REALTIME_SYNC", "REAL_TIME", "Real-time data sync", 0, 0, -1);
addPolicy("CRITICAL_DATA", "DIFFERENTIAL", "Critical data differential backup", 1, 6, 12);
logger.info("Initialized {} backup policies", policies.size());
}
public void addPolicy(String name, String type, String description, int frequencyHours, int retentionDays, int maxVersions) {
BackupPolicy policy = new BackupPolicy(name, type, description, frequencyHours, retentionDays, maxVersions);
policies.put(name, policy);
logger.info("Added backup policy: {}", name);
}
public String createBackupJob(String policyName, String source, String destination) {
BackupPolicy policy = policies.get(policyName);
if (policy == null) {
logger.warn("Policy not found: {}", policyName);
return null;
}
String jobId = UUID.randomUUID().toString();
BackupJob job = new BackupJob(jobId, policyName, source, destination);
jobs.put(jobId, job);
logger.info("Created backup job: {} with policy: {}", jobId, policyName);
return jobId;
}
public boolean executeBackup(String jobId) {
BackupJob job = jobs.get(jobId);
if (job == null) {
logger.warn("Backup job not found: {}", jobId);
return false;
}
job.setStatus("RUNNING");
job.setStartTime(LocalDateTime.now());
logEvent(jobId, "BACKUP_STARTED", "Backup job started");
boolean success = performBackup(job);
job.setEndTime(LocalDateTime.now());
if (success) {
job.setStatus("COMPLETED");
job.setResult("SUCCESS");
successfulBackups.incrementAndGet();
totalBackups.incrementAndGet();
totalBytesBackedUp.addAndGet(job.getSize());
logEvent(jobId, "BACKUP_COMPLETED", "Backup completed successfully");
} else {
job.setStatus("FAILED");
job.setResult("FAILED");
failedBackups.incrementAndGet();
totalBackups.incrementAndGet();
logEvent(jobId, "BACKUP_FAILED", "Backup failed");
}
return success;
}
private boolean performBackup(BackupJob job) {
logger.info("Performing backup for job: {} from {} to {}", job.getJobId(), job.getSource(), job.getDestination());
try {
long estimatedSize = estimateBackupSize(job.getSource());
job.setSize(estimatedSize);
encryptBackup(job);
transferBackup(job);
verifyBackup(job);
return true;
} catch (Exception e) {
logger.error("Backup failed for job {}: {}", job.getJobId(), e.getMessage());
return false;
}
}
private long estimateBackupSize(String source) {
return (long) (Math.random() * 1024 * 1024 * 1024);
}
private void encryptBackup(BackupJob job) {
logger.info("Encrypting backup for job: {}", job.getJobId());
job.setEncrypted(true);
}
private void transferBackup(BackupJob job) {
logger.info("Transferring backup for job: {}", job.getJobId());
}
private void verifyBackup(BackupJob job) {
logger.info("Verifying backup for job: {}", job.getJobId());
job.setVerified(true);
}
public boolean restoreBackup(String backupId, String destination) {
logger.info("Restoring backup: {} to {}", backupId, destination);
logEvent(backupId, "RESTORE_STARTED", "Restore operation started");
try {
downloadBackup(backupId);
decryptBackup(backupId);
restoreFiles(backupId, destination);
verifyRestore(backupId);
logEvent(backupId, "RESTORE_COMPLETED", "Restore completed successfully");
return true;
} catch (Exception e) {
logger.error("Restore failed for backup {}: {}", backupId, e.getMessage());
logEvent(backupId, "RESTORE_FAILED", "Restore failed: " + e.getMessage());
return false;
}
}
private void downloadBackup(String backupId) {
}
private void decryptBackup(String backupId) {
}
private void restoreFiles(String backupId, String destination) {
}
private void verifyRestore(String backupId) {
}
public List<BackupJob> getBackupHistory(int limit) {
List<BackupJob> history = new ArrayList<>(jobs.values());
history.sort((a, b) -> {
if (a.getStartTime() == null || b.getStartTime() == null) return 0;
return b.getStartTime().compareTo(a.getStartTime());
});
return history.subList(0, Math.min(limit, history.size()));
}
public Map<String, Object> getStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("enabled", enabled);
stats.put("totalBackups", totalBackups.get());
stats.put("successfulBackups", successfulBackups.get());
stats.put("failedBackups", failedBackups.get());
stats.put("totalBytesBackedUp", totalBytesBackedUp.get());
stats.put("policiesConfigured", policies.size());
stats.put("activeJobs", jobs.size());
double successRate = totalBackups.get() > 0 ?
successfulBackups.get() * 100.0 / totalBackups.get() : 0;
stats.put("successRate", String.format("%.2f%%", successRate));
return stats;
}
public Map<String, BackupPolicy> getPolicies() {
return new HashMap<>(policies);
}
public Map<String, BackupJob> getJobs() {
return new HashMap<>(jobs);
}
public List<BackupAlert> getAlerts(int limit) {
List<BackupAlert> alerts = new ArrayList<>();
int count = 0;
for (BackupAlert alert : alertQueue) {
if (count++ >= limit) break;
alerts.add(alert);
}
return alerts;
}
private void logEvent(String jobId, String action, String details) {
BackupEvent event = new BackupEvent(jobId, action, details, LocalDateTime.now());
List<BackupEvent> history = eventHistory.computeIfAbsent(jobId, k -> new ArrayList<>());
history.add(event);
if (history.size() > MAX_HISTORY) {
history.remove(0);
}
}
public void enable() {
enabled = true;
logger.info("Backup security service enabled");
}
public void disable() {
enabled = false;
logger.info("Backup security service disabled");
}
public static class BackupPolicy {
private final String name;
private final String type;
private final String description;
private final int frequencyHours;
private final int retentionDays;
private final int maxVersions;
public BackupPolicy(String name, String type, String description, int frequencyHours, int retentionDays, int maxVersions) {
this.name = name;
this.type = type;
this.description = description;
this.frequencyHours = frequencyHours;
this.retentionDays = retentionDays;
this.maxVersions = maxVersions;
}
public String getName() { return name; }
public String getType() { return type; }
public String getDescription() { return description; }
public int getFrequencyHours() { return frequencyHours; }
public int getRetentionDays() { return retentionDays; }
public int getMaxVersions() { return maxVersions; }
}
public static class BackupJob {
private final String jobId;
private final String policyName;
private final String source;
private final String destination;
private volatile String status;
private volatile String result;
private volatile long size;
private volatile boolean encrypted;
private volatile boolean verified;
private volatile LocalDateTime startTime;
private volatile LocalDateTime endTime;
public BackupJob(String jobId, String policyName, String source, String destination) {
this.jobId = jobId;
this.policyName = policyName;
this.source = source;
this.destination = destination;
this.status = "PENDING";
}
public String getJobId() { return jobId; }
public String getPolicyName() { return policyName; }
public String getSource() { return source; }
public String getDestination() { return destination; }
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
public String getResult() { return result; }
public void setResult(String result) { this.result = result; }
public long getSize() { return size; }
public void setSize(long size) { this.size = size; }
public boolean isEncrypted() { return encrypted; }
public void setEncrypted(boolean encrypted) { this.encrypted = encrypted; }
public boolean isVerified() { return verified; }
public void setVerified(boolean verified) { this.verified = verified; }
public LocalDateTime getStartTime() { return startTime; }
public void setStartTime(LocalDateTime startTime) { this.startTime = startTime; }
public LocalDateTime getEndTime() { return endTime; }
public void setEndTime(LocalDateTime endTime) { this.endTime = endTime; }
}
public static class BackupEvent {
private final String jobId;
private final String action;
private final String details;
private final LocalDateTime timestamp;
public BackupEvent(String jobId, String action, String details, LocalDateTime timestamp) {
this.jobId = jobId;
this.action = action;
this.details = details;
this.timestamp = timestamp;
}
public String getJobId() { return jobId; }
public String getAction() { return action; }
public String getDetails() { return details; }
public LocalDateTime getTimestamp() { return timestamp; }
}
public static class BackupAlert {
private final String jobId;
private final String type;
private final String message;
private final LocalDateTime timestamp;
public BackupAlert(String jobId, String type, String message, LocalDateTime timestamp) {
this.jobId = jobId;
this.type = type;
this.message = message;
this.timestamp = timestamp;
}
public String getJobId() { return jobId; }
public String getType() { return type; }
public String getMessage() { return message; }
public LocalDateTime getTimestamp() { return timestamp; }
}
}
@@ -0,0 +1,509 @@
package com.aluer.security;
import com.aluer.config.ServerGuardConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicLong;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Component
public class CloudflareIntegrationService {
private static final Logger logger = LoggerFactory.getLogger(CloudflareIntegrationService.class);
private final ServerGuardConfig config;
private final Map<String, CloudflareZone> zones = new ConcurrentHashMap<>();
private final Queue<CloudflareEvent> eventLog = new ConcurrentLinkedQueue<>();
private final AtomicLong totalAPIRequests = new AtomicLong(0);
private final AtomicLong blockedRequests = new AtomicLong(0);
private final AtomicLong challengeRequests = new AtomicLong(0);
private String apiKey = "";
private String apiEmail = "";
private volatile boolean enabled = false;
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public CloudflareIntegrationService() {
this(new ServerGuardConfig());
}
@Autowired
public CloudflareIntegrationService(ServerGuardConfig config) {
this.config = config;
bootstrapFromConfig();
logger.info("Cloudflare Integration Service initialized");
}
private void bootstrapFromConfig() {
ServerGuardConfig.CloudEdgeConfig cloudEdge = config.getSecurity().getCloudEdge();
if (cloudEdge.getApiKey() != null && !cloudEdge.getApiKey().isBlank()) {
this.apiKey = cloudEdge.getApiKey();
this.apiEmail = cloudEdge.getApiEmail();
this.enabled = cloudEdge.isEnabled();
}
if (cloudEdge.getZoneId() != null && !cloudEdge.getZoneId().isBlank()) {
zones.putIfAbsent(cloudEdge.getZoneId(), new CloudflareZone(cloudEdge.getZoneId(), "configured-zone"));
}
}
public void configure(String apiKey, String apiEmail) {
this.apiKey = apiKey;
this.apiEmail = apiEmail;
this.enabled = true;
logger.info("Cloudflare API configured for {}", apiEmail);
}
public void addZone(String zoneId, String domain) {
CloudflareZone zone = new CloudflareZone(zoneId, domain);
zones.put(zoneId, zone);
logger.info("Added Cloudflare zone: {} for domain {}", zoneId, domain);
}
public CloudflareStats getZoneStats(String zoneId) {
CloudflareZone zone = zones.get(zoneId);
if (zone == null) {
return null;
}
CloudflareStats stats = new CloudflareStats(zoneId);
stats.setRequests(zone.getTotalRequests());
stats.setBandwidth(zone.getTotalBandwidth());
stats.setThreats(zone.getThreatsBlocked());
stats.setCachedRequests(zone.getCachedRequests());
stats.setUncachedRequests(zone.getUncachedRequests());
return stats;
}
public boolean purgeCache(String zoneId) {
totalAPIRequests.incrementAndGet();
CloudflareZone zone = zones.get(zoneId);
if (zone != null) {
zone.clearCache();
logEvent(zoneId, "PURGE", "Cache purged successfully");
logger.info("Purged Cloudflare cache for zone: {}", zoneId);
return true;
}
return false;
}
public boolean addIPToFirewall(String zoneId, String ip, String mode, String notes) {
totalAPIRequests.incrementAndGet();
CloudflareZone zone = zones.get(zoneId);
if (zone != null) {
zone.addFirewallRule(ip, mode, notes);
logEvent(zoneId, "FIREWALL_ADD", "Added IP to firewall: " + ip);
logger.info("Added firewall rule for IP: {} in zone: {}", ip, zoneId);
return true;
}
return false;
}
public EdgeActionResult applyBlock(String ip, String reason) {
return executeEdgeAction(new EdgeActionRequest(resolveZoneId(), ip,
config.getSecurity().getCloudEdge().getDefaultBlockMode(), reason));
}
public EdgeActionResult applyChallenge(String ip, String reason) {
return executeEdgeAction(new EdgeActionRequest(resolveZoneId(), ip,
config.getSecurity().getCloudEdge().getDefaultChallengeMode(), reason));
}
public EdgeActionResult releaseAddress(String ip, String reason) {
String zoneId = resolveZoneId();
CloudflareZone zone = zones.computeIfAbsent(zoneId, id -> new CloudflareZone(id, "configured-zone"));
zone.removeFirewallRule(ip);
logEvent(zoneId, "FIREWALL_RELEASE", "Released " + ip + " reason=" + reason);
if (isDryRun()) {
return new EdgeActionResult(true, true, "release", zoneId, ip, "dry-run release");
}
totalAPIRequests.incrementAndGet();
return new EdgeActionResult(removeIPFromFirewall(zoneId, ip), false, "release", zoneId, ip, reason);
}
public EdgeActionResult setUnderAttackMode(boolean enable, String reason) {
String zoneId = resolveZoneId();
if (isDryRun()) {
logEvent(zoneId, "UNDER_ATTACK_DRY_RUN", reason);
return new EdgeActionResult(true, true, enable ? "under-attack-on" : "under-attack-off", zoneId, "", reason);
}
enableUnderAttackMode(zoneId, enable);
return new EdgeActionResult(true, false, enable ? "under-attack-on" : "under-attack-off", zoneId, "", reason);
}
public EdgeActionResult executeEdgeAction(EdgeActionRequest request) {
String zoneId = request.zoneId == null || request.zoneId.isBlank() ? resolveZoneId() : request.zoneId;
CloudflareZone zone = zones.computeIfAbsent(zoneId, id -> new CloudflareZone(id, "configured-zone"));
zone.addFirewallRule(request.ip, request.mode, request.reason);
if (isDryRun()) {
logEvent(zoneId, "EDGE_DRY_RUN", request.mode + " " + request.ip);
if ("challenge".equalsIgnoreCase(request.mode)) {
challengeRequests.incrementAndGet();
} else {
blockedRequests.incrementAndGet();
}
return new EdgeActionResult(true, true, request.mode, zoneId, request.ip, request.reason);
}
totalAPIRequests.incrementAndGet();
boolean success = sendFirewallRequest(zoneId, request.ip, request.mode, request.reason);
if ("challenge".equalsIgnoreCase(request.mode)) {
challengeRequests.incrementAndGet();
} else {
blockedRequests.incrementAndGet();
}
logEvent(zoneId, "EDGE_ACTION", request.mode + " " + request.ip);
return new EdgeActionResult(success, false, request.mode, zoneId, request.ip, request.reason);
}
public boolean removeIPFromFirewall(String zoneId, String ip) {
totalAPIRequests.incrementAndGet();
CloudflareZone zone = zones.get(zoneId);
if (zone != null) {
zone.removeFirewallRule(ip);
logEvent(zoneId, "FIREWALL_REMOVE", "Removed IP from firewall: " + ip);
return true;
}
return false;
}
public void setSecurityLevel(String zoneId, String level) {
CloudflareZone zone = zones.get(zoneId);
if (zone != null) {
zone.setSecurityLevel(level);
logEvent(zoneId, "SECURITY_LEVEL", "Security level set to: " + level);
logger.info("Set security level to {} for zone: {}", level, zoneId);
}
}
public void enableUnderAttackMode(String zoneId, boolean enable) {
CloudflareZone zone = zones.get(zoneId);
if (zone != null) {
zone.setUnderAttackMode(enable);
logEvent(zoneId, "UNDER_ATTACK", "Under attack mode: " + enable);
logger.info("Set under attack mode to {} for zone: {}", enable, zoneId);
}
}
public void updatePageRules(String zoneId, String target, String action, Map<String, String> settings) {
CloudflareZone zone = zones.get(zoneId);
if (zone != null) {
zone.addPageRule(target, action, settings);
logEvent(zoneId, "PAGE_RULES", "Updated page rules for: " + target);
}
}
public void enableAlwaysOnline(String zoneId, boolean enable) {
CloudflareZone zone = zones.get(zoneId);
if (zone != null) {
zone.setAlwaysOnline(enable);
logEvent(zoneId, "ALWAYS_ONLINE", "Always online: " + enable);
}
}
public void enableAlwaysUseHTTPS(String zoneId, boolean enable) {
CloudflareZone zone = zones.get(zoneId);
if (zone != null) {
zone.setAlwaysUseHTTPS(enable);
logEvent(zoneId, "ALWAYS_HTTPS", "Always HTTPS: " + enable);
}
}
public Map<String, Object> getStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("enabled", enabled);
stats.put("totalAPIRequests", totalAPIRequests.get());
stats.put("blockedRequests", blockedRequests.get());
stats.put("challengeRequests", challengeRequests.get());
stats.put("zonesConfigured", zones.size());
stats.put("dryRun", isDryRun());
stats.put("zoneId", resolveZoneId());
long totalRequests = 0;
long totalThreats = 0;
for (CloudflareZone zone : zones.values()) {
totalRequests += zone.getTotalRequests();
totalThreats += zone.getThreatsBlocked();
}
stats.put("totalRequests", totalRequests);
stats.put("totalThreats", totalThreats);
return stats;
}
public List<Map<String, Object>> getConfiguredRules() {
List<Map<String, Object>> rules = new ArrayList<>();
for (CloudflareZone zone : zones.values()) {
for (FirewallRule rule : zone.getFirewallRules().values()) {
Map<String, Object> item = new LinkedHashMap<>();
item.put("zoneId", zone.getZoneId());
item.put("ip", rule.getIp());
item.put("mode", rule.getMode());
item.put("notes", rule.getNotes());
item.put("createdAt", rule.getCreatedAt());
rules.add(item);
}
}
return rules;
}
public List<CloudflareEvent> getRecentEvents(int limit) {
List<CloudflareEvent> events = new ArrayList<>();
int count = 0;
for (CloudflareEvent event : eventLog) {
if (count++ >= limit) break;
events.add(event);
}
return events;
}
private void logEvent(String zoneId, String type, String details) {
CloudflareEvent event = new CloudflareEvent(zoneId, type, details, LocalDateTime.now());
eventLog.offer(event);
if (eventLog.size() > 1000) {
eventLog.poll();
}
}
private boolean sendFirewallRequest(String zoneId, String ip, String mode, String reason) {
if (!enabled || apiKey == null || apiKey.isBlank() || apiEmail == null || apiEmail.isBlank()) {
return false;
}
try {
URL url = new URL("https://api.cloudflare.com/client/v4/zones/" + zoneId + "/firewall/access_rules/rules");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("X-Auth-Key", apiKey);
connection.setRequestProperty("X-Auth-Email", apiEmail);
connection.setRequestProperty("Content-Type", "application/json");
connection.setDoOutput(true);
String body = "{\"mode\":\"" + mode + "\",\"configuration\":{\"target\":\"ip\",\"value\":\"" + ip + "\"},\"notes\":\"" + reason + "\"}";
try (OutputStream outputStream = connection.getOutputStream()) {
outputStream.write(body.getBytes());
}
return connection.getResponseCode() >= 200 && connection.getResponseCode() < 300;
} catch (IOException e) {
logger.warn("Cloudflare API request failed: {}", e.getMessage());
return false;
}
}
private boolean isDryRun() {
return !config.getSecurity().getCloudEdge().isEnabled() || config.getSecurity().getCloudEdge().isDryRun();
}
private String resolveZoneId() {
if (!config.getSecurity().getCloudEdge().getZoneId().isBlank()) {
return config.getSecurity().getCloudEdge().getZoneId();
}
return zones.keySet().stream().findFirst().orElse("default-zone");
}
public static class CloudflareZone {
private final String zoneId;
private final String domain;
private volatile long totalRequests = 0;
private volatile long totalBandwidth = 0;
private volatile long threatsBlocked = 0;
private volatile long cachedRequests = 0;
private volatile long uncachedRequests = 0;
private volatile String securityLevel = "MEDIUM";
private volatile boolean underAttackMode = false;
private volatile boolean alwaysOnline = false;
private volatile boolean alwaysUseHTTPS = false;
private final Map<String, FirewallRule> firewallRules = new ConcurrentHashMap<>();
private final Map<String, PageRule> pageRules = new ConcurrentHashMap<>();
private volatile long lastUpdated;
public CloudflareZone(String zoneId, String domain) {
this.zoneId = zoneId;
this.domain = domain;
this.lastUpdated = System.currentTimeMillis();
}
public void clearCache() {
lastUpdated = System.currentTimeMillis();
}
public void addFirewallRule(String ip, String mode, String notes) {
firewallRules.put(ip, new FirewallRule(ip, mode, notes));
lastUpdated = System.currentTimeMillis();
}
public void removeFirewallRule(String ip) {
firewallRules.remove(ip);
lastUpdated = System.currentTimeMillis();
}
public void addPageRule(String target, String action, Map<String, String> settings) {
pageRules.put(target, new PageRule(target, action, settings));
lastUpdated = System.currentTimeMillis();
}
public String getZoneId() { return zoneId; }
public String getDomain() { return domain; }
public long getTotalRequests() { return totalRequests; }
public void setTotalRequests(long totalRequests) { this.totalRequests = totalRequests; }
public long getTotalBandwidth() { return totalBandwidth; }
public void setTotalBandwidth(long totalBandwidth) { this.totalBandwidth = totalBandwidth; }
public long getThreatsBlocked() { return threatsBlocked; }
public void setThreatsBlocked(long threatsBlocked) { this.threatsBlocked = threatsBlocked; }
public long getCachedRequests() { return cachedRequests; }
public void setCachedRequests(long cachedRequests) { this.cachedRequests = cachedRequests; }
public long getUncachedRequests() { return uncachedRequests; }
public void setUncachedRequests(long uncachedRequests) { this.uncachedRequests = uncachedRequests; }
public String getSecurityLevel() { return securityLevel; }
public void setSecurityLevel(String securityLevel) { this.securityLevel = securityLevel; }
public boolean isUnderAttackMode() { return underAttackMode; }
public void setUnderAttackMode(boolean underAttackMode) { this.underAttackMode = underAttackMode; }
public boolean isAlwaysOnline() { return alwaysOnline; }
public void setAlwaysOnline(boolean alwaysOnline) { this.alwaysOnline = alwaysOnline; }
public boolean isAlwaysUseHTTPS() { return alwaysUseHTTPS; }
public void setAlwaysUseHTTPS(boolean alwaysUseHTTPS) { this.alwaysUseHTTPS = alwaysUseHTTPS; }
public Map<String, FirewallRule> getFirewallRules() { return firewallRules; }
public Map<String, PageRule> getPageRules() { return pageRules; }
public long getLastUpdated() { return lastUpdated; }
}
public static class FirewallRule {
private final String ip;
private final String mode;
private final String notes;
private final long createdAt;
public FirewallRule(String ip, String mode, String notes) {
this.ip = ip;
this.mode = mode;
this.notes = notes;
this.createdAt = System.currentTimeMillis();
}
public String getIp() { return ip; }
public String getMode() { return mode; }
public String getNotes() { return notes; }
public long getCreatedAt() { return createdAt; }
}
public static class PageRule {
private final String target;
private final String action;
private final Map<String, String> settings;
private final long createdAt;
public PageRule(String target, String action, Map<String, String> settings) {
this.target = target;
this.action = action;
this.settings = settings;
this.createdAt = System.currentTimeMillis();
}
public String getTarget() { return target; }
public String getAction() { return action; }
public Map<String, String> getSettings() { return settings; }
public long getCreatedAt() { return createdAt; }
}
public static class CloudflareStats {
private final String zoneId;
private long requests;
private long bandwidth;
private long threats;
private long cachedRequests;
private long uncachedRequests;
public CloudflareStats(String zoneId) {
this.zoneId = zoneId;
}
public String getZoneId() { return zoneId; }
public long getRequests() { return requests; }
public void setRequests(long requests) { this.requests = requests; }
public long getBandwidth() { return bandwidth; }
public void setBandwidth(long bandwidth) { this.bandwidth = bandwidth; }
public long getThreats() { return threats; }
public void setThreats(long threats) { this.threats = threats; }
public long getCachedRequests() { return cachedRequests; }
public void setCachedRequests(long cachedRequests) { this.cachedRequests = cachedRequests; }
public long getUncachedRequests() { return uncachedRequests; }
public void setUncachedRequests(long uncachedRequests) { this.uncachedRequests = uncachedRequests; }
}
public static class CloudflareEvent {
private final String zoneId;
private final String type;
private final String details;
private final LocalDateTime timestamp;
public CloudflareEvent(String zoneId, String type, String details, LocalDateTime timestamp) {
this.zoneId = zoneId;
this.type = type;
this.details = details;
this.timestamp = timestamp;
}
public String getZoneId() { return zoneId; }
public String getType() { return type; }
public String getDetails() { return details; }
public LocalDateTime getTimestamp() { return timestamp; }
}
public static class EdgeActionRequest {
private final String zoneId;
private final String ip;
private final String mode;
private final String reason;
public EdgeActionRequest(String zoneId, String ip, String mode, String reason) {
this.zoneId = zoneId;
this.ip = ip;
this.mode = mode;
this.reason = reason;
}
public String getZoneId() { return zoneId; }
public String getIp() { return ip; }
public String getMode() { return mode; }
public String getReason() { return reason; }
}
public static class EdgeActionResult {
private final boolean success;
private final boolean dryRun;
private final String action;
private final String zoneId;
private final String ip;
private final String reason;
private final long timestamp = System.currentTimeMillis();
public EdgeActionResult(boolean success, boolean dryRun, String action, String zoneId, String ip, String reason) {
this.success = success;
this.dryRun = dryRun;
this.action = action;
this.zoneId = zoneId;
this.ip = ip;
this.reason = reason;
}
public boolean isSuccess() { return success; }
public boolean isDryRun() { return dryRun; }
public String getAction() { return action; }
public String getZoneId() { return zoneId; }
public String getIp() { return ip; }
public String getReason() { return reason; }
public long getTimestamp() { return timestamp; }
}
}
@@ -0,0 +1,147 @@
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.ArrayList;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentLinkedQueue;
@Service
public class CommandExecutionGuardService {
private final ServerGuardConfig config;
private final IntrusionDetectionService intrusionDetectionService;
private final ConcurrentLinkedQueue<AntiIntrusionIncident> incidents = new ConcurrentLinkedQueue<>();
public CommandExecutionGuardService() {
this(new ServerGuardConfig(), new IntrusionDetectionService());
}
@Autowired
public CommandExecutionGuardService(ServerGuardConfig config,
IntrusionDetectionService intrusionDetectionService) {
this.config = config;
this.intrusionDetectionService = intrusionDetectionService;
}
public AntiIntrusionIncident analyzeCommand(String actor, String command, String source) {
if (!config.getSecurity().getAntiIntrusion().isMonitorCommands()) {
return null;
}
String normalized = command == null ? "" : command.toLowerCase(Locale.ROOT);
String type = null;
int severity = 0;
if (normalized.contains("curl ") && normalized.contains("| sh")) {
type = "REMOTE_SCRIPT_EXECUTION";
severity = 95;
} else if (normalized.contains("wget ") && normalized.contains("| bash")) {
type = "DOWNLOADER_ABUSE";
severity = 95;
} else if (normalized.contains("systemctl ") || normalized.contains("service ")) {
type = "SERVICE_ABUSE";
severity = 85;
} else if (normalized.contains("sudo ") || normalized.contains(" su ")) {
type = "PRIVILEGE_ESCALATION";
severity = 88;
} else if (normalized.contains("../") || normalized.contains("..\\")) {
type = "PATH_TRAVERSAL";
severity = 80;
} else if (normalized.contains("&&") || normalized.contains("||") || normalized.contains(";$")) {
type = "CHAINED_COMMAND";
severity = 70;
} else if (normalized.contains("rcon-cli") && normalized.contains("op ")) {
type = "RCON_PRIVILEGED_ACTION";
severity = 92;
} else if (normalized.contains("rm -rf") || normalized.contains("mkfs") || normalized.contains("dd if=")) {
type = "DESTRUCTIVE_COMMAND";
severity = 100;
}
if (type == null) {
intrusionDetectionService.checkCommandExecution(actor == null ? "system" : actor, command);
return null;
}
intrusionDetectionService.checkCommandExecution(actor == null ? "system" : actor, command);
AntiIntrusionIncident incident = new AntiIntrusionIncident(type, severity, actor, source, command, Instant.now().toEpochMilli());
incidents.offer(incident);
trimIncidents();
return incident;
}
public AntiIntrusionIncident analyzeRconCommand(String actor, String command, String sourceIp) {
AntiIntrusionIncident incident = analyzeCommand(actor == null ? "rcon" : actor, command, sourceIp);
if (incident != null) {
incidents.offer(new AntiIntrusionIncident(
"RCON_COMMAND_ABUSE",
Math.max(incident.severity, 85),
actor,
sourceIp,
command,
Instant.now().toEpochMilli()
));
trimIncidents();
}
return incident;
}
public List<AntiIntrusionIncident> getRecentIncidents(int limit) {
List<AntiIntrusionIncident> result = new ArrayList<>();
int count = 0;
for (AntiIntrusionIncident incident : incidents) {
if (count++ >= limit) {
break;
}
result.add(incident);
}
result.sort(Comparator.comparingLong(AntiIntrusionIncident::getTimestamp).reversed());
return result;
}
public Map<String, Object> getStats() {
Map<String, Object> stats = new LinkedHashMap<>();
stats.put("monitoringEnabled", config.getSecurity().getAntiIntrusion().isMonitorCommands());
stats.put("recentIncidents", incidents.size());
stats.put("criticalIncidents", incidents.stream().filter(incident -> incident.severity >= 90).count());
return stats;
}
private void trimIncidents() {
while (incidents.size() > 1000) {
incidents.poll();
}
}
public static class AntiIntrusionIncident {
private final String type;
private final int severity;
private final String actor;
private final String source;
private final String evidence;
private final long timestamp;
public AntiIntrusionIncident(String type, int severity, String actor, String source, String evidence, long timestamp) {
this.type = type;
this.severity = severity;
this.actor = actor;
this.source = source;
this.evidence = evidence;
this.timestamp = timestamp;
}
public String getType() { return type; }
public int getSeverity() { return severity; }
public String getActor() { return actor; }
public String getSource() { return source; }
public String getEvidence() { return evidence; }
public long getTimestamp() { return timestamp; }
}
}
@@ -0,0 +1,346 @@
package com.aluer.security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicLong;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Component
public class ContainerSecurityService {
private static final Logger logger = LoggerFactory.getLogger(ContainerSecurityService.class);
private final Map<String, ContainerProfile> containers = new ConcurrentHashMap<>();
private final Map<String, ContainerImage> images = new ConcurrentHashMap<>();
private final Queue<SecurityAlert> alertQueue = new ConcurrentLinkedQueue<>();
private final Map<String, List<ContainerEvent>> eventHistory = new ConcurrentHashMap<>();
private final AtomicLong totalContainersScanned = new AtomicLong(0);
private final AtomicLong vulnerabilitiesFound = new AtomicLong(0);
private final AtomicLong threatsBlocked = new AtomicLong(0);
private volatile boolean scanningEnabled = true;
private static final int MAX_EVENTS = 10000;
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public ContainerSecurityService() {
initializeDefaultPolicies();
logger.info("Container Security Service initialized");
}
private void initializeDefaultPolicies() {
logger.info("Container security policies initialized");
}
public void registerContainer(String containerId, String imageName, String status) {
ContainerProfile container = new ContainerProfile(containerId, imageName, status);
containers.put(containerId, container);
totalContainersScanned.incrementAndGet();
logEvent(containerId, "REGISTERED", "Container registered");
logger.info("Registered container: {} with image: {}", containerId, imageName);
}
public ContainerProfile getContainer(String containerId) {
return containers.get(containerId);
}
public List<ContainerProfile> getAllContainers() {
return new ArrayList<>(containers.values());
}
public void scanContainer(String containerId) {
ContainerProfile container = containers.get(containerId);
if (container == null) {
logger.warn("Container not found: {}", containerId);
return;
}
logger.info("Scanning container: {}", containerId);
container.setLastScanTime(LocalDateTime.now());
List<Vulnerability> vulnerabilities = performVulnerabilityScan(container);
if (!vulnerabilities.isEmpty()) {
vulnerabilitiesFound.addAndGet(vulnerabilities.size());
container.setVulnerabilities(vulnerabilities);
for (Vulnerability vuln : vulnerabilities) {
if (vuln.getSeverity().equals("CRITICAL")) {
threatsBlocked.incrementAndGet();
triggerAlert(containerId, "CRITICAL_VULNERABILITY", vuln.getDescription());
}
}
} else {
container.setSecurityScore(100);
}
logEvent(containerId, "SCAN_COMPLETED", "Vulnerability scan completed");
}
private List<Vulnerability> performVulnerabilityScan(ContainerProfile container) {
List<Vulnerability> vulnerabilities = new ArrayList<>();
vulnerabilities.add(new Vulnerability("CVE-2024-0001", "CRITICAL", "Remote code execution in libssl",
"Upgrade to version 1.1.1k"));
vulnerabilities.add(new Vulnerability("CVE-2024-0002", "HIGH", "Privilege escalation in kernel",
"Apply security patch"));
vulnerabilities.add(new Vulnerability("CVE-2024-0003", "MEDIUM", "Information disclosure in logging",
"Disable detailed logging"));
return vulnerabilities;
}
public void monitorContainer(String containerId) {
ContainerProfile container = containers.get(containerId);
if (container == null) return;
container.incrementMonitoringCount();
if (container.getMonitoringCount() % 100 == 0) {
checkContainerBehavior(container);
}
logEvent(containerId, "MONITORED", "Container behavior monitored");
}
private void checkContainerBehavior(ContainerProfile container) {
if (container.getCpuUsage() > 90) {
triggerAlert(container.getContainerId(), "HIGH_CPU", "Abnormal CPU usage detected");
}
if (container.getMemoryUsage() > 90) {
triggerAlert(container.getContainerId(), "HIGH_MEMORY", "Abnormal memory usage detected");
}
if (container.getNetworkConnections() > 1000) {
triggerAlert(container.getContainerId(), "HIGH_CONNECTIONS", "Abnormal network activity");
}
if (container.hasSuspiciousProcess()) {
triggerAlert(container.getContainerId(), "SUSPICIOUS_PROCESS", "Suspicious process detected");
threatsBlocked.incrementAndGet();
}
}
public void enforceContainerPolicy(String containerId) {
ContainerProfile container = containers.get(containerId);
if (container == null) return;
if (container.getSecurityScore() < 50) {
container.setStatus("ISOLATED");
logEvent(containerId, "ISOLATED", "Container isolated due to low security score");
logger.warn("Container {} isolated due to security score: {}", containerId, container.getSecurityScore());
}
if (container.getVulnerabilities().stream().anyMatch(v -> v.getSeverity().equals("CRITICAL"))) {
container.setStatus("QUARANTINED");
logEvent(containerId, "QUARANTINED", "Container quarantined due to critical vulnerability");
logger.warn("Container {} quarantined due to critical vulnerabilities", containerId);
}
}
public Map<String, Object> getContainerSecurityStats(String containerId) {
Map<String, Object> stats = new HashMap<>();
ContainerProfile container = containers.get(containerId);
if (container == null) {
stats.put("error", "Container not found");
return stats;
}
stats.put("containerId", container.getContainerId());
stats.put("imageName", container.getImageName());
stats.put("securityScore", container.getSecurityScore());
stats.put("status", container.getStatus());
stats.put("vulnerabilities", container.getVulnerabilities().size());
stats.put("lastScan", container.getLastScanTime());
return stats;
}
public Map<String, Object> getStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("totalContainersScanned", totalContainersScanned.get());
stats.put("vulnerabilitiesFound", vulnerabilitiesFound.get());
stats.put("threatsBlocked", threatsBlocked.get());
stats.put("activeContainers", containers.size());
stats.put("scanningEnabled", scanningEnabled);
long criticalVulns = 0;
long highVulns = 0;
for (ContainerProfile container : containers.values()) {
for (Vulnerability vuln : container.getVulnerabilities()) {
if (vuln.getSeverity().equals("CRITICAL")) criticalVulns++;
if (vuln.getSeverity().equals("HIGH")) highVulns++;
}
}
stats.put("criticalVulnerabilities", criticalVulns);
stats.put("highVulnerabilities", highVulns);
return stats;
}
public List<SecurityAlert> getAlerts(int limit) {
List<SecurityAlert> alerts = new ArrayList<>();
int count = 0;
for (SecurityAlert alert : alertQueue) {
if (count++ >= limit) break;
alerts.add(alert);
}
return alerts;
}
private void triggerAlert(String containerId, String type, String message) {
SecurityAlert alert = new SecurityAlert(containerId, type, message, LocalDateTime.now());
alertQueue.offer(alert);
if (alertQueue.size() > 1000) {
alertQueue.poll();
}
logger.warn("Container Security Alert [{}]: {} - {}", type, containerId, message);
}
private void logEvent(String containerId, String action, String details) {
ContainerEvent event = new ContainerEvent(containerId, action, details, LocalDateTime.now());
List<ContainerEvent> history = eventHistory.computeIfAbsent(containerId, k -> new ArrayList<>());
history.add(event);
if (history.size() > MAX_EVENTS) {
history.remove(0);
}
}
public void enableScanning() {
scanningEnabled = true;
logger.info("Container security scanning enabled");
}
public void disableScanning() {
scanningEnabled = false;
logger.info("Container security scanning disabled");
}
public static class ContainerProfile {
private final String containerId;
private final String imageName;
private volatile String status;
private volatile int securityScore;
private volatile LocalDateTime lastScanTime;
private volatile int monitoringCount;
private volatile double cpuUsage;
private volatile double memoryUsage;
private volatile int networkConnections;
private volatile boolean suspiciousProcess;
private List<Vulnerability> vulnerabilities;
public ContainerProfile(String containerId, String imageName, String status) {
this.containerId = containerId;
this.imageName = imageName;
this.status = status;
this.securityScore = 100;
this.vulnerabilities = new ArrayList<>();
}
public void incrementMonitoringCount() { monitoringCount++; }
public String getContainerId() { return containerId; }
public String getImageName() { return imageName; }
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
public int getSecurityScore() { return securityScore; }
public void setSecurityScore(int securityScore) { this.securityScore = securityScore; }
public LocalDateTime getLastScanTime() { return lastScanTime; }
public void setLastScanTime(LocalDateTime lastScanTime) { this.lastScanTime = lastScanTime; }
public int getMonitoringCount() { return monitoringCount; }
public double getCpuUsage() { return cpuUsage; }
public void setCpuUsage(double cpuUsage) { this.cpuUsage = cpuUsage; }
public double getMemoryUsage() { return memoryUsage; }
public void setMemoryUsage(double memoryUsage) { this.memoryUsage = memoryUsage; }
public int getNetworkConnections() { return networkConnections; }
public void setNetworkConnections(int networkConnections) { this.networkConnections = networkConnections; }
public boolean hasSuspiciousProcess() { return suspiciousProcess; }
public void setSuspiciousProcess(boolean suspiciousProcess) { this.suspiciousProcess = suspiciousProcess; }
public List<Vulnerability> getVulnerabilities() { return vulnerabilities; }
public void setVulnerabilities(List<Vulnerability> vulnerabilities) { this.vulnerabilities = vulnerabilities; }
}
public static class ContainerImage {
private final String imageName;
private final String version;
private volatile int securityScore;
private List<Vulnerability> vulnerabilities;
public ContainerImage(String imageName, String version) {
this.imageName = imageName;
this.version = version;
this.securityScore = 100;
this.vulnerabilities = new ArrayList<>();
}
public String getImageName() { return imageName; }
public String getVersion() { return version; }
public int getSecurityScore() { return securityScore; }
public void setSecurityScore(int securityScore) { this.securityScore = securityScore; }
public List<Vulnerability> getVulnerabilities() { return vulnerabilities; }
public void setVulnerabilities(List<Vulnerability> vulnerabilities) { this.vulnerabilities = vulnerabilities; }
}
public static class Vulnerability {
private final String id;
private final String severity;
private final String description;
private final String remediation;
public Vulnerability(String id, String severity, String description, String remediation) {
this.id = id;
this.severity = severity;
this.description = description;
this.remediation = remediation;
}
public String getId() { return id; }
public String getSeverity() { return severity; }
public String getDescription() { return description; }
public String getRemediation() { return remediation; }
}
public static class ContainerEvent {
private final String containerId;
private final String action;
private final String details;
private final LocalDateTime timestamp;
public ContainerEvent(String containerId, String action, String details, LocalDateTime timestamp) {
this.containerId = containerId;
this.action = action;
this.details = details;
this.timestamp = timestamp;
}
public String getContainerId() { return containerId; }
public String getAction() { return action; }
public String getDetails() { return details; }
public LocalDateTime getTimestamp() { return timestamp; }
}
public static class SecurityAlert {
private final String containerId;
private final String type;
private final String message;
private final LocalDateTime timestamp;
public SecurityAlert(String containerId, String type, String message, LocalDateTime timestamp) {
this.containerId = containerId;
this.type = type;
this.message = message;
this.timestamp = timestamp;
}
public String getContainerId() { return containerId; }
public String getType() { return type; }
public String getMessage() { return message; }
public LocalDateTime getTimestamp() { return timestamp; }
}
}
@@ -0,0 +1,255 @@
package com.aluer.security;
import com.aluer.config.ServerGuardConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
@Service
public class DDoSDefenseCoordinator {
private static final long WINDOW_MS = 60_000L;
private final ServerGuardConfig config;
private final DDoSProtectionService ddosProtectionService;
private final DistributedAttackMitigationService distributedAttackMitigationService;
private final MinecraftProtocolSecurityService minecraftProtocolSecurityService;
private final HostEnforcementService hostEnforcementService;
private final Map<String, SlowConnectionTracker> slowConnections = new ConcurrentHashMap<>();
private final ConcurrentLinkedQueue<DDoSIncidentSummary> incidents = new ConcurrentLinkedQueue<>();
public DDoSDefenseCoordinator() {
this(new ServerGuardConfig(), new DDoSProtectionService(), new DistributedAttackMitigationService(),
new MinecraftProtocolSecurityService(), new HostEnforcementService());
}
@Autowired
public DDoSDefenseCoordinator(ServerGuardConfig config,
DDoSProtectionService ddosProtectionService,
DistributedAttackMitigationService distributedAttackMitigationService,
MinecraftProtocolSecurityService minecraftProtocolSecurityService,
HostEnforcementService hostEnforcementService) {
this.config = config;
this.ddosProtectionService = ddosProtectionService;
this.distributedAttackMitigationService = distributedAttackMitigationService;
this.minecraftProtocolSecurityService = minecraftProtocolSecurityService;
this.hostEnforcementService = hostEnforcementService;
}
public List<DDoSIncidentSummary> analyzeTraffic(String sourceIP, String destIP, int sourcePort, int destPort,
String protocol, byte[] payload) {
if (!config.getSecurity().getDdosDefense().isEnabled()) {
return List.of();
}
List<DDoSIncidentSummary> result = new ArrayList<>();
int payloadSize = payload == null ? 0 : payload.length;
String normalizedProtocol = protocol == null ? "TCP" : protocol.toUpperCase(Locale.ROOT);
String payloadText = payload == null ? "" : new String(payload, StandardCharsets.UTF_8).toLowerCase(Locale.ROOT);
boolean allowed = ddosProtectionService.checkConnection(sourceIP);
if (!allowed) {
result.add(recordIncident(sourceIP, "L4", "CONNECTION_FLOOD", 90, "Connection flood threshold exceeded"));
}
ddosProtectionService.checkPacketSize(sourceIP, payloadSize);
ddosProtectionService.checkBandwidth(sourceIP, payloadSize);
if ("TCP".equals(normalizedProtocol)) {
ddosProtectionService.checkSynFlood(sourceIP);
} else if ("UDP".equals(normalizedProtocol)) {
ddosProtectionService.checkUDPAmplification(sourceIP, payloadSize);
} else if ("ICMP".equals(normalizedProtocol)) {
ddosProtectionService.checkICMPFlood(sourceIP);
}
if (containsHttpTraffic(payloadText)) {
boolean httpAllowed = ddosProtectionService.checkHTTPFlood(sourceIP, detectUserAgent(payloadText), detectPath(payloadText));
if (!httpAllowed) {
result.add(recordIncident(sourceIP, "L7", "HTTP_FLOOD", 88, "HTTP flood threshold exceeded"));
}
}
SlowConnectionTracker tracker = slowConnections.computeIfAbsent(sourceIP, SlowConnectionTracker::new);
tracker.record(payloadSize);
if (tracker.isSlowConnection(config.getSecurity().getDdosDefense().getSlowConnectionThreshold())) {
result.add(recordIncident(sourceIP, "L7", "SLOW_CONNECTION", 70, "Slow connection pattern detected"));
}
for (MinecraftProtocolSecurityService.MinecraftThreatSignal signal : minecraftProtocolSecurityService.analyzePacket(
sourceIP, destIP, sourcePort, destPort, payload)) {
String category = signal.getType().contains("RCON") ? "MINECRAFT-RCON" : "MINECRAFT";
result.add(recordIncident(sourceIP, category, signal.getType(), signal.getConfidence(), signal.getDetails()));
}
Map<String, Object> trafficData = new HashMap<>();
trafficData.put("packetPattern", buildPacketPattern(normalizedProtocol, payloadText));
trafficData.put("requestPattern", payloadText);
trafficData.put("flags", normalizedProtocol);
distributedAttackMitigationService.analyzeTraffic(sourceIP, trafficData);
if (ddosProtectionService.isBlocked(sourceIP)) {
hostEnforcementService.blockIp(sourceIP, "DDoS coordinator escalation", config.getSecurity().getHostEnforcement().getDefaultBlockMinutes());
}
trimIncidentLog();
return result;
}
public Map<String, Object> getPosture() {
Map<String, Object> ddosStats = ddosProtectionService.getStats();
Map<String, Object> mitigationStats = distributedAttackMitigationService.getStats();
Map<String, Object> minecraftPosture = minecraftProtocolSecurityService.getPosture();
Map<String, Object> posture = new LinkedHashMap<>();
posture.put("blockedIPs", ddosStats.getOrDefault("blockedIPs", 0));
posture.put("totalDetected", ddosStats.getOrDefault("totalDetected", 0));
posture.put("totalBlocked", ddosStats.getOrDefault("totalBlocked", 0));
posture.put("activeIncidents", incidents.size());
posture.put("mitigatedIncidents", mitigationStats.getOrDefault("totalAttacksMitigated", 0));
posture.put("defenseLevel", mitigationStats.getOrDefault("currentDefenseLevel", "LOW"));
posture.put("minecraftThreats", minecraftPosture.getOrDefault("recentSignals", 0));
posture.put("botSwarmSources", minecraftPosture.getOrDefault("botSwarmSources", 0));
posture.put("recentIncidents", getRecentIncidents(5));
return posture;
}
public List<DDoSIncidentSummary> getRecentIncidents(int limit) {
List<DDoSIncidentSummary> result = new ArrayList<>();
int count = 0;
for (DDoSIncidentSummary incident : incidents) {
if (count++ >= limit) {
break;
}
result.add(incident);
}
result.sort(Comparator.comparingLong(DDoSIncidentSummary::getTimestamp).reversed());
return result;
}
public List<DDoSIncidentSummary> getIncidentsForIp(String ip, int limit) {
List<DDoSIncidentSummary> result = new ArrayList<>();
for (DDoSIncidentSummary incident : getRecentIncidents(200)) {
if (ip.equals(incident.getSourceIP())) {
result.add(incident);
if (result.size() >= limit) {
break;
}
}
}
return result;
}
private DDoSIncidentSummary recordIncident(String sourceIP, String layer, String type, int severity, String details) {
DDoSIncidentSummary incident = new DDoSIncidentSummary(sourceIP, layer, type, severity, details, Instant.now().toEpochMilli());
incidents.offer(incident);
return incident;
}
private void trimIncidentLog() {
while (incidents.size() > 1000) {
incidents.poll();
}
}
private boolean containsHttpTraffic(String payload) {
return payload.startsWith("get ") || payload.startsWith("post ") || payload.contains(" http/1.");
}
private String detectUserAgent(String payload) {
int index = payload.indexOf("user-agent:");
if (index < 0) {
return "unknown";
}
int end = payload.indexOf('\n', index);
return end > index ? payload.substring(index, end).trim() : payload.substring(index).trim();
}
private String detectPath(String payload) {
if (payload.startsWith("get ") || payload.startsWith("post ")) {
String[] parts = payload.split(" ");
if (parts.length > 1) {
return parts[1];
}
}
return "/";
}
private String buildPacketPattern(String protocol, String payloadText) {
if (payloadText.contains("rcon")) {
return "RCON failed repeated";
}
if (payloadText.contains("status") || payloadText.contains("ping")) {
return "MINECRAFT status flood";
}
if (payloadText.contains("login")) {
return "MINECRAFT login flood";
}
if ("UDP".equals(protocol) && payloadText.length() > 1024) {
return "UDP flood";
}
return protocol + " traffic";
}
private static final class SlowConnectionTracker {
private final String sourceIP;
private final List<Entry> entries = new ArrayList<>();
private SlowConnectionTracker(String sourceIP) {
this.sourceIP = sourceIP;
}
private void record(int size) {
long now = System.currentTimeMillis();
entries.removeIf(entry -> entry.timestamp < now - WINDOW_MS);
entries.add(new Entry(now, size));
}
private boolean isSlowConnection(int threshold) {
if (entries.size() < threshold) {
return false;
}
long smallPackets = entries.stream().filter(entry -> entry.size < 64).count();
return smallPackets > entries.size() * 0.7;
}
private record Entry(long timestamp, int size) {
}
}
public static class DDoSIncidentSummary {
private final String sourceIP;
private final String layer;
private final String type;
private final int severity;
private final String details;
private final long timestamp;
public DDoSIncidentSummary(String sourceIP, String layer, String type, int severity, String details, long timestamp) {
this.sourceIP = sourceIP;
this.layer = layer;
this.type = type;
this.severity = severity;
this.details = details;
this.timestamp = timestamp;
}
public String getSourceIP() { return sourceIP; }
public String getLayer() { return layer; }
public String getType() { return type; }
public int getSeverity() { return severity; }
public String getDetails() { return details; }
public long getTimestamp() { return timestamp; }
}
}
@@ -0,0 +1,438 @@
package com.aluer.security;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.net.*;
import java.nio.*;
@Service
public class DDoSProtectionService {
private final Map<String, TrafficRecord> trafficMap = new ConcurrentHashMap<>();
private final Map<String, BlockedIP> blockedIPs = new ConcurrentHashMap<>();
private final Map<String, List<Long>> requestTimestamps = new ConcurrentHashMap<>();
private final Map<String, AtomicInteger> connectionCounts = new ConcurrentHashMap<>();
private final Queue<AttackEvent> attackLog = new ConcurrentLinkedQueue<>();
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
private static final int MAX_REQUESTS_PER_SECOND = 100;
private static final int MAX_CONNECTIONS_PER_IP = 50;
private static final long BLOCK_DURATION = 300000;
private static final long TRAFFIC_WINDOW = 1000;
private static final int MAX_PACKET_SIZE = 65535;
private static final double MAX_BYTES_PER_SECOND = 100_000_000;
private final AtomicLong totalBlocked = new AtomicLong(0);
private final AtomicLong totalDetected = new AtomicLong(0);
public DDoSProtectionService() {
startCleanupTask();
}
public boolean checkConnection(String ip) {
if (isBlocked(ip)) {
logAttack(ip, "BLOCKED_CONNECTION", "Connection from blocked IP");
return false;
}
AtomicInteger count = connectionCounts.computeIfAbsent(ip, k -> new AtomicInteger(0));
int current = count.incrementAndGet();
if (current > MAX_CONNECTIONS_PER_IP) {
blockIP(ip, "CONNECTION_FLOOD", "Too many connections: " + current);
return false;
}
return true;
}
public boolean checkRequest(String ip, String endpoint) {
if (isBlocked(ip)) {
return false;
}
List<Long> timestamps = requestTimestamps.computeIfAbsent(ip + ":" + endpoint, k -> new CopyOnWriteArrayList<>());
long now = System.currentTimeMillis();
timestamps.removeIf(t -> now - t > TRAFFIC_WINDOW);
timestamps.add(now);
if (timestamps.size() > MAX_REQUESTS_PER_SECOND) {
blockIP(ip, "REQUEST_FLOOD", "Too many requests: " + timestamps.size());
return false;
}
return true;
}
public boolean checkPacketSize(String ip, int size) {
if (isBlocked(ip)) {
return false;
}
if (size > MAX_PACKET_SIZE) {
blockIP(ip, "OVERSIZED_PACKET", "Packet size: " + size);
return false;
}
return true;
}
public boolean checkBandwidth(String ip, long bytes) {
if (isBlocked(ip)) {
return false;
}
TrafficRecord record = trafficMap.computeIfAbsent(ip, k -> new TrafficRecord(ip));
record.addBytes(bytes);
if (record.getBytesPerSecond() > MAX_BYTES_PER_SECOND) {
blockIP(ip, "BANDWIDTH_EXCEED", "Bandwidth: " + record.getBytesPerSecond());
return false;
}
return true;
}
public boolean checkPort(String ip, int port) {
if (isBlocked(ip)) {
return false;
}
Set<Integer> scannedPorts = recordPortScan(ip, port);
if (scannedPorts.size() > 20) {
blockIP(ip, "PORT_SCAN", "Scanned " + scannedPorts.size() + " ports");
return false;
}
return true;
}
private Set<Integer> recordPortScan(String ip, int port) {
Map<Integer, Long> portScans = portScanMap.computeIfAbsent(ip, k -> new ConcurrentHashMap<>());
long now = System.currentTimeMillis();
portScans.entrySet().removeIf(e -> now - e.getValue() > 60000);
portScans.put(port, now);
return portScans.keySet();
}
private final Map<String, Map<Integer, Long>> portScanMap = new ConcurrentHashMap<>();
public boolean checkSynFlood(String ip) {
if (isBlocked(ip)) {
return false;
}
AtomicInteger synCount = synCountMap.computeIfAbsent(ip, k -> new AtomicInteger(0));
int count = synCount.incrementAndGet();
if (count > 100) {
blockIP(ip, "SYN_FLOOD", "SYN packets: " + count);
return false;
}
return true;
}
private final Map<String, AtomicInteger> synCountMap = new ConcurrentHashMap<>();
public boolean checkFragmentation(String ip, short identification, int offset) {
if (isBlocked(ip)) {
return false;
}
FragmentRecord frag = fragmentationMap.computeIfAbsent(ip, k -> new FragmentRecord());
if (frag.addFragment(identification, offset)) {
blockIP(ip, "FRAGMENTATION_ATTACK", "Too many fragments");
return false;
}
return true;
}
private final Map<String, FragmentRecord> fragmentationMap = new ConcurrentHashMap<>();
public boolean checkUDPAmplification(String ip, int payloadSize) {
if (isBlocked(ip)) {
return false;
}
AtomicInteger udpCount = udpAmplificationMap.computeIfAbsent(ip, k -> new AtomicInteger(0));
int count = udpCount.incrementAndGet();
if (count > 50 && payloadSize > 1000) {
blockIP(ip, "UDP_AMPLIFICATION", "Large UDP packets: " + count);
return false;
}
return true;
}
private final Map<String, AtomicInteger> udpAmplificationMap = new ConcurrentHashMap<>();
public boolean checkICMPFlood(String ip) {
if (isBlocked(ip)) {
return false;
}
AtomicInteger icmpCount = icmpFloodMap.computeIfAbsent(ip, k -> new AtomicInteger(0));
int count = icmpCount.incrementAndGet();
if (count > 50) {
blockIP(ip, "ICMP_FLOOD", "ICMP packets: " + count);
return false;
}
return true;
}
private final Map<String, AtomicInteger> icmpFloodMap = new ConcurrentHashMap<>();
public boolean checkHTTPFlood(String ip, String userAgent, String path) {
if (isBlocked(ip)) {
return false;
}
List<String> paths = httpFloodMap.computeIfAbsent(ip, k -> new CopyOnWriteArrayList<>());
long now = System.currentTimeMillis();
paths.add(now + ":" + path);
paths.removeIf(p -> Long.parseLong(p.split(":")[0]) < now - 10000);
Map<String, Integer> pathCounts = new HashMap<>();
for (String p : paths) {
String pathOnly = p.split(":")[1];
pathCounts.merge(pathOnly, 1, Integer::sum);
}
String problematicPath = null;
for (Map.Entry<String, Integer> entry : pathCounts.entrySet()) {
if (entry.getValue() > 30) {
problematicPath = entry.getKey();
blockIP(ip, "HTTP_FLOOD", "Path " + problematicPath + " hit " + entry.getValue() + " times");
return false;
}
}
if (isKnownBot(userAgent)) {
return true;
}
if (paths.size() > 200) {
blockIP(ip, "HTTP_FLOOD", "Too many requests");
return false;
}
return true;
}
private final Map<String, List<String>> httpFloodMap = new ConcurrentHashMap<>();
private boolean isKnownBot(String userAgent) {
if (userAgent == null) return false;
String lower = userAgent.toLowerCase();
return lower.contains("googlebot") || lower.contains("bingbot") ||
lower.contains("slurp") || lower.contains("duckduckbot");
}
public boolean checkSSLHandshake(String ip) {
if (isBlocked(ip)) {
return false;
}
AtomicInteger handshakeCount = sslHandshakeMap.computeIfAbsent(ip, k -> new AtomicInteger(0));
int count = handshakeCount.incrementAndGet();
if (count > 30) {
blockIP(ip, "SSL_FLOOD", "SSL handshakes: " + count);
return false;
}
return true;
}
private final Map<String, AtomicInteger> sslHandshakeMap = new ConcurrentHashMap<>();
public void blockIP(String ip, String reason, String details) {
if (blockedIPs.containsKey(ip)) {
BlockedIP existing = blockedIPs.get(ip);
existing.count.incrementAndGet();
existing.lastBlockTime = System.currentTimeMillis();
} else {
BlockedIP blocked = new BlockedIP(ip, reason, details);
blockedIPs.put(ip, blocked);
totalBlocked.incrementAndGet();
}
logAttack(ip, reason, details);
}
public void unblockIP(String ip) {
blockedIPs.remove(ip);
trafficMap.remove(ip);
requestTimestamps.entrySet().removeIf(e -> e.getKey().startsWith(ip));
connectionCounts.remove(ip);
}
public boolean isBlocked(String ip) {
BlockedIP blocked = blockedIPs.get(ip);
if (blocked == null) {
return false;
}
if (System.currentTimeMillis() - blocked.lastBlockTime > BLOCK_DURATION) {
unblockIP(ip);
return false;
}
return true;
}
public BlockedIP getBlockInfo(String ip) {
return blockedIPs.get(ip);
}
public Collection<BlockedIP> getAllBlockedIPs() {
return blockedIPs.values();
}
public void logAttack(String ip, String type, String details) {
AttackEvent event = new AttackEvent(ip, type, details, System.currentTimeMillis());
attackLog.offer(event);
totalDetected.incrementAndGet();
while (attackLog.size() > 10000) {
attackLog.poll();
}
}
public List<AttackEvent> getAttackLog(int limit) {
List<AttackEvent> result = new ArrayList<>();
int count = 0;
for (AttackEvent event : attackLog) {
if (count++ >= limit) break;
result.add(event);
}
return result;
}
private void startCleanupTask() {
scheduler.scheduleAtFixedRate(() -> {
long now = System.currentTimeMillis();
for (Map.Entry<String, BlockedIP> entry : blockedIPs.entrySet()) {
if (now - entry.getValue().lastBlockTime > BLOCK_DURATION) {
unblockIP(entry.getKey());
}
}
trafficMap.entrySet().removeIf(e -> e.getValue().isStale());
requestTimestamps.entrySet().removeIf(e -> {
List<Long> list = e.getValue();
list.removeIf(t -> now - t > TRAFFIC_WINDOW);
return list.isEmpty();
});
connectionCounts.entrySet().removeIf(e -> e.getValue().get() == 0);
synCountMap.entrySet().removeIf(e -> e.getValue().get() == 0);
icmpFloodMap.entrySet().removeIf(e -> e.getValue().get() == 0);
udpAmplificationMap.entrySet().removeIf(e -> e.getValue().get() == 0);
}, 30, 30, TimeUnit.SECONDS);
}
public Map<String, Object> getStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("blockedIPs", blockedIPs.size());
stats.put("totalBlocked", totalBlocked.get());
stats.put("totalDetected", totalDetected.get());
stats.put("activeTrafficRecords", trafficMap.size());
return stats;
}
public static class TrafficRecord {
private final String ip;
private final AtomicLong totalBytes = new AtomicLong(0);
private final AtomicLong windowBytes = new AtomicLong(0);
private volatile long lastUpdate = System.currentTimeMillis();
public TrafficRecord(String ip) {
this.ip = ip;
}
public void addBytes(long bytes) {
long now = System.currentTimeMillis();
if (now - lastUpdate > 1000) {
windowBytes.set(bytes);
lastUpdate = now;
} else {
windowBytes.addAndGet(bytes);
}
totalBytes.addAndGet(bytes);
}
public long getBytesPerSecond() {
return windowBytes.get();
}
public long getTotalBytes() {
return totalBytes.get();
}
public boolean isStale() {
return System.currentTimeMillis() - lastUpdate > 60000;
}
}
public static class BlockedIP {
public final String ip;
public final String reason;
public final String details;
public final long firstBlockTime;
public volatile long lastBlockTime;
public final AtomicInteger count = new AtomicInteger(1);
public BlockedIP(String ip, String reason, String details) {
this.ip = ip;
this.reason = reason;
this.details = details;
this.firstBlockTime = System.currentTimeMillis();
this.lastBlockTime = System.currentTimeMillis();
}
}
public static class AttackEvent {
public final String ip;
public final String type;
public final String details;
public final long timestamp;
public AttackEvent(String ip, String type, String details, long timestamp) {
this.ip = ip;
this.type = type;
this.details = details;
this.timestamp = timestamp;
}
}
public static class FragmentRecord {
private final Map<Short, Set<Integer>> fragments = new ConcurrentHashMap<>();
public synchronized boolean addFragment(short identification, int offset) {
Set<Integer> offsets = fragments.computeIfAbsent(identification, k -> ConcurrentHashMap.newKeySet());
offsets.add(offset);
if (offsets.size() > 100) {
fragments.remove(identification);
return true;
}
return false;
}
}
}
@@ -0,0 +1,423 @@
package com.aluer.security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicLong;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.net.InetAddress;
@Component
public class DNSSecurityService {
private static final Logger logger = LoggerFactory.getLogger(DNSSecurityService.class);
private final Map<String, DNSQueryRecord> queryCache = new ConcurrentHashMap<>();
private final Map<String, List<ClientQueryHistory>> clientQueryHistory = new ConcurrentHashMap<>();
private final Map<String, DNSZone> zones = new ConcurrentHashMap<>();
private final Queue<DNSEvent> eventLog = new ConcurrentLinkedQueue<>();
private final AtomicLong totalQueries = new AtomicLong(0);
private final AtomicLong blockedQueries = new AtomicLong(0);
private final AtomicLong suspiciousQueries = new AtomicLong(0);
private static final int MAX_QUERIES_PER_MINUTE = 60;
private static final int MAX_QUERIES_PER_HOUR = 1000;
private static final int CACHE_TTL_SECONDS = 300;
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
private final Set<String> blockedDomains = new HashSet<>(Arrays.asList(
"malware.com", "phishing.com", "ransomware.com", "trojan.com",
"coinminer.com", "adservice.com", "tracker.com", "spyware.com"
));
private final Set<String> suspiciousTLDs = new HashSet<>(Arrays.asList(
".tk", ".ml", ".ga", ".cf", ".gq", ".xyz", ".top", ".work"
));
public DNSSecurityService() {
initializeDefaultZones();
}
private void initializeDefaultZones() {
DNSZone minecraftZone = new DNSZone("minecraft");
minecraftZone.addRecord("auth.mojang.com", "13.107.42.20");
minecraftZone.addRecord("sessionserver.mojang.com", "13.107.42.20");
minecraftZone.addRecord("api.mojang.com", "13.107.42.20");
minecraftZone.addRecord("textures.minecraft.net", "13.107.42.20");
zones.put("minecraft", minecraftZone);
DNSZone localZone = new DNSZone("local");
localZone.addRecord("localhost", "127.0.0.1");
zones.put("local", localZone);
}
public DNSQueryResult processQuery(String clientIP, String domainName, int queryType) {
DNSQueryResult result = new DNSQueryResult();
result.setClientIP(clientIP);
result.setDomainName(domainName);
result.setQueryType(queryType);
result.setTimestamp(LocalDateTime.now());
totalQueries.incrementAndGet();
if (isRateLimited(clientIP)) {
result.setBlocked(true);
result.setReason("Rate limit exceeded");
blockedQueries.incrementAndGet();
logEvent(clientIP, domainName, "BLOCKED", "Rate limit exceeded");
return result;
}
if (isDomainBlocked(domainName)) {
result.setBlocked(true);
result.setReason("Blocked domain");
result.setBlocked(true);
blockedQueries.incrementAndGet();
logEvent(clientIP, domainName, "BLOCKED", "Blocked domain");
return result;
}
if (isSuspiciousDomain(domainName)) {
result.setSuspicious(true);
result.setWarning("Suspicious TLD or pattern");
suspiciousQueries.incrementAndGet();
logEvent(clientIP, domainName, "SUSPICIOUS", "Suspicious domain pattern");
}
if (isDNSSplitTunneling(clientIP, domainName)) {
result.setSuspicious(true);
result.setWarning("Possible DNS tunnel detected");
suspiciousQueries.incrementAndGet();
logEvent(clientIP, domainName, "SUSPICIOUS", "Possible DNS tunnel");
}
DNSQueryRecord record = new DNSQueryRecord(clientIP, domainName, queryType, LocalDateTime.now());
queryCache.put(domainName + ":" + clientIP, record);
List<ClientQueryHistory> history = clientQueryHistory.computeIfAbsent(clientIP, k -> new ArrayList<>());
history.add(new ClientQueryHistory(domainName, LocalDateTime.now()));
if (history.size() > 1000) {
history.subList(0, 500).clear();
}
String resolvedIP = resolveDomain(domainName);
result.setResolvedIP(resolvedIP);
result.setBlocked(false);
logEvent(clientIP, domainName, "ALLOWED", "Query allowed");
return result;
}
private boolean isRateLimited(String clientIP) {
List<ClientQueryHistory> history = clientQueryHistory.get(clientIP);
if (history == null) return false;
LocalDateTime oneMinuteAgo = LocalDateTime.now().minusMinutes(1);
long queriesLastMinute = history.stream()
.filter(q -> q.getTimestamp().isAfter(oneMinuteAgo))
.count();
if (queriesLastMinute > MAX_QUERIES_PER_MINUTE) {
return true;
}
LocalDateTime oneHourAgo = LocalDateTime.now().minusHours(1);
long queriesLastHour = history.stream()
.filter(q -> q.getTimestamp().isAfter(oneHourAgo))
.count();
return queriesLastHour > MAX_QUERIES_PER_HOUR;
}
private boolean isDomainBlocked(String domainName) {
String lowerDomain = domainName.toLowerCase();
for (String blocked : blockedDomains) {
if (lowerDomain.endsWith(blocked) || lowerDomain.equals(blocked)) {
return true;
}
}
return false;
}
private boolean isSuspiciousDomain(String domainName) {
String lowerDomain = domainName.toLowerCase();
for (String tld : suspiciousTLDs) {
if (lowerDomain.endsWith(tld)) {
return true;
}
}
if (lowerDomain.length() > 50) {
return true;
}
int dots = lowerDomain.split("\\.").length - 1;
if (dots > 5) {
return true;
}
if (lowerDomain.contains("----") || lowerDomain.contains("----")) {
return true;
}
return false;
}
private boolean isDNSSplitTunneling(String clientIP, String domainName) {
List<ClientQueryHistory> history = clientQueryHistory.get(clientIP);
if (history == null || history.size() < 10) return false;
LocalDateTime recent = LocalDateTime.now().minusMinutes(5);
long recentQueries = history.stream()
.filter(q -> q.getTimestamp().isAfter(recent))
.count();
if (recentQueries < 100) return false;
Set<String> uniqueDomains = history.stream()
.filter(q -> q.getTimestamp().isAfter(recent))
.map(ClientQueryHistory::getDomain)
.collect(java.util.stream.Collectors.toSet());
double entropy = calculateEntropy(String.join(".", uniqueDomains));
return entropy > 4.5;
}
private double calculateEntropy(String data) {
if (data == null || data.isEmpty()) return 0;
Map<Character, Long> frequency = new HashMap<>();
for (char c : data.toCharArray()) {
frequency.merge(c, 1L, Long::sum);
}
double entropy = 0;
int length = data.length();
for (long count : frequency.values()) {
double probability = (double) count / length;
entropy -= probability * (Math.log(probability) / Math.log(2));
}
return entropy;
}
private String resolveDomain(String domainName) {
for (DNSZone zone : zones.values()) {
String ip = zone.resolve(domainName);
if (ip != null) {
return ip;
}
}
try {
InetAddress address = InetAddress.getByName(domainName);
return address.getHostAddress();
} catch (Exception e) {
return null;
}
}
public void addBlockedDomain(String domain) {
blockedDomains.add(domain.toLowerCase());
logger.info("Added blocked domain: {}", domain);
}
public void removeBlockedDomain(String domain) {
blockedDomains.remove(domain.toLowerCase());
logger.info("Removed blocked domain: {}", domain);
}
public void addZone(String zoneName, Map<String, String> records) {
DNSZone zone = new DNSZone(zoneName);
for (Map.Entry<String, String> entry : records.entrySet()) {
zone.addRecord(entry.getKey(), entry.getValue());
}
zones.put(zoneName, zone);
logger.info("Added DNS zone: {}", zoneName);
}
public Map<String, Object> getStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("totalQueries", totalQueries.get());
stats.put("blockedQueries", blockedQueries.get());
stats.put("suspiciousQueries", suspiciousQueries.get());
stats.put("cachedQueries", queryCache.size());
stats.put("activeClients", clientQueryHistory.size());
stats.put("zonesConfigured", zones.size());
stats.put("blockedDomains", blockedDomains.size());
return stats;
}
public Map<String, DNSQueryRecord> getRecentQueries(int limit) {
Map<String, DNSQueryRecord> recent = new LinkedHashMap<>();
int count = 0;
for (Map.Entry<String, DNSQueryRecord> entry : queryCache.entrySet()) {
if (count++ >= limit) break;
recent.put(entry.getKey(), entry.getValue());
}
return recent;
}
public List<String> getTopQueriedDomains(int limit) {
Map<String, Long> domainCounts = new HashMap<>();
for (DNSQueryRecord record : queryCache.values()) {
String domain = record.getDomainName();
domainCounts.merge(domain, 1L, Long::sum);
}
return domainCounts.entrySet().stream()
.sorted(Map.Entry.<String, Long>comparingByValue().reversed())
.limit(limit)
.map(Map.Entry::getKey)
.collect(java.util.stream.Collectors.toList());
}
public Map<String, Long> getClientQueryStats(String clientIP) {
List<ClientQueryHistory> history = clientQueryHistory.get(clientIP);
if (history == null) {
return new HashMap<>();
}
Map<String, Long> stats = new HashMap<>();
stats.put("totalQueries", (long) history.size());
LocalDateTime oneMinuteAgo = LocalDateTime.now().minusMinutes(1);
long recentQueries = history.stream()
.filter(q -> q.getTimestamp().isAfter(oneMinuteAgo))
.count();
stats.put("queriesLastMinute", recentQueries);
return stats;
}
private void logEvent(String clientIP, String domain, String eventType, String details) {
DNSEvent event = new DNSEvent(clientIP, domain, eventType, details, LocalDateTime.now());
eventLog.offer(event);
if (eventLog.size() > 5000) {
eventLog.poll();
}
}
public List<DNSEvent> getRecentEvents(int limit) {
List<DNSEvent> events = new ArrayList<>();
int count = 0;
for (DNSEvent event : eventLog) {
if (count++ >= limit) break;
events.add(event);
}
return events;
}
public static class DNSQueryResult {
private String clientIP;
private String domainName;
private int queryType;
private String resolvedIP;
private boolean blocked;
private boolean suspicious;
private String reason;
private String warning;
private LocalDateTime timestamp;
public String getClientIP() { return clientIP; }
public void setClientIP(String clientIP) { this.clientIP = clientIP; }
public String getDomainName() { return domainName; }
public void setDomainName(String domainName) { this.domainName = domainName; }
public int getQueryType() { return queryType; }
public void setQueryType(int queryType) { this.queryType = queryType; }
public String getResolvedIP() { return resolvedIP; }
public void setResolvedIP(String resolvedIP) { this.resolvedIP = resolvedIP; }
public boolean isBlocked() { return blocked; }
public void setBlocked(boolean blocked) { this.blocked = blocked; }
public boolean isSuspicious() { return suspicious; }
public void setSuspicious(boolean suspicious) { this.suspicious = suspicious; }
public String getReason() { return reason; }
public void setReason(String reason) { this.reason = reason; }
public String getWarning() { return warning; }
public void setWarning(String warning) { this.warning = warning; }
public LocalDateTime getTimestamp() { return timestamp; }
public void setTimestamp(LocalDateTime timestamp) { this.timestamp = timestamp; }
}
public static class DNSQueryRecord {
private final String clientIP;
private final String domainName;
private final int queryType;
private final LocalDateTime timestamp;
public DNSQueryRecord(String clientIP, String domainName, int queryType, LocalDateTime timestamp) {
this.clientIP = clientIP;
this.domainName = domainName;
this.queryType = queryType;
this.timestamp = timestamp;
}
public String getClientIP() { return clientIP; }
public String getDomainName() { return domainName; }
public int getQueryType() { return queryType; }
public LocalDateTime getTimestamp() { return timestamp; }
}
public static class DNSZone {
private final String name;
private final Map<String, String> records = new HashMap<>();
public DNSZone(String name) {
this.name = name;
}
public void addRecord(String domain, String ip) {
records.put(domain.toLowerCase(), ip);
}
public String resolve(String domain) {
return records.get(domain.toLowerCase());
}
public String getName() { return name; }
public Map<String, String> getRecords() { return records; }
}
public static class ClientQueryHistory {
private final String domain;
private final LocalDateTime timestamp;
public ClientQueryHistory(String domain, LocalDateTime timestamp) {
this.domain = domain;
this.timestamp = timestamp;
}
public String getDomain() { return domain; }
public LocalDateTime getTimestamp() { return timestamp; }
}
public static class DNSEvent {
private final String clientIP;
private final String domain;
private final String eventType;
private final String details;
private final LocalDateTime timestamp;
public DNSEvent(String clientIP, String domain, String eventType, String details, LocalDateTime timestamp) {
this.clientIP = clientIP;
this.domain = domain;
this.eventType = eventType;
this.details = details;
this.timestamp = timestamp;
}
public String getClientIP() { return clientIP; }
public String getDomain() { return domain; }
public String getEventType() { return eventType; }
public String getDetails() { return details; }
public LocalDateTime getTimestamp() { return timestamp; }
}
}
@@ -0,0 +1,479 @@
package com.aluer.security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicLong;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@Component
public class DistributedAttackMitigationService {
private static final Logger logger = LoggerFactory.getLogger(DistributedAttackMitigationService.class);
private final Map<String, AttackSignature> attackSignatures = new ConcurrentHashMap<>();
private final Map<String, MitigationRule> mitigationRules = new ConcurrentHashMap<>();
private final Map<String, AttackIncident> activeIncidents = new ConcurrentHashMap<>();
private final Queue<MitigationEvent> eventLog = new ConcurrentLinkedQueue<>();
private final Map<String, List<AttackVector>> attackVectors = new ConcurrentHashMap<>();
private final AtomicLong totalAttacksDetected = new AtomicLong(0);
private final AtomicLong totalAttacksMitigated = new AtomicLong(0);
private final AtomicLong totalAttacksBlocked = new AtomicLong(0);
private volatile boolean mitigationEnabled = true;
private String currentDefenseLevel = "MEDIUM";
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
private static final int MAX_INCIDENTS = 1000;
private static final int DEFENSE_LEVEL_HIGH_THRESHOLD = 100;
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public DistributedAttackMitigationService() {
initializeDefaultSignatures();
initializeDefaultRules();
startAutoMitigation();
logger.info("Distributed Attack Mitigation Service initialized");
}
private void initializeDefaultSignatures() {
addSignature("SYN_FLOOD", "DDoS", "SYN.*SYN.*SYN", 80, "SYN flood attack");
addSignature("UDP_FLOOD", "DDoS", "UDP.*flood", 90, "UDP flood attack");
addSignature("ICMP_FLOOD", "DDoS", "ICMP.*flood", 70, "ICMP flood attack");
addSignature("HTTP_FLOOD", "DDoS", "GET.*repeated|POST.*repeated", 85, "HTTP flood attack");
addSignature("DNS_AMPLIFICATION", "DDoS", "DNS.*amplification", 95, "DNS amplification attack");
addSignature("NTP_AMPLIFICATION", "DDoS", "NTP.*amplification", 95, "NTP amplification attack");
addSignature("SSDP_AMPLIFICATION", "DDoS", "SSDP.*amplification", 90, "SSDP amplification attack");
addSignature("SLOWLORIS", "DDoS", "slow.*loris|partial.*request", 75, "Slowloris attack");
addSignature("HTTP_PIPELINING", "DDoS", "pipelining.*abuse", 70, "HTTP pipelining attack");
addSignature("BOTNET_ACTIVITY", "DDoS", "botnet.*detected", 90, "Botnet activity detected");
addSignature("BRUTE_FORCE_SSH", "BruteForce", "SSH.*failed.*repeated", 85, "SSH brute force attack");
addSignature("BRUTE_FORCE_FTP", "BruteForce", "FTP.*failed.*repeated", 85, "FTP brute force attack");
addSignature("BRUTE_FORCE_RCON", "BruteForce", "RCON.*failed.*repeated", 90, "RCON brute force attack");
addSignature("SQL_INJECTION", "Injection", "union.*select|insert.*into", 95, "SQL injection attack");
addSignature("XSS_ATTACK", "Injection", "<script|javascript:", 90, "Cross-site scripting attack");
addSignature("CSRF_ATTACK", "Injection", "CSRF.*token", 80, "CSRF attack");
addSignature("COMMAND_INJECTION", "Injection", "cmd\\.exe|/bin/bash", 95, "Command injection attack");
addSignature("PATH_TRAVERSAL", "Injection", "\\.\\./|\\.\\.\\\\", 85, "Path traversal attack");
addSignature("DISTRIBUTED_SCAN", "Reconnaissance", "port.*scan.*distributed", 75, "Distributed port scan");
addSignature("CRAWLER_ABUSE", "Reconnaissance", "crawler.*abuse|scraping", 60, "Web crawler abuse");
logger.info("Initialized {} attack signatures", attackSignatures.size());
}
private void initializeDefaultRules() {
addMitigationRule("BLOCK_SYN_FLOOD", "SYN_FLOOD", "BLOCK", 50, 60);
addMitigationRule("RATE_LIMIT_UDP", "UDP_FLOOD", "RATE_LIMIT", 100, 30);
addMitigationRule("BLOCK_ICMP", "ICMP_FLOOD", "BLOCK", 100, 60);
addMitigationRule("RATE_LIMIT_HTTP", "HTTP_FLOOD", "RATE_LIMIT", 50, 10);
addMitigationRule("DROP_DNS_AMP", "DNS_AMPLIFICATION", "BLOCK", 100, 300);
addMitigationRule("BLOCK_NTP_AMP", "NTP_AMPLIFICATION", "BLOCK", 100, 300);
addMitigationRule("THROTTLE_SLOWLORIS", "SLOWLORIS", "THROTTLE", 30, 60);
addMitigationRule("BLOCK_BOTNET", "BOTNET_ACTIVITY", "BLOCK", 100, 600);
addMitigationRule("BLOCK_SSH_BRUTE", "BRUTE_FORCE_SSH", "BLOCK", 10, 3600);
addMitigationRule("BLOCK_FTP_BRUTE", "BRUTE_FORCE_FTP", "BLOCK", 10, 3600);
addMitigationRule("BLOCK_RCON_BRUTE", "BRUTE_FORCE_RCON", "BLOCK", 5, 3600);
addMitigationRule("SANITIZE_SQL", "SQL_INJECTION", "SANITIZE", 100, 0);
addMitigationRule("SANITIZE_XSS", "XSS_ATTACK", "SANITIZE", 100, 0);
addMitigationRule("BLOCK_CMD_INJECTION", "COMMAND_INJECTION", "BLOCK", 100, 0);
addMitigationRule("BLOCK_TRAVERSAL", "PATH_TRAVERSAL", "BLOCK", 100, 0);
logger.info("Initialized {} mitigation rules", mitigationRules.size());
}
private void addSignature(String id, String type, String pattern, int severity, String description) {
AttackSignature sig = new AttackSignature(id, type, pattern, severity, description);
attackSignatures.put(id, sig);
}
private void addMitigationRule(String name, String signatureId, String action, int threshold, int duration) {
MitigationRule rule = new MitigationRule(name, signatureId, action, threshold, duration);
mitigationRules.put(name, rule);
}
public void analyzeTraffic(String sourceIP, Map<String, Object> trafficData) {
if (!mitigationEnabled) return;
for (AttackSignature signature : attackSignatures.values()) {
if (matchesSignature(trafficData, signature)) {
handleAttackDetection(sourceIP, signature, trafficData);
}
}
updateDefenseLevel();
}
private boolean matchesSignature(Map<String, Object> trafficData, AttackSignature signature) {
String pattern = signature.getPattern();
if (trafficData.containsKey("packetPattern")) {
String packetPattern = (String) trafficData.get("packetPattern");
if (packetPattern != null && packetPattern.matches(pattern)) {
return true;
}
}
if (trafficData.containsKey("requestPattern")) {
String requestPattern = (String) trafficData.get("requestPattern");
if (requestPattern != null && requestPattern.matches(pattern)) {
return true;
}
}
if (trafficData.containsKey("flags")) {
String flags = (String) trafficData.get("flags");
if (flags != null && flags.matches(pattern)) {
return true;
}
}
return false;
}
private void handleAttackDetection(String sourceIP, AttackSignature signature, Map<String, Object> trafficData) {
totalAttacksDetected.incrementAndGet();
String incidentId = UUID.randomUUID().toString();
AttackIncident incident = new AttackIncident(
incidentId,
sourceIP,
signature.getId(),
signature.getType(),
signature.getSeverity(),
trafficData,
LocalDateTime.now()
);
activeIncidents.put(incidentId, incident);
List<AttackVector> vectors = attackVectors.computeIfAbsent(sourceIP, k -> new ArrayList<>());
vectors.add(new AttackVector(signature.getId(), System.currentTimeMillis()));
applyMitigation(sourceIP, signature);
if (activeIncidents.size() > MAX_INCIDENTS) {
String firstKey = activeIncidents.keySet().iterator().next();
activeIncidents.remove(firstKey);
}
logger.warn("Attack detected from {}: {} [{}]", sourceIP, signature.getDescription(), signature.getType());
}
private void applyMitigation(String sourceIP, AttackSignature signature) {
for (MitigationRule rule : mitigationRules.values()) {
if (rule.getSignatureId().equals(signature.getId())) {
switch (rule.getAction()) {
case "BLOCK":
applyBlock(sourceIP, rule.getDuration());
totalAttacksBlocked.incrementAndGet();
logEvent(sourceIP, signature.getId(), "BLOCKED", "Blocked by rule: " + rule.getName());
break;
case "RATE_LIMIT":
applyRateLimit(sourceIP, rule.getThreshold());
logEvent(sourceIP, signature.getId(), "RATE_LIMITED", "Rate limited by rule: " + rule.getName());
break;
case "SANITIZE":
applySanitization(sourceIP);
logEvent(sourceIP, signature.getId(), "SANITIZED", "Request sanitized");
break;
case "THROTTLE":
applyThrottling(sourceIP, rule.getThreshold());
logEvent(sourceIP, signature.getId(), "THROTTLED", "Connection throttled");
break;
}
totalAttacksMitigated.incrementAndGet();
logger.info("Applied mitigation for {}: {}", sourceIP, rule.getAction());
break;
}
}
}
private void applyBlock(String sourceIP, int duration) {
logger.info("Blocking IP: {} for {} seconds", sourceIP, duration);
}
private void applyRateLimit(String sourceIP, int threshold) {
logger.info("Applying rate limit to IP: {} (threshold: {})", sourceIP, threshold);
}
private void applySanitization(String sourceIP) {
logger.info("Applying request sanitization for IP: {}", sourceIP);
}
private void applyThrottling(String sourceIP, int threshold) {
logger.info("Throttling connection for IP: {} (threshold: {})", sourceIP, threshold);
}
private void updateDefenseLevel() {
int activeAttackCount = activeIncidents.size();
if (activeAttackCount > DEFENSE_LEVEL_HIGH_THRESHOLD * 2) {
if (!"HIGH".equals(currentDefenseLevel)) {
currentDefenseLevel = "HIGH";
logger.warn("Defense level raised to HIGH - {} active attacks", activeAttackCount);
}
} else if (activeAttackCount > DEFENSE_LEVEL_HIGH_THRESHOLD) {
if (!"MEDIUM".equals(currentDefenseLevel)) {
currentDefenseLevel = "MEDIUM";
logger.info("Defense level raised to MEDIUM - {} active attacks", activeAttackCount);
}
} else if (activeAttackCount < DEFENSE_LEVEL_HIGH_THRESHOLD / 2) {
if (!"LOW".equals(currentDefenseLevel)) {
currentDefenseLevel = "LOW";
logger.info("Defense level lowered to LOW - {} active attacks", activeAttackCount);
}
}
}
private void startAutoMitigation() {
scheduler.scheduleAtFixedRate(() -> {
cleanupOldIncidents();
analyzeAttackPatterns();
generateDefenseRecommendations();
}, 10, 10, TimeUnit.SECONDS);
}
private void cleanupOldIncidents() {
long cutoffTime = System.currentTimeMillis() - (3600000);
List<String> toRemove = new ArrayList<>();
for (Map.Entry<String, AttackIncident> entry : activeIncidents.entrySet()) {
if (entry.getValue().getDetectedAt().isBefore(LocalDateTime.now().minusHours(1))) {
toRemove.add(entry.getKey());
}
}
for (String id : toRemove) {
activeIncidents.remove(id);
}
for (Map.Entry<String, List<AttackVector>> entry : attackVectors.entrySet()) {
long recentCutoff = System.currentTimeMillis() - (300000);
entry.getValue().removeIf(v -> v.getTimestamp() < recentCutoff);
}
}
private void analyzeAttackPatterns() {
for (Map.Entry<String, List<AttackVector>> entry : attackVectors.entrySet()) {
List<AttackVector> vectors = entry.getValue();
if (vectors.size() > 10) {
Map<String, Long> typeCounts = new HashMap<>();
for (AttackVector v : vectors) {
typeCounts.merge(v.getSignatureId(), 1L, Long::sum);
}
for (Map.Entry<String, Long> typeEntry : typeCounts.entrySet()) {
if (typeEntry.getValue() > 5) {
logger.warn("Attack pattern detected from {}: {} attacks of type {} in 5 minutes",
entry.getKey(), typeEntry.getValue(), typeEntry.getKey());
}
}
}
}
}
private void generateDefenseRecommendations() {
if (activeIncidents.size() > 50) {
logger.warn("HIGH ATTACK VOLUME RECOMMENDATION: Consider enabling emergency defense mode");
}
Map<String, Long> typeCounts = new HashMap<>();
for (AttackIncident incident : activeIncidents.values()) {
typeCounts.merge(incident.getAttackType(), 1L, Long::sum);
}
for (Map.Entry<String, Long> entry : typeCounts.entrySet()) {
if (entry.getValue() > 20) {
logger.warn("DEFENSE RECOMMENDATION: High volume of {} attacks detected ({}), consider additional mitigation",
entry.getKey(), entry.getValue());
}
}
}
public Map<String, Object> getStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("mitigationEnabled", mitigationEnabled);
stats.put("defenseLevel", currentDefenseLevel);
stats.put("totalAttacksDetected", totalAttacksDetected.get());
stats.put("totalAttacksMitigated", totalAttacksMitigated.get());
stats.put("totalAttacksBlocked", totalAttacksBlocked.get());
stats.put("activeIncidents", activeIncidents.size());
stats.put("attackSignatures", attackSignatures.size());
stats.put("mitigationRules", mitigationRules.size());
double mitigationRate = totalAttacksDetected.get() > 0 ?
totalAttacksMitigated.get() * 100.0 / totalAttacksDetected.get() : 0;
stats.put("mitigationRate", String.format("%.2f%%", mitigationRate));
return stats;
}
public List<AttackIncident> getActiveIncidents(int limit) {
List<AttackIncident> incidents = new ArrayList<>();
int count = 0;
for (AttackIncident incident : activeIncidents.values()) {
if (count++ >= limit) break;
incidents.add(incident);
}
return incidents;
}
public Map<String, Long> getAttackTypeDistribution() {
Map<String, Long> distribution = new HashMap<>();
for (AttackIncident incident : activeIncidents.values()) {
distribution.merge(incident.getAttackType(), 1L, Long::sum);
}
return distribution;
}
public void enableMitigation() {
mitigationEnabled = true;
logger.info("Attack mitigation enabled");
}
public void disableMitigation() {
mitigationEnabled = false;
logger.info("Attack mitigation disabled");
}
public void setDefenseLevel(String level) {
this.currentDefenseLevel = level;
logger.info("Defense level set to: {}", level);
}
private void logEvent(String sourceIP, String signatureId, String action, String details) {
MitigationEvent event = new MitigationEvent(sourceIP, signatureId, action, details, LocalDateTime.now());
eventLog.offer(event);
if (eventLog.size() > 5000) {
eventLog.poll();
}
}
public List<MitigationEvent> getRecentEvents(int limit) {
List<MitigationEvent> events = new ArrayList<>();
int count = 0;
for (MitigationEvent event : eventLog) {
if (count++ >= limit) break;
events.add(event);
}
return events;
}
public static class AttackSignature {
private final String id;
private final String type;
private final String pattern;
private final int severity;
private final String description;
public AttackSignature(String id, String type, String pattern, int severity, String description) {
this.id = id;
this.type = type;
this.pattern = pattern;
this.severity = severity;
this.description = description;
}
public String getId() { return id; }
public String getType() { return type; }
public String getPattern() { return pattern; }
public int getSeverity() { return severity; }
public String getDescription() { return description; }
}
public static class MitigationRule {
private final String name;
private final String signatureId;
private final String action;
private final int threshold;
private final int duration;
public MitigationRule(String name, String signatureId, String action, int threshold, int duration) {
this.name = name;
this.signatureId = signatureId;
this.action = action;
this.threshold = threshold;
this.duration = duration;
}
public String getName() { return name; }
public String getSignatureId() { return signatureId; }
public String getAction() { return action; }
public int getThreshold() { return threshold; }
public int getDuration() { return duration; }
}
public static class AttackIncident {
private final String incidentId;
private final String sourceIP;
private final String signatureId;
private final String attackType;
private final int severity;
private final Map<String, Object> evidence;
private final LocalDateTime detectedAt;
public AttackIncident(String incidentId, String sourceIP, String signatureId, String attackType,
int severity, Map<String, Object> evidence, LocalDateTime detectedAt) {
this.incidentId = incidentId;
this.sourceIP = sourceIP;
this.signatureId = signatureId;
this.attackType = attackType;
this.severity = severity;
this.evidence = evidence;
this.detectedAt = detectedAt;
}
public String getIncidentId() { return incidentId; }
public String getSourceIP() { return sourceIP; }
public String getSignatureId() { return signatureId; }
public String getAttackType() { return attackType; }
public int getSeverity() { return severity; }
public Map<String, Object> getEvidence() { return evidence; }
public LocalDateTime getDetectedAt() { return detectedAt; }
}
public static class AttackVector {
private final String signatureId;
private final long timestamp;
public AttackVector(String signatureId, long timestamp) {
this.signatureId = signatureId;
this.timestamp = timestamp;
}
public String getSignatureId() { return signatureId; }
public long getTimestamp() { return timestamp; }
}
public static class MitigationEvent {
private final String sourceIP;
private final String signatureId;
private final String action;
private final String details;
private final LocalDateTime timestamp;
public MitigationEvent(String sourceIP, String signatureId, String action, String details, LocalDateTime timestamp) {
this.sourceIP = sourceIP;
this.signatureId = signatureId;
this.action = action;
this.details = details;
this.timestamp = timestamp;
}
public String getSourceIP() { return sourceIP; }
public String getSignatureId() { return signatureId; }
public String getAction() { return action; }
public String getDetails() { return details; }
public LocalDateTime getTimestamp() { return timestamp; }
}
}
@@ -0,0 +1,196 @@
package com.aluer.security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicLong;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.security.MessageDigest;
import java.util.Base64;
@Component
public class EncryptionService {
private static final Logger logger = LoggerFactory.getLogger(EncryptionService.class);
private final Map<String, String> encryptionKeys = new ConcurrentHashMap<>();
private final Map<String, EncryptionStats> stats = new ConcurrentHashMap<>();
private final Queue<EncryptionEvent> eventLog = new ConcurrentLinkedQueue<>();
private final AtomicLong totalEncryptions = new AtomicLong(0);
private final AtomicLong totalDecryptions = new AtomicLong(0);
private final AtomicLong totalFailures = new AtomicLong(0);
private static final String DEFAULT_KEY = "AluerDefaultKey2024Secure!";
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public EncryptionService() {
encryptionKeys.put("default", DEFAULT_KEY);
logger.info("Encryption Service initialized");
}
public String encrypt(String plaintext, String keyName) {
try {
String key = encryptionKeys.getOrDefault(keyName, DEFAULT_KEY);
String encrypted = xorEncrypt(plaintext, key);
totalEncryptions.incrementAndGet();
EncryptionStats stat = stats.computeIfAbsent(keyName, k -> new EncryptionStats(keyName));
stat.incrementEncryptions();
logEvent("ENCRYPT", keyName, "SUCCESS", null);
return encrypted;
} catch (Exception e) {
totalFailures.incrementAndGet();
logEvent("ENCRYPT", keyName, "FAILED", e.getMessage());
logger.error("Encryption failed: {}", e.getMessage());
return null;
}
}
public String decrypt(String ciphertext, String keyName) {
try {
String key = encryptionKeys.getOrDefault(keyName, DEFAULT_KEY);
String decrypted = xorDecrypt(ciphertext, key);
totalDecryptions.incrementAndGet();
EncryptionStats stat = stats.computeIfAbsent(keyName, k -> new EncryptionStats(keyName));
stat.incrementDecryptions();
logEvent("DECRYPT", keyName, "SUCCESS", null);
return decrypted;
} catch (Exception e) {
totalFailures.incrementAndGet();
logEvent("DECRYPT", keyName, "FAILED", e.getMessage());
logger.error("Decryption failed: {}", e.getMessage());
return null;
}
}
private String xorEncrypt(String plaintext, String key) {
StringBuilder result = new StringBuilder();
for (int i = 0; i < plaintext.length(); i++) {
result.append((char) (plaintext.charAt(i) ^ key.charAt(i % key.length())));
}
return Base64.getEncoder().encodeToString(result.toString().getBytes());
}
private String xorDecrypt(String ciphertext, String key) {
byte[] decoded = Base64.getDecoder().decode(ciphertext);
String decodedStr = new String(decoded);
StringBuilder result = new StringBuilder();
for (int i = 0; i < decodedStr.length(); i++) {
result.append((char) (decodedStr.charAt(i) ^ key.charAt(i % key.length())));
}
return result.toString();
}
public String hashData(String data, String algorithm) {
try {
MessageDigest md = MessageDigest.getInstance(algorithm);
byte[] hash = md.digest(data.getBytes());
StringBuilder hexString = new StringBuilder();
for (byte b : hash) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) hexString.append('0');
hexString.append(hex);
}
return hexString.toString();
} catch (Exception e) {
logger.error("Hashing failed: {}", e.getMessage());
return null;
}
}
public String generateKey(int length) {
String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*";
Random random = new Random();
StringBuilder key = new StringBuilder();
for (int i = 0; i < length; i++) {
key.append(chars.charAt(random.nextInt(chars.length())));
}
return key.toString();
}
public void addKey(String name, String key) {
encryptionKeys.put(name, key);
logger.info("Added encryption key: {}", name);
}
public boolean removeKey(String name) {
if ("default".equals(name)) {
logger.warn("Cannot remove default key");
return false;
}
return encryptionKeys.remove(name) != null;
}
public Map<String, Object> getStats() {
Map<String, Object> statsMap = new HashMap<>();
statsMap.put("totalEncryptions", totalEncryptions.get());
statsMap.put("totalDecryptions", totalDecryptions.get());
statsMap.put("totalFailures", totalFailures.get());
statsMap.put("activeKeys", encryptionKeys.size());
return statsMap;
}
public List<EncryptionEvent> getRecentEvents(int limit) {
List<EncryptionEvent> events = new ArrayList<>();
int count = 0;
for (EncryptionEvent event : eventLog) {
if (count++ >= limit) break;
events.add(event);
}
return events;
}
private void logEvent(String operation, String keyName, String status, String error) {
EncryptionEvent event = new EncryptionEvent(operation, keyName, status, error, LocalDateTime.now());
eventLog.offer(event);
if (eventLog.size() > 1000) {
eventLog.poll();
}
}
public static class EncryptionStats {
private final String keyName;
private final AtomicLong encryptions = new AtomicLong(0);
private final AtomicLong decryptions = new AtomicLong(0);
public EncryptionStats(String keyName) {
this.keyName = keyName;
}
public void incrementEncryptions() { encryptions.incrementAndGet(); }
public void incrementDecryptions() { decryptions.incrementAndGet(); }
public String getKeyName() { return keyName; }
public long getEncryptions() { return encryptions.get(); }
public long getDecryptions() { return decryptions.get(); }
}
public static class EncryptionEvent {
private final String operation;
private final String keyName;
private final String status;
private final String error;
private final LocalDateTime timestamp;
public EncryptionEvent(String operation, String keyName, String status, String error, LocalDateTime timestamp) {
this.operation = operation;
this.keyName = keyName;
this.status = status;
this.error = error;
this.timestamp = timestamp;
}
public String getOperation() { return operation; }
public String getKeyName() { return keyName; }
public String getStatus() { return status; }
public String getError() { return error; }
public LocalDateTime getTimestamp() { return timestamp; }
}
}
@@ -0,0 +1,286 @@
package com.aluer.security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicLong;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Component
public class EndpointDetectionResponseService {
private static final Logger logger = LoggerFactory.getLogger(EndpointDetectionResponseService.class);
private final Map<String, EndpointProfile> endpoints = new ConcurrentHashMap<>();
private final Map<String, EDRRule> rules = new ConcurrentHashMap<>();
private final Queue<EDRAlert> alertQueue = new ConcurrentLinkedQueue<>();
private final Map<String, List<ThreatIndicator>> threatIndicators = new ConcurrentHashMap<>();
private final AtomicLong totalEndpointsMonitored = new AtomicLong(0);
private final AtomicLong threatsDetected = new AtomicLong(0);
private final AtomicLong responsesExecuted = new AtomicLong(0);
private volatile boolean enabled = false;
private static final int MAX_ALERTS = 10000;
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public EndpointDetectionResponseService() {
initializeDefaultRules();
logger.info("Endpoint Detection and Response Service initialized");
}
private void initializeDefaultRules() {
addRule("SUSPICIOUS_PROCESS", "PROCESS", "cmd.exe|powershell.exe|/bin/sh", 90, "CRITICAL");
addRule("UNAUTHORIZED_ACCESS", "ACCESS", "sudo|su |admin", 85, "HIGH");
addRule("MALICIOUS_FILE", "FILE", "\\.exe$|\\.dll$|\\.bat$", 80, "HIGH");
addRule("NETWORK_ANOMALY", "NETWORK", "unusual.*port|excessive.*connection", 75, "MEDIUM");
addRule("REGISTRY_CHANGE", "REGISTRY", "HKLM|HKCU", 70, "MEDIUM");
addRule("SERVICE_INSTALL", "SERVICE", "sc\\.exe|systemctl", 80, "HIGH");
addRule("SCHEDULE_TASK", "TASK", "at\\.exe|schtasks", 75, "MEDIUM");
addRule("WMI_EXECUTION", "WMI", "wmic|winmgmt", 85, "HIGH");
addRule("PASSWORD_DUMP", "CREDENTIAL", "mimikatz|procdump|pwdump", 100, "CRITICAL");
addRule("LATERAL_MOVEMENT", "MOVEMENT", "psexec|wmic|smb", 90, "HIGH");
logger.info("Initialized {} EDR rules", rules.size());
}
public void addRule(String name, String category, String pattern, int severity, String priority) {
EDRRule rule = new EDRRule(name, category, pattern, severity, priority);
rules.put(name, rule);
}
public void registerEndpoint(String endpointId, String hostname, String os, String ip) {
EndpointProfile endpoint = new EndpointProfile(endpointId, hostname, os, ip);
endpoints.put(endpointId, endpoint);
totalEndpointsMonitored.incrementAndGet();
logger.info("Registered endpoint: {} ({})", hostname, os);
}
public void analyzeEndpoint(String endpointId, Map<String, Object> telemetry) {
EndpointProfile endpoint = endpoints.get(endpointId);
if (endpoint == null) return;
for (EDRRule rule : rules.values()) {
if (matchesRule(telemetry, rule)) {
handleDetection(endpoint, rule, telemetry);
}
}
endpoint.updateLastSeen();
}
private boolean matchesRule(Map<String, Object> telemetry, EDRRule rule) {
for (Map.Entry<String, Object> entry : telemetry.entrySet()) {
if (entry.getValue() instanceof String) {
String value = (String) entry.getValue();
if (value.matches(rule.getPattern())) {
return true;
}
}
}
return false;
}
private void handleDetection(EndpointProfile endpoint, EDRRule rule, Map<String, Object> telemetry) {
threatsDetected.incrementAndGet();
EDRAlert alert = new EDRAlert(
endpoint.getEndpointId(),
rule.getName(),
rule.getCategory(),
rule.getSeverity(),
telemetry,
LocalDateTime.now()
);
alertQueue.offer(alert);
if (alertQueue.size() > MAX_ALERTS) {
alertQueue.poll();
}
executeResponse(endpoint, rule);
logger.warn("EDR Alert: {} detected on endpoint {} ({})",
rule.getName(), endpoint.getHostname(), endpoint.getEndpointId());
}
private void executeResponse(EndpointProfile endpoint, EDRRule rule) {
responsesExecuted.incrementAndGet();
switch (rule.getPriority()) {
case "CRITICAL":
isolateEndpoint(endpoint.getEndpointId());
break;
case "HIGH":
killSuspiciousProcess(endpoint, rule);
break;
case "MEDIUM":
quarantineFile(endpoint, rule);
break;
default:
logSuspiciousActivity(endpoint, rule);
}
}
private void isolateEndpoint(String endpointId) {
EndpointProfile endpoint = endpoints.get(endpointId);
if (endpoint != null) {
endpoint.setStatus("ISOLATED");
logger.warn("Endpoint {} has been isolated", endpointId);
}
}
private void killSuspiciousProcess(EndpointProfile endpoint, EDRRule rule) {
logger.info("Killing suspicious process on endpoint: {}", endpoint.getHostname());
}
private void quarantineFile(EndpointProfile endpoint, EDRRule rule) {
logger.info("Quarantining suspicious file on endpoint: {}", endpoint.getHostname());
}
private void logSuspiciousActivity(EndpointProfile endpoint, EDRRule rule) {
logger.info("Logging suspicious activity on endpoint: {}", endpoint.getHostname());
}
public void addThreatIndicator(String indicator, String type, String severity) {
List<ThreatIndicator> indicators = threatIndicators.computeIfAbsent(type, k -> new ArrayList<>());
indicators.add(new ThreatIndicator(indicator, type, severity, LocalDateTime.now()));
}
public Map<String, Object> getStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("enabled", enabled);
stats.put("totalEndpointsMonitored", totalEndpointsMonitored.get());
stats.put("threatsDetected", threatsDetected.get());
stats.put("responsesExecuted", responsesExecuted.get());
stats.put("activeEndpoints", endpoints.size());
stats.put("rulesConfigured", rules.size());
stats.put("alertQueueSize", alertQueue.size());
long critical = alertQueue.stream().filter(a -> a.getSeverity() >= 90).count();
stats.put("criticalAlerts", critical);
return stats;
}
public Map<String, EndpointProfile> getEndpoints() {
return new HashMap<>(endpoints);
}
public List<EDRAlert> getRecentAlerts(int limit) {
List<EDRAlert> alerts = new ArrayList<>();
int count = 0;
for (EDRAlert alert : alertQueue) {
if (count++ >= limit) break;
alerts.add(alert);
}
return alerts;
}
public void enable() {
enabled = true;
logger.info("EDR service enabled");
}
public void disable() {
enabled = false;
logger.info("EDR service disabled");
}
public static class EndpointProfile {
private final String endpointId;
private final String hostname;
private final String os;
private final String ip;
private volatile String status;
private volatile long lastSeen;
public EndpointProfile(String endpointId, String hostname, String os, String ip) {
this.endpointId = endpointId;
this.hostname = hostname;
this.os = os;
this.ip = ip;
this.status = "ACTIVE";
this.lastSeen = System.currentTimeMillis();
}
public void updateLastSeen() { this.lastSeen = System.currentTimeMillis(); }
public String getEndpointId() { return endpointId; }
public String getHostname() { return hostname; }
public String getOs() { return os; }
public String getIp() { return ip; }
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
public long getLastSeen() { return lastSeen; }
}
public static class EDRRule {
private final String name;
private final String category;
private final String pattern;
private final int severity;
private final String priority;
public EDRRule(String name, String category, String pattern, int severity, String priority) {
this.name = name;
this.category = category;
this.pattern = pattern;
this.severity = severity;
this.priority = priority;
}
public String getName() { return name; }
public String getCategory() { return category; }
public String getPattern() { return pattern; }
public int getSeverity() { return severity; }
public String getPriority() { return priority; }
}
public static class EDRAlert {
private final String endpointId;
private final String ruleName;
private final String category;
private final int severity;
private final Map<String, Object> telemetry;
private final LocalDateTime timestamp;
public EDRAlert(String endpointId, String ruleName, String category, int severity, Map<String, Object> telemetry, LocalDateTime timestamp) {
this.endpointId = endpointId;
this.ruleName = ruleName;
this.category = category;
this.severity = severity;
this.telemetry = telemetry;
this.timestamp = timestamp;
}
public String getEndpointId() { return endpointId; }
public String getRuleName() { return ruleName; }
public String getCategory() { return category; }
public int getSeverity() { return severity; }
public Map<String, Object> getTelemetry() { return telemetry; }
public LocalDateTime getTimestamp() { return timestamp; }
}
public static class ThreatIndicator {
private final String indicator;
private final String type;
private final String severity;
private final LocalDateTime timestamp;
public ThreatIndicator(String indicator, String type, String severity, LocalDateTime timestamp) {
this.indicator = indicator;
this.type = type;
this.severity = severity;
this.timestamp = timestamp;
}
public String getIndicator() { return indicator; }
public String getType() { return type; }
public String getSeverity() { return severity; }
public LocalDateTime getTimestamp() { return timestamp; }
}
}
@@ -0,0 +1,201 @@
package com.aluer.security;
import com.aluer.config.ServerGuardConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
@Service
public class FileIntegrityMonitorService {
private final ServerGuardConfig config;
private final Map<String, String> baselineHashes = new ConcurrentHashMap<>();
private final ConcurrentLinkedQueue<IntegrityAlert> alerts = new ConcurrentLinkedQueue<>();
private volatile long lastScanTime = 0L;
public FileIntegrityMonitorService() {
this(new ServerGuardConfig());
}
@Autowired
public FileIntegrityMonitorService(ServerGuardConfig config) {
this.config = config;
}
public synchronized Map<String, Object> scanNow() {
if (!config.getSecurity().getAntiIntrusion().getFileIntegrity().isEnabled()) {
return Map.of("enabled", false, "trackedFiles", baselineHashes.size(), "alerts", 0);
}
Map<String, String> currentHashes = collectCurrentHashes();
int newAlerts = 0;
if (baselineHashes.isEmpty()) {
baselineHashes.putAll(currentHashes);
} else {
for (Map.Entry<String, String> entry : currentHashes.entrySet()) {
String oldHash = baselineHashes.get(entry.getKey());
if (oldHash == null) {
alerts.offer(new IntegrityAlert("CREATED", entry.getKey(), "New monitored file discovered", Instant.now().toEpochMilli()));
newAlerts++;
} else if (!oldHash.equals(entry.getValue())) {
alerts.offer(new IntegrityAlert("MODIFIED", entry.getKey(), "File hash changed", Instant.now().toEpochMilli()));
newAlerts++;
}
}
for (String tracked : new ArrayList<>(baselineHashes.keySet())) {
if (!currentHashes.containsKey(tracked)) {
alerts.offer(new IntegrityAlert("DELETED", tracked, "Monitored file disappeared", Instant.now().toEpochMilli()));
newAlerts++;
}
}
baselineHashes.clear();
baselineHashes.putAll(currentHashes);
}
trimAlerts();
lastScanTime = System.currentTimeMillis();
Map<String, Object> result = new LinkedHashMap<>();
result.put("enabled", true);
result.put("trackedFiles", baselineHashes.size());
result.put("newAlerts", newAlerts);
result.put("lastScanTime", lastScanTime);
return result;
}
public synchronized Map<String, Object> rebuildBaseline() {
baselineHashes.clear();
Map<String, String> hashes = collectCurrentHashes();
baselineHashes.putAll(hashes);
lastScanTime = System.currentTimeMillis();
Map<String, Object> result = new LinkedHashMap<>();
result.put("baselineFiles", baselineHashes.size());
result.put("lastScanTime", lastScanTime);
return result;
}
public Map<String, Object> getBaselineStatus() {
Map<String, Object> result = new LinkedHashMap<>();
result.put("enabled", config.getSecurity().getAntiIntrusion().getFileIntegrity().isEnabled());
result.put("trackedFiles", baselineHashes.size());
result.put("alerts", alerts.size());
result.put("lastScanTime", lastScanTime);
result.put("paths", config.getSecurity().getAntiIntrusion().getFileIntegrity().getMonitoredPaths());
return result;
}
public List<IntegrityAlert> getRecentAlerts(int limit) {
List<IntegrityAlert> result = new ArrayList<>();
int count = 0;
for (IntegrityAlert alert : alerts) {
if (count++ >= limit) {
break;
}
result.add(alert);
}
result.sort(Comparator.comparingLong(IntegrityAlert::getTimestamp).reversed());
return result;
}
private Map<String, String> collectCurrentHashes() {
Map<String, String> hashes = new HashMap<>();
for (String configuredPath : config.getSecurity().getAntiIntrusion().getFileIntegrity().getMonitoredPaths()) {
hashes.putAll(resolvePathHashes(configuredPath));
}
return hashes;
}
private Map<String, String> resolvePathHashes(String configuredPath) {
Map<String, String> hashes = new HashMap<>();
Path path = Paths.get(configuredPath);
try {
if (configuredPath.contains("*")) {
Path parent = path.getParent();
if (parent != null && Files.isDirectory(parent)) {
PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:" + configuredPath);
try (var stream = Files.walk(parent, 1)) {
stream.filter(Files::isRegularFile)
.filter(matcher::matches)
.forEach(file -> hashes.put(file.toString(), sha256(file)));
}
}
return hashes;
}
if (Files.isDirectory(path)) {
int maxDepth = config.getSecurity().getAntiIntrusion().getFileIntegrity().getMaxDepth();
try (var stream = Files.walk(path, maxDepth)) {
stream.filter(Files::isRegularFile)
.forEach(file -> hashes.put(file.toString(), sha256(file)));
}
} else if (Files.isRegularFile(path)) {
hashes.put(path.toString(), sha256(path));
}
} catch (IOException ignored) {
}
return hashes;
}
private String sha256(Path file) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] bytes = Files.readAllBytes(file);
byte[] hash = digest.digest(bytes);
StringBuilder hex = new StringBuilder();
for (byte b : hash) {
hex.append(String.format("%02x", b));
}
return hex.toString();
} catch (IOException | NoSuchAlgorithmException e) {
return "unavailable";
}
}
private void trimAlerts() {
while (alerts.size() > 1000) {
alerts.poll();
}
}
public static class IntegrityAlert {
private final String type;
private final String path;
private final String details;
private final long timestamp;
public IntegrityAlert(String type, String path, String details, long timestamp) {
this.type = type;
this.path = path;
this.details = details;
this.timestamp = timestamp;
}
public String getType() { return type; }
public String getPath() { return path; }
public String getDetails() { return details; }
public long getTimestamp() { return timestamp; }
}
}
@@ -0,0 +1,431 @@
package com.aluer.security;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.security.MessageDigest;
@Service
public class FirewallService {
private final Map<String, FirewallRule> rules = new ConcurrentHashMap<>();
private final Map<String, FirewallProfile> profiles = new ConcurrentHashMap<>();
private final Map<String, ConnectionState> connections = new ConcurrentHashMap<>();
private final Queue<FirewallLog> logs = new ConcurrentLinkedQueue<>();
private final Set<String> whitelist = ConcurrentHashMap.newKeySet();
private final Set<String> blacklist = ConcurrentHashMap.newKeySet();
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
private volatile FirewallProfile activeProfile;
private final AtomicLong ruleIdCounter = new AtomicLong(1);
public static final int MAX_CONNECTIONS = 10000;
public static final long CONNECTION_TIMEOUT = 120000;
public static final int MAX_RULES = 500;
public FirewallService() {
initializeDefaultRules();
initializeDefaultProfiles();
startCleanupTask();
}
private void initializeDefaultProfiles() {
FirewallProfile strict = new FirewallProfile("strict", "严格模式", true);
strict.maxConnectionsPerIP = 10;
strict.maxRequestsPerSecond = 20;
strict.blockPingFlood = true;
strict.blockPortScan = true;
strict.blockSQLInjection = true;
strict.blockXSS = true;
profiles.put("strict", strict);
FirewallProfile normal = new FirewallProfile("normal", "普通模式", false);
normal.maxConnectionsPerIP = 50;
normal.maxRequestsPerSecond = 100;
normal.blockPingFlood = false;
normal.blockPortScan = true;
normal.blockSQLInjection = true;
normal.blockXSS = true;
profiles.put("normal", normal);
FirewallProfile relaxed = new FirewallProfile("relaxed", "宽松模式", false);
relaxed.maxConnectionsPerIP = 100;
relaxed.maxRequestsPerSecond = 500;
relaxed.blockPingFlood = false;
relaxed.blockPortScan = false;
relaxed.blockSQLInjection = false;
relaxed.blockXSS = false;
profiles.put("relaxed", relaxed);
activeProfile = normal;
}
private void initializeDefaultRules() {
addRule("DROP", "tcp", "0.0.0.0/0", "0.0.0.0/0", 23, "Telnet", "BLOCK_TELNET");
addRule("DROP", "tcp", "0.0.0.0/0", "0.0.0.0/0", 445, "SMB", "BLOCK_SMB");
addRule("DROP", "udp", "0.0.0.0/0", "0.0.0.0/0", 137, "NetBIOS", "BLOCK_NETBIOS");
addRule("DROP", "udp", "0.0.0.0/0", "0.0.0.0/0", 138, "NetBIOS", "BLOCK_NETBIOS");
addRule("DROP", "tcp", "0.0.0.0/0", "0.0.0.0/0", 1433, "MSSQL", "BLOCK_MSSQL");
addRule("DROP", "tcp", "0.0.0.0/0", "0.0.0.0/0", 3306, "MySQL", "BLOCK_MYSQL");
addRule("DROP", "tcp", "0.0.0.0/0", "0.0.0.0/0", 5432, "PostgreSQL", "BLOCK_POSTGRESQL");
addRule("DROP", "tcp", "0.0.0.0/0", "0.0.0.0/0", 27017, "MongoDB", "BLOCK_MONGODB");
}
public long addRule(String action, String protocol, String sourceIP, String destIP, int port, String description, String category) {
if (rules.size() >= MAX_RULES) {
return -1;
}
long id = ruleIdCounter.getAndIncrement();
FirewallRule rule = new FirewallRule(id, action, protocol, sourceIP, destIP, port, description, category);
rules.put(String.valueOf(id), rule);
logRuleChange("ADD", id, rule);
return id;
}
public boolean removeRule(long ruleId) {
String key = String.valueOf(ruleId);
FirewallRule removed = rules.remove(key);
if (removed != null) {
logRuleChange("REMOVE", ruleId, removed);
return true;
}
return false;
}
public FirewallRule getRule(long ruleId) {
return rules.get(String.valueOf(ruleId));
}
public Collection<FirewallRule> getAllRules() {
return rules.values();
}
public boolean updateRule(long ruleId, FirewallRule updated) {
String key = String.valueOf(ruleId);
if (!rules.containsKey(key)) {
return false;
}
rules.put(key, updated);
logRuleChange("UPDATE", ruleId, updated);
return true;
}
public boolean checkConnection(String sourceIP, String destIP, int port, String protocol) {
if (whitelist.contains(sourceIP)) {
return true;
}
if (blacklist.contains(sourceIP)) {
logBlock(sourceIP, destIP, port, "BLACKLIST");
return false;
}
FirewallProfile profile = activeProfile;
if (profile == null) {
return true;
}
for (FirewallRule rule : rules.values()) {
if (rule.matches(protocol, sourceIP, destIP, port)) {
if ("DROP".equals(rule.action) || "DENY".equals(rule.action)) {
logBlock(sourceIP, destIP, port, rule.category);
return false;
}
}
}
if (profile.maxConnectionsPerIP > 0) {
int connCount = getConnectionCount(sourceIP);
if (connCount >= profile.maxConnectionsPerIP) {
logBlock(sourceIP, destIP, port, "CONNECTION_LIMIT");
return false;
}
}
return true;
}
public boolean checkRequest(String ip, String request) {
FirewallProfile profile = activeProfile;
if (profile == null) {
return true;
}
if (profile.blockSQLInjection && containsSQLInjection(request)) {
logBlock(ip, "REQUEST", 0, "SQL_INJECTION");
return false;
}
if (profile.blockXSS && containsXSS(request)) {
logBlock(ip, "REQUEST", 0, "XSS");
return false;
}
if (profile.blockPathTraversal && containsPathTraversal(request)) {
logBlock(ip, "REQUEST", 0, "PATH_TRAVERSAL");
return false;
}
return true;
}
private boolean containsSQLInjection(String input) {
if (input == null) return false;
String lower = input.toLowerCase();
String[] sqlKeywords = {"union", "select", "insert", "update", "delete", "drop",
"create", "alter", "exec", "execute", "script", "--", ";"};
for (String keyword : sqlKeywords) {
if (lower.contains(keyword)) {
return true;
}
}
return false;
}
private boolean containsXSS(String input) {
if (input == null) return false;
String[] xssPatterns = {"<script", "javascript:", "onerror=", "onload=",
"<iframe", "eval(", "document.cookie"};
for (String pattern : xssPatterns) {
if (input.toLowerCase().contains(pattern)) {
return true;
}
}
return false;
}
private boolean containsPathTraversal(String input) {
if (input == null) return false;
return input.contains("../") || input.contains("..\\");
}
public void addToWhitelist(String ip) {
whitelist.add(ip);
logConfigChange("WHITELIST_ADD", ip);
}
public void removeFromWhitelist(String ip) {
whitelist.remove(ip);
logConfigChange("WHITELIST_REMOVE", ip);
}
public boolean isWhitelisted(String ip) {
return whitelist.contains(ip);
}
public void addToBlacklist(String ip) {
blacklist.add(ip);
logConfigChange("BLACKLIST_ADD", ip);
}
public void removeFromBlacklist(String ip) {
blacklist.remove(ip);
logConfigChange("BLACKLIST_REMOVE", ip);
}
public boolean isBlacklisted(String ip) {
return blacklist.contains(ip);
}
public boolean setActiveProfile(String profileName) {
FirewallProfile profile = profiles.get(profileName);
if (profile == null) {
return false;
}
activeProfile = profile;
logConfigChange("PROFILE_CHANGE", profileName);
return true;
}
public FirewallProfile getActiveProfile() {
return activeProfile;
}
public boolean createProfile(String name, String description) {
if (profiles.containsKey(name)) {
return false;
}
FirewallProfile profile = new FirewallProfile(name, description, false);
profiles.put(name, profile);
return true;
}
public boolean deleteProfile(String name) {
FirewallProfile profile = profiles.get(name);
if (profile == null) {
return false;
}
if (profile.isDefault) {
return false;
}
return profiles.remove(name) != null;
}
public Collection<FirewallProfile> getAllProfiles() {
return profiles.values();
}
public void recordConnection(String ip, String destIP, int port, String protocol) {
String key = ip + ":" + destIP + ":" + port;
connections.put(key, new ConnectionState(ip, destIP, port, protocol));
}
public void closeConnection(String ip, String destIP, int port) {
String key = ip + ":" + destIP + ":" + port;
connections.remove(key);
}
public int getConnectionCount(String ip) {
return (int) connections.keySet().stream()
.filter(k -> k.startsWith(ip + ":"))
.count();
}
public Collection<ConnectionState> getActiveConnections() {
return connections.values();
}
private void logBlock(String sourceIP, String destIP, int port, String reason) {
FirewallLog log = new FirewallLog("BLOCK", sourceIP, destIP, port, reason, System.currentTimeMillis());
addLog(log);
}
private void logRuleChange(String action, long ruleId, FirewallRule rule) {
FirewallLog log = new FirewallLog("RULE_" + action, rule.sourceIP, rule.destIP, rule.port,
ruleId + ":" + rule.description, System.currentTimeMillis());
addLog(log);
}
private void logConfigChange(String action, String details) {
FirewallLog log = new FirewallLog("CONFIG_" + action, "SYSTEM", details, 0, "", System.currentTimeMillis());
addLog(log);
}
private void addLog(FirewallLog log) {
logs.offer(log);
while (logs.size() > 5000) {
logs.remove();
}
}
public List<FirewallLog> getLogs(int limit) {
List<FirewallLog> result = new ArrayList<>();
int count = 0;
for (FirewallLog log : logs) {
if (count++ >= limit) break;
result.add(log);
}
return result;
}
public Map<String, Object> getStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("totalRules", rules.size());
stats.put("whitelistSize", whitelist.size());
stats.put("blacklistSize", blacklist.size());
stats.put("activeConnections", connections.size());
stats.put("activeProfile", activeProfile != null ? activeProfile.name : "none");
return stats;
}
private void startCleanupTask() {
scheduler.scheduleAtFixedRate(() -> {
long now = System.currentTimeMillis();
connections.entrySet().removeIf(entry ->
now - entry.getValue().createdAt > CONNECTION_TIMEOUT);
}, 60, 60, TimeUnit.SECONDS);
}
public static class FirewallRule {
public final long id;
public final String action;
public final String protocol;
public final String sourceIP;
public final String destIP;
public final int port;
public final String description;
public final String category;
public final long createdAt;
public FirewallRule(long id, String action, String protocol, String sourceIP,
String destIP, int port, String description, String category) {
this.id = id;
this.action = action;
this.protocol = protocol;
this.sourceIP = sourceIP;
this.destIP = destIP;
this.port = port;
this.description = description;
this.category = category;
this.createdAt = System.currentTimeMillis();
}
public boolean matches(String protocol, String sourceIP, String destIP, int port) {
if (!this.protocol.equalsIgnoreCase(protocol) && !this.protocol.equals("*")) {
return false;
}
if (this.port != 0 && this.port != port) {
return false;
}
return true;
}
}
public static class FirewallProfile {
public final String name;
public final String description;
public final boolean isDefault;
public int maxConnectionsPerIP = 50;
public int maxRequestsPerSecond = 100;
public boolean blockPingFlood = false;
public boolean blockPortScan = false;
public boolean blockSQLInjection = false;
public boolean blockXSS = false;
public boolean blockPathTraversal = false;
public FirewallProfile(String name, String description, boolean isDefault) {
this.name = name;
this.description = description;
this.isDefault = isDefault;
}
}
public static class ConnectionState {
public final String sourceIP;
public final String destIP;
public final int port;
public final String protocol;
public final long createdAt;
public volatile long lastActivity;
public ConnectionState(String sourceIP, String destIP, int port, String protocol) {
this.sourceIP = sourceIP;
this.destIP = destIP;
this.port = port;
this.protocol = protocol;
this.createdAt = System.currentTimeMillis();
this.lastActivity = System.currentTimeMillis();
}
}
public static class FirewallLog {
public final String type;
public final String sourceIP;
public final String destIP;
public final int port;
public final String reason;
public final long timestamp;
public FirewallLog(String type, String sourceIP, String destIP, int port, String reason, long timestamp) {
this.type = type;
this.sourceIP = sourceIP;
this.destIP = destIP;
this.port = port;
this.reason = reason;
this.timestamp = timestamp;
}
}
}
@@ -0,0 +1,411 @@
package com.aluer.security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicLong;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Component
public class FlowAnalyzerService {
private static final Logger logger = LoggerFactory.getLogger(FlowAnalyzerService.class);
private final Map<String, FlowRecord> activeFlows = new ConcurrentHashMap<>();
private final Map<String, FlowStatistics> flowStatistics = new ConcurrentHashMap<>();
private final Queue<FlowAlert> alertQueue = new ConcurrentLinkedQueue<>();
private final Map<String, List<HistoryEntry>> flowHistory = new ConcurrentHashMap<>();
private final AtomicLong totalFlowsAnalyzed = new AtomicLong(0);
private final AtomicLong totalBytesTransferred = new AtomicLong(0);
private static final int FLOW_TIMEOUT_SECONDS = 300;
private static final int MAX_ACTIVE_FLOWS = 10000;
private static final long BYTES_THRESHOLD = 100 * 1024 * 1024;
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public FlowAnalyzerService() {
logger.info("Flow Analyzer Service initialized");
}
public void recordPacket(String sourceIP, String destIP, int sourcePort, int destPort,
int packetSize, String protocol) {
String flowKey = generateFlowKey(sourceIP, destIP, sourcePort, destPort, protocol);
FlowRecord flow = activeFlows.computeIfAbsent(flowKey, k -> {
FlowRecord newFlow = new FlowRecord(sourceIP, destIP, sourcePort, destPort, protocol);
totalFlowsAnalyzed.incrementAndGet();
return newFlow;
});
flow.addPacket(packetSize);
totalBytesTransferred.addAndGet(packetSize);
if (flow.getTotalBytes() > BYTES_THRESHOLD) {
triggerAlert(flow, "HIGH_VOLUME", "异常高流量传输: " + formatBytes(flow.getTotalBytes()));
}
if (flow.getPacketCount() > 10000) {
triggerAlert(flow, "HIGH_PACKET_COUNT", "高数据包数量: " + flow.getPacketCount());
}
long flowAge = System.currentTimeMillis() - flow.getStartTime();
if (flowAge > FLOW_TIMEOUT_SECONDS * 1000) {
expireFlow(flowKey);
}
}
public void recordBidirectionalFlow(String clientIP, String serverIP, int clientPort, int serverPort,
int clientToServerBytes, int serverToClientBytes, String protocol) {
String forwardKey = generateFlowKey(clientIP, serverIP, clientPort, serverPort, protocol);
String reverseKey = generateFlowKey(serverIP, clientIP, serverPort, clientPort, protocol);
FlowRecord forwardFlow = activeFlows.computeIfAbsent(forwardKey, k -> {
FlowRecord f = new FlowRecord(clientIP, serverIP, clientPort, serverPort, protocol);
totalFlowsAnalyzed.incrementAndGet();
return f;
});
forwardFlow.addPacket(clientToServerBytes);
FlowRecord reverseFlow = activeFlows.computeIfAbsent(reverseKey, k -> {
FlowRecord f = new FlowRecord(serverIP, clientIP, serverPort, clientPort, protocol);
totalFlowsAnalyzed.incrementAndGet();
return f;
});
reverseFlow.addPacket(serverToClientBytes);
totalBytesTransferred.addAndGet(clientToServerBytes + serverToClientBytes);
analyzeFlowRatio(forwardFlow, reverseFlow);
}
private void analyzeFlowRatio(FlowRecord forward, FlowRecord reverse) {
long forwardBytes = forward.getTotalBytes();
long reverseBytes = reverse.getTotalBytes();
if (forwardBytes > 0 && reverseBytes > 0) {
double ratio = (double) forwardBytes / reverseBytes;
if (ratio > 100 || ratio < 0.01) {
triggerAlert(forward, "ASYMMETRIC_FLOW", "不对称流量比率: " + String.format("%.2f", ratio));
}
}
long forwardPackets = forward.getPacketCount();
long reversePackets = reverse.getPacketCount();
if (forwardPackets > 0 && reversePackets > 0) {
double packetRatio = (double) forwardPackets / reversePackets;
if (packetRatio > 50 || packetRatio < 0.02) {
triggerAlert(forward, "PACKET_RATIO_ANOMALY", "数据包比率异常: " + String.format("%.2f", packetRatio));
}
}
}
public Map<String, Object> analyzeFlowPatterns(String ip) {
Map<String, Object> analysis = new HashMap<>();
List<FlowRecord> relatedFlows = new ArrayList<>();
for (FlowRecord flow : activeFlows.values()) {
if (flow.getSourceIP().equals(ip) || flow.getDestIP().equals(ip)) {
relatedFlows.add(flow);
}
}
if (relatedFlows.isEmpty()) {
analysis.put("status", "no_flows");
return analysis;
}
long totalBytes = relatedFlows.stream().mapToLong(FlowRecord::getTotalBytes).sum();
long totalPackets = relatedFlows.stream().mapToLong(FlowRecord::getPacketCount).sum();
analysis.put("totalFlows", relatedFlows.size());
analysis.put("totalBytes", totalBytes);
analysis.put("totalPackets", totalPackets);
Map<String, Long> destPorts = new HashMap<>();
Map<String, Long> protocols = new HashMap<>();
for (FlowRecord flow : relatedFlows) {
destPorts.merge(String.valueOf(flow.getDestPort()), 1L, Long::sum);
protocols.merge(flow.getProtocol(), 1L, Long::sum);
}
analysis.put("destinationPorts", destPorts);
analysis.put("protocols", protocols);
double avgBytesPerFlow = (double) totalBytes / relatedFlows.size();
analysis.put("avgBytesPerFlow", avgBytesPerFlow);
if (avgBytesPerFlow > 10 * 1024 * 1024) {
analysis.put("warning", "异常高流量");
}
return analysis;
}
public List<FlowRecord> getTopFlows(int limit, String sortBy) {
List<FlowRecord> flows = new ArrayList<>(activeFlows.values());
if ("bytes".equals(sortBy)) {
flows.sort((a, b) -> Long.compare(b.getTotalBytes(), a.getTotalBytes()));
} else if ("packets".equals(sortBy)) {
flows.sort((a, b) -> Long.compare(b.getPacketCount(), a.getPacketCount()));
} else if ("duration".equals(sortBy)) {
flows.sort((a, b) -> Long.compare(b.getDuration(), a.getDuration()));
} else {
flows.sort((a, b) -> Long.compare(b.getTotalBytes(), a.getTotalBytes()));
}
return flows.subList(0, Math.min(limit, flows.size()));
}
public Map<String, FlowStatistics> getProtocolStatistics() {
Map<String, FlowStatistics> stats = new HashMap<>();
for (FlowRecord flow : activeFlows.values()) {
FlowStatistics protocolStats = stats.computeIfAbsent(flow.getProtocol(), k -> new FlowStatistics(flow.getProtocol()));
protocolStats.addFlow(flow);
}
return stats;
}
public Map<String, Object> getTrafficMatrix() {
Map<String, Object> matrix = new HashMap<>();
Map<String, Long> sourceIPTraffic = new HashMap<>();
Map<String, Long> destIPTraffic = new HashMap<>();
Map<String, Long> protocolTraffic = new HashMap<>();
Map<String, Long> portTraffic = new HashMap<>();
for (FlowRecord flow : activeFlows.values()) {
sourceIPTraffic.merge(flow.getSourceIP(), flow.getTotalBytes(), Long::sum);
destIPTraffic.merge(flow.getDestIP(), flow.getTotalBytes(), Long::sum);
protocolTraffic.merge(flow.getProtocol(), flow.getTotalBytes(), Long::sum);
portTraffic.merge(String.valueOf(flow.getDestPort()), flow.getTotalBytes(), Long::sum);
}
matrix.put("bySourceIP", sortByValue(sourceIPTraffic, 10));
matrix.put("byDestIP", sortByValue(destIPTraffic, 10));
matrix.put("byProtocol", sortByValue(protocolTraffic, 10));
matrix.put("byPort", sortByValue(portTraffic, 10));
return matrix;
}
private Map<String, Long> sortByValue(Map<String, Long> map, int limit) {
return map.entrySet().stream()
.sorted(Map.Entry.<String, Long>comparingByValue().reversed())
.limit(limit)
.collect(LinkedHashMap::new,
(m, e) -> m.put(e.getKey(), e.getValue()),
LinkedHashMap::putAll);
}
public void detectAnomalies() {
if (activeFlows.size() > MAX_ACTIVE_FLOWS) {
logger.warn("High number of active flows: {}", activeFlows.size());
}
for (FlowRecord flow : activeFlows.values()) {
if (flow.getPacketCount() > 0) {
double avgPacketSize = (double) flow.getTotalBytes() / flow.getPacketCount();
if (avgPacketSize > 10000) {
triggerAlert(flow, "LARGE_AVG_PACKET", "平均数据包过大: " + String.format("%.0f", avgPacketSize) + " bytes");
}
if (avgPacketSize < 10) {
triggerAlert(flow, "SMALL_AVG_PACKET", "平均数据包过小: " + String.format("%.0f", avgPacketSize) + " bytes");
}
}
}
}
public void expireFlow(String flowKey) {
FlowRecord flow = activeFlows.remove(flowKey);
if (flow != null) {
List<HistoryEntry> history = flowHistory.computeIfAbsent(flow.getSourceIP(), k -> new ArrayList<>());
history.add(new HistoryEntry(flow.getDestIP(), flow.getTotalBytes(), flow.getPacketCount(), LocalDateTime.now()));
if (history.size() > 1000) {
history.subList(0, 500).clear();
}
FlowStatistics stats = flowStatistics.get(flow.getProtocol());
if (stats != null) {
stats.recordCompletedFlow(flow);
}
}
}
public Map<String, Object> getStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("totalFlowsAnalyzed", totalFlowsAnalyzed.get());
stats.put("totalBytesTransferred", totalBytesTransferred.get());
stats.put("activeFlows", activeFlows.size());
stats.put("alertQueueSize", alertQueue.size());
long totalFlowBytes = activeFlows.values().stream().mapToLong(FlowRecord::getTotalBytes).sum();
stats.put("activeFlowBytes", totalFlowBytes);
return stats;
}
public List<FlowAlert> getRecentAlerts(int limit) {
List<FlowAlert> alerts = new ArrayList<>();
int count = 0;
for (FlowAlert alert : alertQueue) {
if (count++ >= limit) break;
alerts.add(alert);
}
return alerts;
}
private void triggerAlert(FlowRecord flow, String alertType, String details) {
FlowAlert alert = new FlowAlert(
flow.getSourceIP(),
flow.getDestIP(),
alertType,
details,
flow.getTotalBytes(),
LocalDateTime.now()
);
alertQueue.offer(alert);
if (alertQueue.size() > 1000) {
alertQueue.poll();
}
logger.warn("Flow Alert: {} - {} -> {}: {}", alertType, flow.getSourceIP(), flow.getDestIP(), details);
}
private String generateFlowKey(String sourceIP, String destIP, int sourcePort, int destPort, String protocol) {
return sourceIP + "-" + destIP + "-" + sourcePort + "-" + destPort + "-" + protocol;
}
private String formatBytes(long bytes) {
if (bytes < 1024) return bytes + " B";
if (bytes < 1024 * 1024) return String.format("%.2f KB", bytes / 1024.0);
if (bytes < 1024 * 1024 * 1024) return String.format("%.2f MB", bytes / (1024.0 * 1024));
return String.format("%.2f GB", bytes / (1024.0 * 1024 * 1024));
}
public static class FlowRecord {
private final String sourceIP;
private final String destIP;
private final int sourcePort;
private final int destPort;
private final String protocol;
private final long startTime;
private volatile long lastPacketTime;
private volatile long packetCount;
private volatile long totalBytes;
public FlowRecord(String sourceIP, String destIP, int sourcePort, int destPort, String protocol) {
this.sourceIP = sourceIP;
this.destIP = destIP;
this.sourcePort = sourcePort;
this.destPort = destPort;
this.protocol = protocol;
this.startTime = System.currentTimeMillis();
this.lastPacketTime = startTime;
this.packetCount = 0;
this.totalBytes = 0;
}
public synchronized void addPacket(int size) {
packetCount++;
totalBytes += size;
lastPacketTime = System.currentTimeMillis();
}
public long getDuration() {
return lastPacketTime - startTime;
}
public String getSourceIP() { return sourceIP; }
public String getDestIP() { return destIP; }
public int getSourcePort() { return sourcePort; }
public int getDestPort() { return destPort; }
public String getProtocol() { return protocol; }
public long getStartTime() { return startTime; }
public long getLastPacketTime() { return lastPacketTime; }
public long getPacketCount() { return packetCount; }
public long getTotalBytes() { return totalBytes; }
}
public static class FlowStatistics {
private final String protocol;
private final AtomicLong totalFlows = new AtomicLong(0);
private final AtomicLong completedFlows = new AtomicLong(0);
private final AtomicLong totalBytes = new AtomicLong(0);
private final AtomicLong totalPackets = new AtomicLong(0);
public FlowStatistics(String protocol) {
this.protocol = protocol;
}
public void addFlow(FlowRecord flow) {
totalFlows.incrementAndGet();
totalBytes.addAndGet(flow.getTotalBytes());
totalPackets.addAndGet(flow.getPacketCount());
}
public void recordCompletedFlow(FlowRecord flow) {
completedFlows.incrementAndGet();
}
public String getProtocol() { return protocol; }
public long getTotalFlows() { return totalFlows.get(); }
public long getCompletedFlows() { return completedFlows.get(); }
public long getTotalBytes() { return totalBytes.get(); }
public long getTotalPackets() { return totalPackets.get(); }
}
public static class FlowAlert {
private final String sourceIP;
private final String destIP;
private final String alertType;
private final String details;
private final long bytes;
private final LocalDateTime timestamp;
public FlowAlert(String sourceIP, String destIP, String alertType, String details, long bytes, LocalDateTime timestamp) {
this.sourceIP = sourceIP;
this.destIP = destIP;
this.alertType = alertType;
this.details = details;
this.bytes = bytes;
this.timestamp = timestamp;
}
public String getSourceIP() { return sourceIP; }
public String getDestIP() { return destIP; }
public String getAlertType() { return alertType; }
public String getDetails() { return details; }
public long getBytes() { return bytes; }
public LocalDateTime getTimestamp() { return timestamp; }
}
public static class HistoryEntry {
private final String destIP;
private final long bytes;
private final long packets;
private final LocalDateTime timestamp;
public HistoryEntry(String destIP, long bytes, long packets, LocalDateTime timestamp) {
this.destIP = destIP;
this.bytes = bytes;
this.packets = packets;
this.timestamp = timestamp;
}
public String getDestIP() { return destIP; }
public long getBytes() { return bytes; }
public long getPackets() { return packets; }
public LocalDateTime getTimestamp() { return timestamp; }
}
}
@@ -0,0 +1,132 @@
package com.aluer.security;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.concurrent.*;
@Service
public class GeoIPService {
private final Map<String, GeoLocation> geoCache = new ConcurrentHashMap<>();
private final Map<String, Set<String>> countryIPs = new ConcurrentHashMap<>();
private final Set<String> allowedCountries = ConcurrentHashMap.newKeySet();
private final Set<String> blockedCountries = ConcurrentHashMap.newKeySet();
private final Queue<GeoEvent> events = new ConcurrentLinkedQueue<>();
private static final long CACHE_DURATION = 86400000;
public GeoIPService() {
initializeDefaultCountries();
}
private void initializeDefaultCountries() {
allowedCountries.add("CN");
allowedCountries.add("US");
allowedCountries.add("JP");
allowedCountries.add("KR");
allowedCountries.add("SG");
}
public boolean checkCountry(String ip, String countryCode) {
if (blockedCountries.contains(countryCode)) {
logEvent(ip, countryCode, "BLOCKED");
return false;
}
if (!allowedCountries.isEmpty() && !allowedCountries.contains(countryCode)) {
logEvent(ip, countryCode, "NOT_ALLOWED");
return false;
}
return true;
}
public void setGeoLocation(String ip, String country, String city, double lat, double lon) {
GeoLocation geo = new GeoLocation(ip, country, city, lat, lon, System.currentTimeMillis());
geoCache.put(ip, geo);
countryIPs.computeIfAbsent(country, k -> ConcurrentHashMap.newKeySet()).add(ip);
}
public GeoLocation getGeoLocation(String ip) {
return geoCache.get(ip);
}
public void addAllowedCountry(String country) {
allowedCountries.add(country);
}
public void removeAllowedCountry(String country) {
allowedCountries.remove(country);
}
public void addBlockedCountry(String country) {
blockedCountries.add(country);
}
public void removeBlockedCountry(String country) {
blockedCountries.remove(country);
}
public Set<String> getAllowedCountries() {
return new HashSet<>(allowedCountries);
}
public Set<String> getBlockedCountries() {
return new HashSet<>(blockedCountries);
}
private void logEvent(String ip, String country, String status) {
events.offer(new GeoEvent(ip, country, status, System.currentTimeMillis()));
}
public List<GeoEvent> getRecentEvents(int limit) {
List<GeoEvent> result = new ArrayList<>();
int count = 0;
for (GeoEvent event : events) {
if (count++ >= limit) break;
result.add(event);
}
return result;
}
public Map<String, Object> getStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("cachedLocations", geoCache.size());
stats.put("allowedCountries", allowedCountries.size());
stats.put("blockedCountries", blockedCountries.size());
return stats;
}
public static class GeoLocation {
public final String ip;
public final String country;
public final String city;
public final double latitude;
public final double longitude;
public final long timestamp;
public GeoLocation(String ip, String country, String city, double lat, double lon, long timestamp) {
this.ip = ip;
this.country = country;
this.city = city;
this.latitude = lat;
this.longitude = lon;
this.timestamp = timestamp;
}
}
public static class GeoEvent {
public final String ip;
public final String country;
public final String status;
public final long timestamp;
public GeoEvent(String ip, String country, String status, long timestamp) {
this.ip = ip;
this.country = country;
this.status = status;
this.timestamp = timestamp;
}
}
}
@@ -0,0 +1,240 @@
package com.aluer.security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicLong;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Component
public class HoneypotService {
private static final Logger logger = LoggerFactory.getLogger(HoneypotService.class);
private final Map<String, HoneypotInstance> honeypots = new ConcurrentHashMap<>();
private final Queue<HoneyPotEvent> eventLog = new ConcurrentLinkedQueue<>();
private final Map<String, List<AttackAttempt>> attackHistory = new ConcurrentHashMap<>();
private final Map<String, AttackerProfile> attackerProfiles = new ConcurrentHashMap<>();
private final AtomicLong totalInteractions = new AtomicLong(0);
private final AtomicLong uniqueAttackers = new AtomicLong(0);
private final AtomicLong attacksRecorded = new AtomicLong(0);
private volatile boolean enabled = false;
private static final int MAX_HISTORY = 10000;
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public HoneypotService() {
initializeDefaultHoneypots();
logger.info("Honeypot Service initialized");
}
private void initializeDefaultHoneypots() {
addHoneypot("ssh-honeypot", "SSH", 2222, "OpenSSH 7.4");
addHoneypot("ftp-honeypot", "FTP", 2121, "ProFTPD 1.3.5");
addHoneypot("http-honeypot", "HTTP", 8080, "Apache 2.4.29");
addHoneypot("mysql-honeypot", "MySQL", 3307, "MySQL 5.7");
addHoneypot("minecraft-honeypot", "MINECRAFT", 25566, "PaperSpigot 1.19");
logger.info("Initialized {} honeypot instances", honeypots.size());
}
public void addHoneypot(String name, String type, int port, String fakeVersion) {
HoneypotInstance honeypot = new HoneypotInstance(name, type, port, fakeVersion);
honeypots.put(name, honeypot);
logger.info("Added honeypot: {} on port {}", name, port);
}
public void recordInteraction(String honeypotName, String sourceIP, String username, String password, String command) {
if (!enabled) return;
totalInteractions.incrementAndGet();
HoneypotInstance honeypot = honeypots.get(honeypotName);
if (honeypot != null) {
honeypot.incrementInteractionCount();
}
AttackerProfile profile = attackerProfiles.computeIfAbsent(sourceIP, k -> {
uniqueAttackers.incrementAndGet();
return new AttackerProfile(sourceIP);
});
profile.recordAttempt(honeypotName);
AttackAttempt attempt = new AttackAttempt(honeypotName, sourceIP, username, password, command, LocalDateTime.now());
List<AttackAttempt> history = attackHistory.computeIfAbsent(sourceIP, k -> new ArrayList<>());
history.add(attempt);
attacksRecorded.incrementAndGet();
if (history.size() > MAX_HISTORY) {
history.remove(0);
}
logEvent(sourceIP, honeypotName, "INTERACTION", "Recorded interaction: " + command);
logger.info("Recorded honeypot interaction from {} on {}", sourceIP, honeypotName);
}
public List<AttackAttempt> getAttackHistory(String ip, int limit) {
List<AttackAttempt> history = attackHistory.getOrDefault(ip, new ArrayList<>());
return history.subList(0, Math.min(limit, history.size()));
}
public Map<String, AttackerProfile> getTopAttackers(int limit) {
List<AttackerProfile> sorted = new ArrayList<>(attackerProfiles.values());
sorted.sort((a, b) -> Integer.compare(b.getTotalAttempts(), a.getTotalAttempts()));
Map<String, AttackerProfile> top = new LinkedHashMap<>();
for (int i = 0; i < Math.min(limit, sorted.size()); i++) {
top.put(sorted.get(i).getIp(), sorted.get(i));
}
return top;
}
public Map<String, Object> getStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("enabled", enabled);
stats.put("totalInteractions", totalInteractions.get());
stats.put("uniqueAttackers", uniqueAttackers.get());
stats.put("attacksRecorded", attacksRecorded.get());
stats.put("honeypotsConfigured", honeypots.size());
Map<String, Long> honeypotStats = new HashMap<>();
for (HoneypotInstance hp : honeypots.values()) {
honeypotStats.put(hp.getName(), hp.getInteractionCount());
}
stats.put("honeypotInteractions", honeypotStats);
return stats;
}
public void enable() {
enabled = true;
logger.info("Honeypot service enabled");
}
public void disable() {
enabled = false;
logger.info("Honeypot service disabled");
}
public Map<String, HoneypotInstance> getHoneypots() {
return new HashMap<>(honeypots);
}
public List<HoneyPotEvent> getRecentEvents(int limit) {
List<HoneyPotEvent> events = new ArrayList<>();
int count = 0;
for (HoneyPotEvent event : eventLog) {
if (count++ >= limit) break;
events.add(event);
}
return events;
}
private void logEvent(String ip, String honeypot, String action, String details) {
HoneyPotEvent event = new HoneyPotEvent(ip, honeypot, action, details, LocalDateTime.now());
eventLog.offer(event);
if (eventLog.size() > 5000) {
eventLog.poll();
}
}
public static class HoneypotInstance {
private final String name;
private final String type;
private final int port;
private final String fakeVersion;
private final AtomicLong interactionCount = new AtomicLong(0);
public HoneypotInstance(String name, String type, int port, String fakeVersion) {
this.name = name;
this.type = type;
this.port = port;
this.fakeVersion = fakeVersion;
}
public void incrementInteractionCount() { interactionCount.incrementAndGet(); }
public String getName() { return name; }
public String getType() { return type; }
public int getPort() { return port; }
public String getFakeVersion() { return fakeVersion; }
public long getInteractionCount() { return interactionCount.get(); }
}
public static class AttackAttempt {
private final String honeypotName;
private final String sourceIP;
private final String username;
private final String password;
private final String command;
private final LocalDateTime timestamp;
public AttackAttempt(String honeypotName, String sourceIP, String username, String password, String command, LocalDateTime timestamp) {
this.honeypotName = honeypotName;
this.sourceIP = sourceIP;
this.username = username;
this.password = password;
this.command = command;
this.timestamp = timestamp;
}
public String getHoneypotName() { return honeypotName; }
public String getSourceIP() { return sourceIP; }
public String getUsername() { return username; }
public String getPassword() { return password; }
public String getCommand() { return command; }
public LocalDateTime getTimestamp() { return timestamp; }
}
public static class AttackerProfile {
private final String ip;
private final Map<String, Integer> honeypotAttempts = new HashMap<>();
private volatile int totalAttempts = 0;
private volatile long firstSeen;
private volatile long lastSeen;
public AttackerProfile(String ip) {
this.ip = ip;
this.firstSeen = System.currentTimeMillis();
this.lastSeen = firstSeen;
}
public void recordAttempt(String honeypotName) {
honeypotAttempts.merge(honeypotName, 1, Integer::sum);
totalAttempts++;
lastSeen = System.currentTimeMillis();
}
public String getIp() { return ip; }
public Map<String, Integer> getHoneypotAttempts() { return honeypotAttempts; }
public int getTotalAttempts() { return totalAttempts; }
public long getFirstSeen() { return firstSeen; }
public long getLastSeen() { return lastSeen; }
}
public static class HoneyPotEvent {
private final String ip;
private final String honeypot;
private final String action;
private final String details;
private final LocalDateTime timestamp;
public HoneyPotEvent(String ip, String honeypot, String action, String details, LocalDateTime timestamp) {
this.ip = ip;
this.honeypot = honeypot;
this.action = action;
this.details = details;
this.timestamp = timestamp;
}
public String getIp() { return ip; }
public String getHoneypot() { return honeypot; }
public String getAction() { return action; }
public String getDetails() { return details; }
public LocalDateTime getTimestamp() { return timestamp; }
}
}
@@ -0,0 +1,479 @@
package com.aluer.security;
import com.aluer.config.ServerGuardConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.regex.Pattern;
@Service
public class HostEnforcementService {
private static final Logger logger = LoggerFactory.getLogger(HostEnforcementService.class);
private static final Pattern IP_PATTERN = Pattern.compile("^[0-9a-fA-F:.]+$");
private final ServerGuardConfig config;
private final Map<String, ManagedRule> desiredRules = new ConcurrentHashMap<>();
private final ConcurrentLinkedQueue<EnforcementActionResult> actionLog = new ConcurrentLinkedQueue<>();
public HostEnforcementService() {
this(new ServerGuardConfig());
}
@Autowired
public HostEnforcementService(ServerGuardConfig config) {
this.config = config;
}
public EnforcementActionResult blockIp(String ip, String reason, int durationMinutes) {
return applyRule("BLOCK", ip, Math.max(1, durationMinutes), 0, reason);
}
public EnforcementActionResult releaseIp(String ip, String reason) {
String normalizedIp = normalizeIp(ip);
if (normalizedIp == null) {
return record(new EnforcementActionResult(false, "RELEASE", "none", true,
"invalid-ip", List.of(), reason, ip, 0, 0));
}
HostFirewallAdapter adapter = resolveAdapter();
ManagedRule existing = findRule(normalizedIp, null);
List<String> preview = adapter.previewReleaseCommands(normalizedIp, existing != null ? existing.mode : "BLOCK");
boolean success = true;
String status = "released";
if (!isDryRunEnabled()) {
success = executeCommands(adapter.buildReleaseCommands(normalizedIp, existing != null ? existing.mode : "BLOCK"));
status = success ? "released" : "release-failed";
}
desiredRules.entrySet().removeIf(entry -> normalizedIp.equals(entry.getValue().ip));
return record(new EnforcementActionResult(success, "RELEASE", adapter.getName(), isDryRunEnabled(),
status, preview, reason, normalizedIp, 0, 0));
}
public EnforcementActionResult rateLimitIp(String ip, int limitPerMinute, String reason) {
return applyRule("RATE_LIMIT", ip, config.getSecurity().getHostEnforcement().getDefaultBlockMinutes(),
Math.max(1, limitPerMinute), reason);
}
public List<ManagedRule> listActiveRules() {
List<ManagedRule> rules = new ArrayList<>(desiredRules.values());
rules.sort(Comparator.comparingLong((ManagedRule rule) -> rule.createdAt).reversed());
return rules;
}
public Map<String, Object> syncDesiredState() {
long now = System.currentTimeMillis();
int expired = 0;
for (ManagedRule rule : new ArrayList<>(desiredRules.values())) {
if (rule.expiresAt > 0 && rule.expiresAt < now) {
releaseIp(rule.ip, "TTL expired");
expired++;
}
}
Map<String, Object> result = new LinkedHashMap<>();
result.put("expiredRulesReleased", expired);
result.put("remainingRules", desiredRules.size());
result.put("backend", resolveAdapter().getName());
result.put("dryRun", isDryRunEnabled());
return result;
}
public Map<String, Object> dryRunPreview(String action, String ip, String reason) {
HostFirewallAdapter adapter = resolveAdapter();
String normalizedAction = action == null ? "BLOCK" : action.toUpperCase(Locale.ROOT);
String normalizedIp = normalizeIp(ip);
List<String> preview;
if (normalizedIp == null) {
preview = List.of();
} else if ("RELEASE".equals(normalizedAction)) {
preview = adapter.previewReleaseCommands(normalizedIp, "BLOCK");
} else if ("RATE_LIMIT".equals(normalizedAction)) {
preview = adapter.previewRateLimitCommands(normalizedIp, config.getSecurity().getHostEnforcement().getDefaultRateLimitPerMinute());
} else {
preview = adapter.previewBlockCommands(normalizedIp);
}
Map<String, Object> result = new LinkedHashMap<>();
result.put("action", normalizedAction);
result.put("ip", normalizedIp);
result.put("backend", adapter.getName());
result.put("reason", reason);
result.put("dryRun", true);
result.put("commands", preview);
return result;
}
public Map<String, Object> getStats() {
long blockRules = desiredRules.values().stream().filter(rule -> "BLOCK".equals(rule.mode)).count();
long rateRules = desiredRules.values().stream().filter(rule -> "RATE_LIMIT".equals(rule.mode)).count();
Map<String, Object> stats = new HashMap<>();
stats.put("enabled", isEnabled());
stats.put("dryRun", isDryRunEnabled());
stats.put("backend", resolveAdapter().getName());
stats.put("managedRules", desiredRules.size());
stats.put("blockRules", blockRules);
stats.put("rateLimitRules", rateRules);
stats.put("loggedActions", actionLog.size());
return stats;
}
public List<EnforcementActionResult> getRecentActions(int limit) {
List<EnforcementActionResult> actions = new ArrayList<>();
int count = 0;
for (EnforcementActionResult action : actionLog) {
if (count++ >= limit) {
break;
}
actions.add(action);
}
return actions;
}
private EnforcementActionResult applyRule(String mode, String ip, int durationMinutes, int limitPerMinute, String reason) {
String normalizedIp = normalizeIp(ip);
if (normalizedIp == null) {
return record(new EnforcementActionResult(false, mode, "none", true,
"invalid-ip", List.of(), reason, ip, durationMinutes, limitPerMinute));
}
HostFirewallAdapter adapter = resolveAdapter();
List<String> preview = "RATE_LIMIT".equals(mode)
? adapter.previewRateLimitCommands(normalizedIp, limitPerMinute)
: adapter.previewBlockCommands(normalizedIp);
boolean success = true;
String status = isDryRunEnabled() ? "dry-run" : "applied";
if (!isDryRunEnabled()) {
List<List<String>> commands = "RATE_LIMIT".equals(mode)
? adapter.buildRateLimitCommands(normalizedIp, limitPerMinute)
: adapter.buildBlockCommands(normalizedIp);
success = executeCommands(commands);
status = success ? "applied" : "execution-failed";
}
long expiresAt = durationMinutes > 0
? System.currentTimeMillis() + durationMinutes * 60_000L
: 0;
ManagedRule rule = new ManagedRule(normalizedIp, mode, reason, durationMinutes, limitPerMinute, expiresAt, adapter.getName());
desiredRules.put(rule.getKey(), rule);
return record(new EnforcementActionResult(success, mode, adapter.getName(), isDryRunEnabled(),
status, preview, reason, normalizedIp, durationMinutes, limitPerMinute));
}
private ManagedRule findRule(String ip, String mode) {
return desiredRules.values().stream()
.filter(rule -> Objects.equals(rule.ip, ip))
.filter(rule -> mode == null || Objects.equals(rule.mode, mode))
.findFirst()
.orElse(null);
}
private EnforcementActionResult record(EnforcementActionResult result) {
actionLog.offer(result);
while (actionLog.size() > 1000) {
actionLog.poll();
}
logger.info("Host enforcement {} {} via {} [{}]", result.action, result.ip, result.backend, result.status);
return result;
}
private boolean executeCommands(List<List<String>> commands) {
boolean success = true;
for (List<String> command : commands) {
ProcessBuilder builder = new ProcessBuilder(command);
builder.redirectErrorStream(true);
try {
Process process = builder.start();
int exitCode = process.waitFor();
if (exitCode != 0) {
success = false;
logger.warn("Host enforcement command failed: {}", String.join(" ", command));
}
} catch (IOException | InterruptedException e) {
success = false;
logger.warn("Host enforcement execution error: {}", e.getMessage());
Thread.currentThread().interrupt();
}
}
return success;
}
private HostFirewallAdapter resolveAdapter() {
String preferred = config.getSecurity().getHostEnforcement().getPreferredBackend();
if ("ufw".equalsIgnoreCase(preferred)) {
return commandAvailable("ufw") ? new UfwAdapter() : new NoopAdapter();
}
if ("iptables".equalsIgnoreCase(preferred)) {
return commandAvailable("iptables") ? new IptablesAdapter() : new NoopAdapter();
}
if (commandAvailable("ufw")) {
return new UfwAdapter();
}
if (commandAvailable("iptables")) {
return new IptablesAdapter();
}
return new NoopAdapter();
}
private boolean commandAvailable(String binary) {
try {
Process process = new ProcessBuilder("sh", "-lc", "command -v " + binary).start();
return process.waitFor() == 0;
} catch (IOException | InterruptedException e) {
Thread.currentThread().interrupt();
return false;
}
}
private boolean isEnabled() {
return config.getSecurity().getHostEnforcement().isEnabled();
}
private boolean isDryRunEnabled() {
return !isEnabled() || config.getSecurity().getHostEnforcement().isDryRun();
}
private String normalizeIp(String ip) {
if (ip == null) {
return null;
}
String normalized = ip.trim();
if (normalized.isEmpty() || !IP_PATTERN.matcher(normalized).matches()) {
return null;
}
return normalized;
}
private interface HostFirewallAdapter {
String getName();
List<List<String>> buildBlockCommands(String ip);
List<List<String>> buildReleaseCommands(String ip, String mode);
List<List<String>> buildRateLimitCommands(String ip, int limitPerMinute);
List<String> previewBlockCommands(String ip);
List<String> previewReleaseCommands(String ip, String mode);
List<String> previewRateLimitCommands(String ip, int limitPerMinute);
}
private static final class UfwAdapter implements HostFirewallAdapter {
@Override
public String getName() {
return "ufw";
}
@Override
public List<List<String>> buildBlockCommands(String ip) {
return List.of(List.of("sudo", "ufw", "deny", "from", ip));
}
@Override
public List<List<String>> buildReleaseCommands(String ip, String mode) {
return List.of(List.of("sudo", "ufw", "delete", "deny", "from", ip));
}
@Override
public List<List<String>> buildRateLimitCommands(String ip, int limitPerMinute) {
return List.of(List.of("sudo", "ufw", "limit", "from", ip));
}
@Override
public List<String> previewBlockCommands(String ip) {
return List.of("sudo ufw deny from " + ip);
}
@Override
public List<String> previewReleaseCommands(String ip, String mode) {
return List.of("sudo ufw delete deny from " + ip);
}
@Override
public List<String> previewRateLimitCommands(String ip, int limitPerMinute) {
return List.of("sudo ufw limit from " + ip + " # ~" + limitPerMinute + "/min");
}
}
private static final class IptablesAdapter implements HostFirewallAdapter {
@Override
public String getName() {
return "iptables";
}
@Override
public List<List<String>> buildBlockCommands(String ip) {
return List.of(List.of("sudo", "iptables", "-I", "INPUT", "-s", ip, "-j", "DROP"));
}
@Override
public List<List<String>> buildReleaseCommands(String ip, String mode) {
if ("RATE_LIMIT".equalsIgnoreCase(mode)) {
return List.of(List.of("sudo", "iptables", "-D", "INPUT", "-s", ip, "-m", "limit", "--limit", "1/second", "-j", "ACCEPT"));
}
return List.of(List.of("sudo", "iptables", "-D", "INPUT", "-s", ip, "-j", "DROP"));
}
@Override
public List<List<String>> buildRateLimitCommands(String ip, int limitPerMinute) {
String rate = Math.max(1, limitPerMinute) + "/minute";
return List.of(
List.of("sudo", "iptables", "-I", "INPUT", "-s", ip, "-m", "limit", "--limit", rate, "-j", "ACCEPT"),
List.of("sudo", "iptables", "-A", "INPUT", "-s", ip, "-j", "DROP")
);
}
@Override
public List<String> previewBlockCommands(String ip) {
return List.of("sudo iptables -I INPUT -s " + ip + " -j DROP");
}
@Override
public List<String> previewReleaseCommands(String ip, String mode) {
if ("RATE_LIMIT".equalsIgnoreCase(mode)) {
return List.of("sudo iptables -D INPUT -s " + ip + " -m limit --limit 1/second -j ACCEPT");
}
return List.of("sudo iptables -D INPUT -s " + ip + " -j DROP");
}
@Override
public List<String> previewRateLimitCommands(String ip, int limitPerMinute) {
String rate = Math.max(1, limitPerMinute) + "/minute";
return List.of(
"sudo iptables -I INPUT -s " + ip + " -m limit --limit " + rate + " -j ACCEPT",
"sudo iptables -A INPUT -s " + ip + " -j DROP"
);
}
}
private static final class NoopAdapter implements HostFirewallAdapter {
@Override
public String getName() {
return "noop";
}
@Override
public List<List<String>> buildBlockCommands(String ip) {
return Collections.emptyList();
}
@Override
public List<List<String>> buildReleaseCommands(String ip, String mode) {
return Collections.emptyList();
}
@Override
public List<List<String>> buildRateLimitCommands(String ip, int limitPerMinute) {
return Collections.emptyList();
}
@Override
public List<String> previewBlockCommands(String ip) {
return List.of("noop block " + ip);
}
@Override
public List<String> previewReleaseCommands(String ip, String mode) {
return List.of("noop release " + ip);
}
@Override
public List<String> previewRateLimitCommands(String ip, int limitPerMinute) {
return List.of("noop rate-limit " + ip + " " + limitPerMinute + "/minute");
}
}
public static class ManagedRule {
private final String ip;
private final String mode;
private final String reason;
private final int durationMinutes;
private final int limitPerMinute;
private final long createdAt;
private final long expiresAt;
private final String backend;
public ManagedRule(String ip, String mode, String reason, int durationMinutes, int limitPerMinute, long expiresAt, String backend) {
this.ip = ip;
this.mode = mode;
this.reason = reason;
this.durationMinutes = durationMinutes;
this.limitPerMinute = limitPerMinute;
this.createdAt = System.currentTimeMillis();
this.expiresAt = expiresAt;
this.backend = backend;
}
public String getKey() {
return ip + ":" + mode;
}
public String getIp() { return ip; }
public String getMode() { return mode; }
public String getReason() { return reason; }
public int getDurationMinutes() { return durationMinutes; }
public int getLimitPerMinute() { return limitPerMinute; }
public long getCreatedAt() { return createdAt; }
public long getExpiresAt() { return expiresAt; }
public String getBackend() { return backend; }
}
public static class EnforcementActionResult {
private final boolean success;
private final String action;
private final String backend;
private final boolean dryRun;
private final String status;
private final List<String> commands;
private final String reason;
private final String ip;
private final int durationMinutes;
private final int limitPerMinute;
private final long timestamp;
public EnforcementActionResult(boolean success, String action, String backend, boolean dryRun, String status,
List<String> commands, String reason, String ip, int durationMinutes, int limitPerMinute) {
this.success = success;
this.action = action;
this.backend = backend;
this.dryRun = dryRun;
this.status = status;
this.commands = commands;
this.reason = reason;
this.ip = ip;
this.durationMinutes = durationMinutes;
this.limitPerMinute = limitPerMinute;
this.timestamp = Instant.now().toEpochMilli();
}
public boolean isSuccess() { return success; }
public String getAction() { return action; }
public String getBackend() { return backend; }
public boolean isDryRun() { return dryRun; }
public String getStatus() { return status; }
public List<String> getCommands() { return commands; }
public String getReason() { return reason; }
public String getIp() { return ip; }
public int getDurationMinutes() { return durationMinutes; }
public int getLimitPerMinute() { return limitPerMinute; }
public long getTimestamp() { return timestamp; }
}
}
@@ -0,0 +1,275 @@
package com.aluer.security;
import com.aluer.config.ServerGuardConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentLinkedQueue;
@Service
public class HostIntrusionCountermeasureService {
private final ServerGuardConfig config;
private final EndpointDetectionResponseService endpointDetectionResponseService;
private final AdvancedMalwareDetectionService advancedMalwareDetectionService;
private final IntrusionDetectionService intrusionDetectionService;
private final FileIntegrityMonitorService fileIntegrityMonitorService;
private final CommandExecutionGuardService commandExecutionGuardService;
private final ConcurrentLinkedQueue<HostIntrusionIncident> incidents = new ConcurrentLinkedQueue<>();
public HostIntrusionCountermeasureService() {
this(new ServerGuardConfig(), new EndpointDetectionResponseService(), new AdvancedMalwareDetectionService(),
new IntrusionDetectionService(), new FileIntegrityMonitorService(), new CommandExecutionGuardService());
}
@Autowired
public HostIntrusionCountermeasureService(ServerGuardConfig config,
EndpointDetectionResponseService endpointDetectionResponseService,
AdvancedMalwareDetectionService advancedMalwareDetectionService,
IntrusionDetectionService intrusionDetectionService,
FileIntegrityMonitorService fileIntegrityMonitorService,
CommandExecutionGuardService commandExecutionGuardService) {
this.config = config;
this.endpointDetectionResponseService = endpointDetectionResponseService;
this.advancedMalwareDetectionService = advancedMalwareDetectionService;
this.intrusionDetectionService = intrusionDetectionService;
this.fileIntegrityMonitorService = fileIntegrityMonitorService;
this.commandExecutionGuardService = commandExecutionGuardService;
}
public HostIntrusionIncident analyzeCommand(String actor, String command, String source) {
CommandExecutionGuardService.AntiIntrusionIncident incident = commandExecutionGuardService.analyzeCommand(actor, command, source);
if (incident == null) {
return null;
}
HostIntrusionIncident hostIncident = new HostIntrusionIncident(
incident.getType(),
"COMMAND",
incident.getSeverity(),
actor,
source,
incident.getEvidence(),
incident.getTimestamp()
);
record(hostIncident);
return hostIncident;
}
public HostIntrusionIncident analyzeProcess(String processName, String source) {
if (!config.getSecurity().getAntiIntrusion().isMonitorProcesses()) {
return null;
}
String normalized = processName == null ? "" : processName.toLowerCase(Locale.ROOT);
intrusionDetectionService.checkProcessActivity("system", processName, true);
if (!(normalized.contains("curl")
|| normalized.contains("wget")
|| normalized.contains("nc ")
|| normalized.contains("socat")
|| normalized.contains("xmrig")
|| normalized.contains("python -c")
|| normalized.contains("bash -c"))) {
return null;
}
HostIntrusionIncident incident = new HostIntrusionIncident(
"SUSPICIOUS_PROCESS",
"PROCESS",
88,
"system",
source,
processName,
Instant.now().toEpochMilli()
);
record(incident);
return incident;
}
public HostIntrusionIncident analyzeFile(String path) {
if (!config.getSecurity().getAntiIntrusion().isMonitorFiles()) {
return null;
}
Path target = Paths.get(path);
if (!Files.exists(target) || !Files.isRegularFile(target)) {
return null;
}
try {
byte[] content = Files.readAllBytes(target);
String hash = sha256(content);
AdvancedMalwareDetectionService.ScanResult scanResult = advancedMalwareDetectionService.scanFile(target.getFileName().toString(), content, hash);
if (scanResult.isThreatDetected()) {
HostIntrusionIncident incident = new HostIntrusionIncident(
"MALWARE_OR_BACKDOOR",
"FILE",
severityToScore(scanResult.getThreatSeverity()),
"system",
path,
scanResult.getThreatName() + ": " + scanResult.getThreatDescription(),
Instant.now().toEpochMilli()
);
intrusionDetectionService.checkFileAccess("system", path, "scan");
record(incident);
return incident;
}
} catch (IOException e) {
return new HostIntrusionIncident("FILE_SCAN_ERROR", "FILE", 50, "system", path, e.getMessage(), Instant.now().toEpochMilli());
}
return null;
}
public Map<String, Object> runFullScan() {
Map<String, Object> integrity = fileIntegrityMonitorService.scanNow();
List<HostIntrusionIncident> detected = new ArrayList<>();
if (config.getSecurity().getAntiIntrusion().isMonitorPlugins()) {
for (String file : discoverPluginFiles()) {
HostIntrusionIncident incident = analyzeFile(file);
if (incident != null) {
detected.add(incident);
}
}
}
for (FileIntegrityMonitorService.IntegrityAlert alert : fileIntegrityMonitorService.getRecentAlerts(20)) {
record(new HostIntrusionIncident(
"FILE_INTEGRITY_" + alert.getType(),
"INTEGRITY",
82,
"integrity-monitor",
alert.getPath(),
alert.getDetails(),
alert.getTimestamp()
));
}
Map<String, Object> result = new LinkedHashMap<>();
result.put("integrity", integrity);
result.put("detectedIncidents", detected.size());
result.put("recentIncidents", getRecentIncidents(10));
return result;
}
public Map<String, Object> getPosture() {
Map<String, Object> posture = new LinkedHashMap<>();
posture.put("enabled", config.getSecurity().getAntiIntrusion().isEnabled());
posture.put("recentIncidents", incidents.size());
posture.put("criticalIncidents", incidents.stream().filter(incident -> incident.severity >= 90).count());
posture.put("fileIntegrity", fileIntegrityMonitorService.getBaselineStatus());
posture.put("commandGuard", commandExecutionGuardService.getStats());
posture.put("edr", endpointDetectionResponseService.getStats());
return posture;
}
public List<HostIntrusionIncident> getRecentIncidents(int limit) {
List<HostIntrusionIncident> result = new ArrayList<>();
int count = 0;
for (HostIntrusionIncident incident : incidents) {
if (count++ >= limit) {
break;
}
result.add(incident);
}
result.sort(Comparator.comparingLong(HostIntrusionIncident::getTimestamp).reversed());
return result;
}
public List<FileIntegrityMonitorService.IntegrityAlert> getIntegrityAlerts(int limit) {
return fileIntegrityMonitorService.getRecentAlerts(limit);
}
private List<String> discoverPluginFiles() {
List<String> files = new ArrayList<>();
for (String configuredPath : config.getSecurity().getAntiIntrusion().getFileIntegrity().getMonitoredPaths()) {
Path path = Paths.get(configuredPath);
try {
if (Files.isDirectory(path) && configuredPath.toLowerCase(Locale.ROOT).contains("plugins")) {
try (var stream = Files.walk(path, 2)) {
stream.filter(Files::isRegularFile).forEach(file -> files.add(file.toString()));
}
} else if (Files.isRegularFile(path) && path.getFileName().toString().endsWith(".jar")) {
files.add(path.toString());
}
} catch (IOException ignored) {
}
}
return files;
}
private void record(HostIntrusionIncident incident) {
incidents.offer(incident);
while (incidents.size() > 1000) {
incidents.poll();
}
}
private int severityToScore(String severity) {
if (severity == null) {
return 50;
}
return switch (severity.toUpperCase(Locale.ROOT)) {
case "CRITICAL" -> 95;
case "HIGH" -> 85;
case "MEDIUM" -> 70;
default -> 55;
};
}
private String sha256(byte[] content) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(content);
StringBuilder builder = new StringBuilder();
for (byte b : hash) {
builder.append(String.format("%02x", b));
}
return builder.toString();
} catch (NoSuchAlgorithmException e) {
return Integer.toHexString(content.length);
}
}
public static class HostIntrusionIncident {
private final String type;
private final String category;
private final int severity;
private final String actor;
private final String source;
private final String details;
private final long timestamp;
public HostIntrusionIncident(String type, String category, int severity, String actor, String source, String details, long timestamp) {
this.type = type;
this.category = category;
this.severity = severity;
this.actor = actor;
this.source = source;
this.details = details;
this.timestamp = timestamp;
}
public String getType() { return type; }
public String getCategory() { return category; }
public int getSeverity() { return severity; }
public String getActor() { return actor; }
public String getSource() { return source; }
public String getDetails() { return details; }
public long getTimestamp() { return timestamp; }
}
}
@@ -0,0 +1,317 @@
package com.aluer.security;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
@Service
public class IPReputationService {
private final Map<String, IPProfile> ipProfiles = new ConcurrentHashMap<>();
private final Map<String, List<ReputationEvent>> reputationHistory = new ConcurrentHashMap<>();
private final Set<String> blacklistedIPs = ConcurrentHashMap.newKeySet();
private final Set<String> whitelistedIPs = ConcurrentHashMap.newKeySet();
private final Queue<ReputationAlert> alerts = new ConcurrentLinkedQueue<>();
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
private static final double DEFAULT_REPUTATION_SCORE = 50.0;
private static final double MAX_SCORE = 100.0;
private static final double MIN_SCORE = 0.0;
private static final long SCORE_DECAY_TIME = 86400000;
private final AtomicLong totalEvaluations = new AtomicLong(0);
public IPReputationService() {
startReputationTask();
}
public double evaluateIP(String ip) {
totalEvaluations.incrementAndGet();
if (whitelistedIPs.contains(ip)) {
return MAX_SCORE;
}
if (blacklistedIPs.contains(ip)) {
return MIN_SCORE;
}
IPProfile profile = ipProfiles.computeIfAbsent(ip, k -> new IPProfile(ip));
double score = profile.calculateScore();
if (score < 20) {
addAlert(ip, "LOW_REPUTATION", "IP reputation score below threshold: " + score);
}
return score;
}
public void recordSuccessfulConnection(String ip) {
IPProfile profile = ipProfiles.computeIfAbsent(ip, k -> new IPProfile(ip));
profile.recordSuccess();
ReputationEvent event = new ReputationEvent(ip, "SUCCESS", "Connection successful", System.currentTimeMillis());
addToHistory(ip, event);
}
public void recordFailedConnection(String ip, String reason) {
IPProfile profile = ipProfiles.computeIfAbsent(ip, k -> new IPProfile(ip));
profile.recordFailure();
ReputationEvent event = new ReputationEvent(ip, "FAILURE", reason, System.currentTimeMillis());
addToHistory(ip, event);
if (profile.failures.get() > 10) {
addAlert(ip, "REPEAT_FAILURES", "Multiple failed connections: " + profile.failures.get());
}
}
public void recordSuspiciousActivity(String ip, String activityType) {
IPProfile profile = ipProfiles.computeIfAbsent(ip, k -> new IPProfile(ip));
profile.recordSuspicious(activityType);
ReputationEvent event = new ReputationEvent(ip, "SUSPICIOUS", activityType, System.currentTimeMillis());
addToHistory(ip, event);
if (profile.suspiciousCount.get() > 5) {
addAlert(ip, "SUSPICIOUS_ACTIVITY", "Multiple suspicious activities: " + activityType);
}
}
public void recordAttack(String ip, String attackType) {
IPProfile profile = ipProfiles.computeIfAbsent(ip, k -> new IPProfile(ip));
profile.recordAttack(attackType);
ReputationEvent event = new ReputationEvent(ip, "ATTACK", attackType, System.currentTimeMillis());
addToHistory(ip, event);
addAlert(ip, "ATTACK_DETECTED", "Attack detected: " + attackType);
}
public void addToBlacklist(String ip) {
blacklistedIPs.add(ip);
whitelistedIPs.remove(ip);
IPProfile profile = ipProfiles.get(ip);
if (profile != null) {
profile.blacklisted = true;
}
ReputationEvent event = new ReputationEvent(ip, "BLACKLIST", "Added to blacklist", System.currentTimeMillis());
addToHistory(ip, event);
}
public void removeFromBlacklist(String ip) {
blacklistedIPs.remove(ip);
IPProfile profile = ipProfiles.get(ip);
if (profile != null) {
profile.blacklisted = false;
}
ReputationEvent event = new ReputationEvent(ip, "UNBLACKLIST", "Removed from blacklist", System.currentTimeMillis());
addToHistory(ip, event);
}
public void addToWhitelist(String ip) {
whitelistedIPs.add(ip);
blacklistedIPs.remove(ip);
IPProfile profile = ipProfiles.computeIfAbsent(ip, k -> new IPProfile(ip));
profile.whitelisted = true;
profile.score = MAX_SCORE;
ReputationEvent event = new ReputationEvent(ip, "WHITELIST", "Added to whitelist", System.currentTimeMillis());
addToHistory(ip, event);
}
public void removeFromWhitelist(String ip) {
whitelistedIPs.remove(ip);
IPProfile profile = ipProfiles.get(ip);
if (profile != null) {
profile.whitelisted = false;
}
}
public boolean isBlacklisted(String ip) {
return blacklistedIPs.contains(ip);
}
public boolean isWhitelisted(String ip) {
return whitelistedIPs.contains(ip);
}
public IPProfile getProfile(String ip) {
return ipProfiles.get(ip);
}
public Collection<IPProfile> getAllProfiles() {
return ipProfiles.values();
}
public List<ReputationEvent> getHistory(String ip, int limit) {
List<ReputationEvent> history = reputationHistory.get(ip);
if (history == null) {
return new ArrayList<>();
}
return history.stream().limit(limit).toList();
}
private void addToHistory(String ip, ReputationEvent event) {
List<ReputationEvent> history = reputationHistory.computeIfAbsent(ip, k -> new CopyOnWriteArrayList<>());
history.add(event);
while (history.size() > 100) {
history.remove(0);
}
}
private void addAlert(String ip, String type, String details) {
ReputationAlert alert = new ReputationAlert(ip, type, details, System.currentTimeMillis());
alerts.offer(alert);
while (alerts.size() > 500) {
alerts.poll();
}
}
public List<ReputationAlert> getAlerts(int limit) {
List<ReputationAlert> result = new ArrayList<>();
int count = 0;
for (ReputationAlert alert : alerts) {
if (count++ >= limit) break;
result.add(alert);
}
return result;
}
private void startReputationTask() {
scheduler.scheduleAtFixedRate(() -> {
for (IPProfile profile : ipProfiles.values()) {
if (profile.whitelisted || profile.blacklisted) {
continue;
}
if (System.currentTimeMillis() - profile.lastUpdate > SCORE_DECAY_TIME) {
profile.applyDecay();
}
}
reputationHistory.entrySet().removeIf(entry -> {
List<ReputationEvent> history = entry.getValue();
history.removeIf(e -> System.currentTimeMillis() - e.timestamp > SCORE_DECAY_TIME);
return history.isEmpty();
});
}, 3600, 3600, TimeUnit.SECONDS);
}
public Map<String, Object> getStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("totalProfiles", ipProfiles.size());
stats.put("blacklisted", blacklistedIPs.size());
stats.put("whitelisted", whitelistedIPs.size());
stats.put("totalEvaluations", totalEvaluations.get());
return stats;
}
public static class IPProfile {
public final String ip;
public final AtomicLong successes = new AtomicLong(0);
public final AtomicLong failures = new AtomicLong(0);
public final AtomicInteger suspiciousCount = new AtomicInteger(0);
public final Map<String, AtomicInteger> attackCounts = new ConcurrentHashMap<>();
public volatile double score = DEFAULT_REPUTATION_SCORE;
public volatile boolean whitelisted = false;
public volatile boolean blacklisted = false;
public volatile long lastUpdate;
public IPProfile(String ip) {
this.ip = ip;
this.lastUpdate = System.currentTimeMillis();
this.score = DEFAULT_REPUTATION_SCORE;
}
public void recordSuccess() {
successes.incrementAndGet();
score = Math.min(MAX_SCORE, score + 2);
lastUpdate = System.currentTimeMillis();
}
public void recordFailure() {
failures.incrementAndGet();
score = Math.max(MIN_SCORE, score - 5);
lastUpdate = System.currentTimeMillis();
}
public void recordSuspicious(String activityType) {
suspiciousCount.incrementAndGet();
score = Math.max(MIN_SCORE, score - 10);
lastUpdate = System.currentTimeMillis();
}
public void recordAttack(String attackType) {
attackCounts.computeIfAbsent(attackType, k -> new AtomicInteger(0)).incrementAndGet();
score = Math.max(MIN_SCORE, score - 20);
lastUpdate = System.currentTimeMillis();
}
public void applyDecay() {
score = Math.max(MIN_SCORE, score - 1);
lastUpdate = System.currentTimeMillis();
}
public double calculateScore() {
if (whitelisted) return MAX_SCORE;
if (blacklisted) return MIN_SCORE;
double baseScore = 50.0;
long totalAttempts = successes.get() + failures.get();
if (totalAttempts > 0) {
double successRate = (double) successes.get() / totalAttempts;
baseScore += successRate * 30;
}
baseScore -= failures.get() * 2;
baseScore -= suspiciousCount.get() * 5;
for (AtomicInteger count : attackCounts.values()) {
baseScore -= count.get() * 10;
}
return Math.max(MIN_SCORE, Math.min(MAX_SCORE, baseScore));
}
}
public static class ReputationEvent {
public final String ip;
public final String type;
public final String details;
public final long timestamp;
public ReputationEvent(String ip, String type, String details, long timestamp) {
this.ip = ip;
this.type = type;
this.details = details;
this.timestamp = timestamp;
}
}
public static class ReputationAlert {
public final String ip;
public final String type;
public final String details;
public final long timestamp;
public ReputationAlert(String ip, String type, String details, long timestamp) {
this.ip = ip;
this.type = type;
this.details = details;
this.timestamp = timestamp;
}
}
}
@@ -0,0 +1,467 @@
package com.aluer.security;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.security.MessageDigest;
import java.nio.file.*;
import java.io.*;
@Service
public class IntrusionDetectionService {
private final Map<String, IntrusionAlert> activeAlerts = new ConcurrentHashMap<>();
private final Map<String, SuspiciousActivity> activityLog = new ConcurrentHashMap<>();
private final Map<String, List<LoginAttempt>> loginAttempts = new ConcurrentHashMap<>();
private final Map<String, UserBehavior> userBehaviors = new ConcurrentHashMap<>();
private final Queue<IntrusionEvent> events = new ConcurrentLinkedQueue<>();
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(3);
private static final int MAX_LOGIN_ATTEMPTS = 5;
private static final long LOGIN_TIMEOUT = 300000;
private static final int MAX_ALERTS = 1000;
private static final double ANOMALY_THRESHOLD = 0.8;
private final AtomicInteger alertLevel = new AtomicInteger(0);
private final AtomicLong totalIntrusions = new AtomicLong(0);
public IntrusionDetectionService() {
startDetectionTask();
}
public boolean checkLoginAttempt(String username, String ip, boolean success) {
List<LoginAttempt> attempts = loginAttempts.computeIfAbsent(username.toLowerCase(), k -> new CopyOnWriteArrayList<>());
long now = System.currentTimeMillis();
attempts.removeIf(a -> now - a.timestamp > LOGIN_TIMEOUT);
if (!success) {
LoginAttempt attempt = new LoginAttempt(username, ip, false, now);
attempts.add(attempt);
if (attempts.size() >= MAX_LOGIN_ATTEMPTS) {
triggerAlert("BRUTE_FORCE", username, "Failed login attempts: " + attempts.size(), ip);
return false;
}
} else {
LoginAttempt attempt = new LoginAttempt(username, ip, true, now);
attempts.clear();
attempts.add(attempt);
}
return true;
}
public void recordFailedLogin(String username, String ip, String reason) {
List<LoginAttempt> attempts = loginAttempts.computeIfAbsent(username.toLowerCase(), k -> new CopyOnWriteArrayList<>());
attempts.add(new LoginAttempt(username, ip, false, System.currentTimeMillis()));
recordActivity(username, "LOGIN_FAILED", reason, ip);
if (attempts.size() >= MAX_LOGIN_ATTEMPTS) {
triggerAlert("BRUTE_FORCE", username, "Account: " + username, ip);
}
}
public void recordSuccessfulLogin(String username, String ip) {
List<LoginAttempt> attempts = loginAttempts.get(username.toLowerCase());
if (attempts != null) {
attempts.clear();
}
recordActivity(username, "LOGIN_SUCCESS", "Login successful", ip);
}
public void recordActivity(String username, String activityType, String details, String ip) {
String key = username + ":" + activityType;
SuspiciousActivity activity = activityLog.computeIfAbsent(key, k -> new SuspiciousActivity(username, activityType));
activity.addOccurrence(details, ip);
if (activity.isSuspicious()) {
triggerAlert("ANOMALY_DETECTED", username, activityType + ": " + details, ip);
}
}
public void analyzeBehavior(String username, Map<String, Object> metrics) {
UserBehavior behavior = userBehaviors.computeIfAbsent(username, k -> new UserBehavior(username));
double cpuUsage = getMetricValue(metrics, "cpu");
double memoryUsage = getMetricValue(metrics, "memory");
double networkIn = getMetricValue(metrics, "network_in");
double networkOut = getMetricValue(metrics, "network_out");
int fileAccess = getMetricInt(metrics, "file_access");
int processCount = getMetricInt(metrics, "processes");
behavior.addSample(cpuUsage, memoryUsage, networkIn, networkOut, fileAccess, processCount);
if (behavior.isAnomalous()) {
triggerAlert("BEHAVIOR_ANOMALY", username, "Unusual behavior pattern detected", "system");
}
}
private double getMetricValue(Map<String, Object> metrics, String key) {
Object value = metrics.get(key);
if (value instanceof Number) {
return ((Number) value).doubleValue();
}
return 0.0;
}
private int getMetricInt(Map<String, Object> metrics, String key) {
Object value = metrics.get(key);
if (value instanceof Number) {
return ((Number) value).intValue();
}
return 0;
}
public void checkFileAccess(String username, String filePath, String operation) {
if (isSensitivePath(filePath)) {
recordActivity(username, "SENSITIVE_FILE_ACCESS", operation + ": " + filePath, "system");
triggerAlert("FILE_ACCESS_VIOLATION", username, "Access to sensitive file: " + filePath, "system");
}
}
private boolean isSensitivePath(String path) {
String[] sensitive = {"/etc/passwd", "/etc/shadow", "/root", "/var/log",
"C:\\Windows\\System32", "C:\\Windows\\System", "config"};
for (String s : sensitive) {
if (path.contains(s)) {
return true;
}
}
return false;
}
public void checkProcessActivity(String username, String processName, boolean isNew) {
if (isSuspiciousProcess(processName)) {
recordActivity(username, "SUSPICIOUS_PROCESS", processName, "system");
triggerAlert("MALICIOUS_PROCESS", username, "Suspicious process: " + processName, "system");
}
}
private boolean isSuspiciousProcess(String processName) {
String[] suspicious = {"nc ", "netcat", "ncat", "socat", "meterpreter",
"mimikatz", "pwdump", "lsass", "procmon"};
for (String s : suspicious) {
if (processName.toLowerCase().contains(s.toLowerCase())) {
return true;
}
}
return false;
}
public void checkNetworkConnection(String username, String remoteIP, int port) {
if (isSuspiciousPort(port)) {
recordActivity(username, "SUSPICIOUS_CONNECTION", remoteIP + ":" + port, remoteIP);
triggerAlert("SUSPICIOUS_CONNECTION", username, "Connection to suspicious port: " + port, remoteIP);
}
if (isKnownMaliciousIP(remoteIP)) {
triggerAlert("MALICIOUS_IP", username, "Known malicious IP: " + remoteIP, remoteIP);
}
}
private boolean isSuspiciousPort(int port) {
int[] suspicious = {4444, 5555, 6666, 7777, 8888, 31337, 12345, 54321};
for (int p : suspicious) {
if (port == p) {
return true;
}
}
return false;
}
private boolean isKnownMaliciousIP(String ip) {
return false;
}
public void checkCommandExecution(String username, String command) {
if (isDangerousCommand(command)) {
recordActivity(username, "DANGEROUS_COMMAND", command, "system");
triggerAlert("COMMAND_INJECTION", username, "Dangerous command: " + command, "system");
}
}
private boolean isDangerousCommand(String command) {
String[] dangerous = {"rm -rf", "dd if", "mkfs", "shutdown", "reboot",
"wget |", "curl |", "nc -e", "bash -i"};
for (String d : dangerous) {
if (command.toLowerCase().contains(d.toLowerCase())) {
return true;
}
}
return false;
}
public void checkPrivilegeEscalation(String username, String attemptedAction) {
recordActivity(username, "PRIVILEGE_ESCALATION", attemptedAction, "system");
triggerAlert("PRIVILEGE_ESCALATION", username, "Privilege escalation attempt: " + attemptedAction, "system");
}
public void triggerAlert(String type, String username, String details, String sourceIP) {
String alertKey = type + ":" + username + ":" + System.currentTimeMillis();
IntrusionAlert alert = new IntrusionAlert(type, username, details, sourceIP);
activeAlerts.put(alertKey, alert);
totalIntrusions.incrementAndGet();
logEvent(type, username, details, sourceIP);
updateAlertLevel(type);
while (activeAlerts.size() > MAX_ALERTS) {
String firstKey = activeAlerts.keySet().iterator().next();
activeAlerts.remove(firstKey);
}
}
private void updateAlertLevel(String alertType) {
int current = alertLevel.get();
int newLevel = switch (alertType) {
case "BRUTE_FORCE", "FILE_ACCESS_VIOLATION" -> Math.min(current + 1, 3);
case "MALICIOUS_PROCESS", "MALICIOUS_IP" -> Math.min(current + 2, 3);
case "PRIVILEGE_ESCALATION", "COMMAND_INJECTION" -> 3;
default -> current;
};
alertLevel.set(newLevel);
}
public IntrusionAlert getAlert(String alertKey) {
return activeAlerts.get(alertKey);
}
public Collection<IntrusionAlert> getActiveAlerts() {
return activeAlerts.values();
}
public boolean acknowledgeAlert(String alertKey) {
return activeAlerts.remove(alertKey) != null;
}
public void clearAlerts() {
activeAlerts.clear();
}
public void logEvent(String type, String username, String details, String sourceIP) {
IntrusionEvent event = new IntrusionEvent(type, username, details, sourceIP, System.currentTimeMillis());
events.offer(event);
while (events.size() > 10000) {
events.poll();
}
}
public List<IntrusionEvent> getEvents(int limit) {
List<IntrusionEvent> result = new ArrayList<>();
int count = 0;
for (IntrusionEvent event : events) {
if (count++ >= limit) break;
result.add(event);
}
return result;
}
public int getAlertLevel() {
return alertLevel.get();
}
public void setAlertLevel(int level) {
alertLevel.set(Math.max(0, Math.min(3, level)));
}
private void startDetectionTask() {
scheduler.scheduleAtFixedRate(() -> {
long now = System.currentTimeMillis();
activityLog.entrySet().removeIf(entry ->
now - entry.getValue().lastActivity > 3600000);
loginAttempts.entrySet().removeIf(entry -> {
entry.getValue().removeIf(a -> now - a.timestamp > LOGIN_TIMEOUT);
return entry.getValue().isEmpty();
});
if (alertLevel.get() > 0) {
alertLevel.decrementAndGet();
}
}, 60, 60, TimeUnit.SECONDS);
}
public Map<String, Object> getStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("activeAlerts", activeAlerts.size());
stats.put("totalIntrusions", totalIntrusions.get());
stats.put("alertLevel", alertLevel.get());
stats.put("trackedUsers", userBehaviors.size());
return stats;
}
public static class IntrusionAlert {
public final String type;
public final String username;
public final String details;
public final String sourceIP;
public final long timestamp;
public boolean acknowledged = false;
public IntrusionAlert(String type, String username, String details, String sourceIP) {
this.type = type;
this.username = username;
this.details = details;
this.sourceIP = sourceIP;
this.timestamp = System.currentTimeMillis();
}
}
public static class LoginAttempt {
public final String username;
public final String ip;
public final boolean success;
public final long timestamp;
public LoginAttempt(String username, String ip, boolean success, long timestamp) {
this.username = username;
this.ip = ip;
this.success = success;
this.timestamp = timestamp;
}
}
public static class SuspiciousActivity {
public final String username;
public final String activityType;
public final List<ActivityOccurrence> occurrences = new ArrayList<>();
public volatile long lastActivity;
private int suspiciousCount = 0;
public SuspiciousActivity(String username, String activityType) {
this.username = username;
this.activityType = activityType;
this.lastActivity = System.currentTimeMillis();
}
public void addOccurrence(String details, String ip) {
occurrences.add(new ActivityOccurrence(details, ip, System.currentTimeMillis()));
lastActivity = System.currentTimeMillis();
if (occurrences.size() > 10) {
occurrences.remove(0);
}
if (isRapidFire()) {
suspiciousCount++;
}
}
private boolean isRapidFire() {
if (occurrences.size() < 3) return false;
long timeSpan = occurrences.get(occurrences.size()-1).timestamp - occurrences.get(0).timestamp;
return timeSpan < 1000;
}
public boolean isSuspicious() {
return suspiciousCount > 3 || occurrences.size() > 10;
}
}
public static class ActivityOccurrence {
public final String details;
public final String ip;
public final long timestamp;
public ActivityOccurrence(String details, String ip, long timestamp) {
this.details = details;
this.ip = ip;
this.timestamp = timestamp;
}
}
public static class UserBehavior {
public final String username;
public final List<BehaviorSample> samples = new ArrayList<>();
private double avgCpu = 0, avgMemory = 0, avgNetworkIn = 0, avgNetworkOut = 0;
private double stdCpu = 0, stdMemory = 0;
public UserBehavior(String username) {
this.username = username;
}
public void addSample(double cpu, double memory, double networkIn, double networkOut, int fileAccess, int processes) {
samples.add(new BehaviorSample(cpu, memory, networkIn, networkOut, fileAccess, processes));
if (samples.size() > 100) {
samples.remove(0);
}
recalculateBaselines();
}
private void recalculateBaselines() {
if (samples.isEmpty()) return;
avgCpu = samples.stream().mapToDouble(s -> s.cpu).average().orElse(0);
avgMemory = samples.stream().mapToDouble(s -> s.memory).average().orElse(0);
avgNetworkIn = samples.stream().mapToDouble(s -> s.networkIn).average().orElse(0);
avgNetworkOut = samples.stream().mapToDouble(s -> s.networkOut).average().orElse(0);
double varianceCpu = samples.stream()
.mapToDouble(s -> Math.pow(s.cpu - avgCpu, 2))
.average().orElse(0);
stdCpu = Math.sqrt(varianceCpu);
double varianceMemory = samples.stream()
.mapToDouble(s -> Math.pow(s.memory - avgMemory, 2))
.average().orElse(0);
stdMemory = Math.sqrt(varianceMemory);
}
public boolean isAnomalous() {
if (samples.isEmpty()) return false;
BehaviorSample latest = samples.get(samples.size() - 1);
double cpuDeviation = stdCpu > 0 ? Math.abs(latest.cpu - avgCpu) / stdCpu : 0;
double memDeviation = stdMemory > 0 ? Math.abs(latest.memory - avgMemory) / stdMemory : 0;
return cpuDeviation > ANOMALY_THRESHOLD || memDeviation > ANOMALY_THRESHOLD;
}
}
public static class BehaviorSample {
public final double cpu;
public final double memory;
public final double networkIn;
public final double networkOut;
public final int fileAccess;
public final int processes;
public BehaviorSample(double cpu, double memory, double networkIn, double networkOut, int fileAccess, int processes) {
this.cpu = cpu;
this.memory = memory;
this.networkIn = networkIn;
this.networkOut = networkOut;
this.fileAccess = fileAccess;
this.processes = processes;
}
}
public static class IntrusionEvent {
public final String type;
public final String username;
public final String details;
public final String sourceIP;
public final long timestamp;
public IntrusionEvent(String type, String username, String details, String sourceIP, long timestamp) {
this.type = type;
this.username = username;
this.details = details;
this.sourceIP = sourceIP;
this.timestamp = timestamp;
}
}
}
@@ -0,0 +1,455 @@
package com.aluer.security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicLong;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.security.MessageDigest;
@Component
public class IntrusionPreventionSystem {
private static final Logger logger = LoggerFactory.getLogger(IntrusionPreventionSystem.class);
private final HostEnforcementService hostEnforcementService;
private final CloudflareIntegrationService cloudflareIntegrationService;
private final Map<String, IPSRule> rules = new ConcurrentHashMap<>();
private final Map<String, BlockedEntry> blockedIPs = new ConcurrentHashMap<>();
private final Queue<IPSAlert> alertQueue = new ConcurrentLinkedQueue<>();
private final Map<String, ConnectionTracker> connectionTrackers = new ConcurrentHashMap<>();
private final AtomicLong totalPacketsProcessed = new AtomicLong(0);
private final AtomicLong totalPacketsBlocked = new AtomicLong(0);
private final AtomicLong totalAttacksPrevented = new AtomicLong(0);
private static final int BLOCK_DURATION_MINUTES = 60;
private static final int MAX_CONNECTIONS_PER_MINUTE = 100;
private static final int PACKET_RATE_LIMIT = 1000;
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public IntrusionPreventionSystem() {
this(new HostEnforcementService(), new CloudflareIntegrationService());
}
@Autowired
public IntrusionPreventionSystem(HostEnforcementService hostEnforcementService,
CloudflareIntegrationService cloudflareIntegrationService) {
this.hostEnforcementService = hostEnforcementService;
this.cloudflareIntegrationService = cloudflareIntegrationService;
initializeDefaultRules();
logger.info("Intrusion Prevention System initialized");
}
private void initializeDefaultRules() {
addRule("BLOCK_SSH_BRUTE_FORCE", "HIGH", "TCP", 22,
"(\\w+:){1,100}Failed password", "SSH brute force attack");
addRule("BLOCK_TELNET_BRUTE_FORCE", "HIGH", "TCP", 23,
"(failed|invalid).*login", "Telnet brute force attack");
addRule("BLOCK_FTP_BRUTE_FORCE", "HIGH", "TCP", 21,
"530 Login authentication failed", "FTP brute force attack");
addRule("BLOCK_MYSQL_BRUTE_FORCE", "HIGH", "TCP", 3306,
"Access denied for user", "MySQL brute force attack");
addRule("BLOCK_PORT_SCAN", "MEDIUM", "TCP", 0,
"port.*scan", "Port scan detected");
addRule("BLOCK_SYN_FLOOD", "HIGH", "TCP", 0,
"SYN.*SYN.*SYN", "SYN flood attack");
addRule("BLOCK_UDP_FLOOD", "HIGH", "UDP", 0,
"udp.*flood", "UDP flood attack");
addRule("BLOCK_ICMP_FLOOD", "MEDIUM", "ICMP", 0,
"icmp.*flood", "ICMP flood attack");
addRule("BLOCK_DNS_AMPLIFICATION", "HIGH", "UDP", 53,
"dns.*amplification", "DNS amplification attack");
addRule("BLOCK_SQL_INJECTION", "HIGH", "TCP", 0,
"(union|select|insert|update|delete).*(from|where)", "SQL injection attempt");
addRule("BLOCK_XSS_ATTACK", "HIGH", "TCP", 0,
"<script|javascript:|onerror=", "Cross-site scripting attempt");
addRule("BLOCK_DIRECTORY_TRAVERSAL", "MEDIUM", "TCP", 0,
"(\\.\\./|\\.\\.\\\\)", "Directory traversal attempt");
logger.info("Initialized {} IPS rules", rules.size());
}
public void addRule(String name, String severity, String protocol, int port, String pattern, String description) {
IPSRule rule = new IPSRule(name, severity, protocol, port, pattern, description);
rules.put(name, rule);
logger.info("Added IPS rule: {}", name);
}
public IPSResult processPacket(String sourceIP, String destIP, int sourcePort, int destPort,
String protocol, byte[] payload) {
IPSResult result = new IPSResult();
result.setSourceIP(sourceIP);
result.setDestIP(destIP);
result.setSourcePort(sourcePort);
result.setDestPort(destPort);
result.setProtocol(protocol);
result.setTimestamp(LocalDateTime.now());
totalPacketsProcessed.incrementAndGet();
if (isBlocked(sourceIP)) {
result.setBlocked(true);
result.setReason("IP is already blocked");
totalPacketsBlocked.incrementAndGet();
return result;
}
if (checkRateLimit(sourceIP)) {
blockIP(sourceIP, "Rate limit exceeded", 30);
result.setBlocked(true);
result.setReason("Rate limit exceeded");
totalPacketsBlocked.incrementAndGet();
totalAttacksPrevented.incrementAndGet();
return result;
}
updateConnectionTracker(sourceIP, destIP, destPort, protocol);
for (IPSRule rule : rules.values()) {
if (!rule.isEnabled()) continue;
if (!rule.matchesProtocol(protocol)) continue;
if (rule.getPort() != 0 && rule.getPort() != destPort) continue;
if (payload != null && rule.matchesPayload(new String(payload))) {
result.addMatchedRule(rule.getName());
result.setThreatDetected(true);
if ("HIGH".equals(rule.getSeverity())) {
blockIP(sourceIP, rule.getDescription(), BLOCK_DURATION_MINUTES);
result.setBlocked(true);
result.setReason("Blocked: " + rule.getDescription());
totalPacketsBlocked.incrementAndGet();
totalAttacksPrevented.incrementAndGet();
triggerAlert(sourceIP, destIP, rule);
} else if ("MEDIUM".equals(rule.getSeverity())) {
result.setWarning("Medium severity threat detected: " + rule.getDescription());
triggerAlert(sourceIP, destIP, rule);
}
}
}
return result;
}
private boolean isBlocked(String ip) {
BlockedEntry entry = blockedIPs.get(ip);
if (entry == null) return false;
if (entry.isExpired()) {
blockedIPs.remove(ip);
return false;
}
return true;
}
private void blockIP(String ip, String reason, int durationMinutes) {
BlockedEntry entry = new BlockedEntry(ip, reason, durationMinutes);
blockedIPs.put(ip, entry);
hostEnforcementService.blockIp(ip, reason, durationMinutes);
logger.warn("Blocked IP: {} for {} minutes - Reason: {}", ip, durationMinutes, reason);
}
public void unblockIP(String ip) {
blockedIPs.remove(ip);
hostEnforcementService.releaseIp(ip, "IPS unblock");
logger.info("Unblocked IP: {}", ip);
}
public HostEnforcementService.EnforcementActionResult enforceDecision(String ip, int severity, String reason, boolean challengeEdge) {
if (severity >= 90) {
HostEnforcementService.EnforcementActionResult local = hostEnforcementService.blockIp(ip, reason, BLOCK_DURATION_MINUTES);
if (challengeEdge) {
cloudflareIntegrationService.applyChallenge(ip, reason);
} else {
cloudflareIntegrationService.applyBlock(ip, reason);
}
return local;
}
return hostEnforcementService.rateLimitIp(ip,
hostEnforcementService.getStats().get("managedRules") instanceof Number ? 60 : 60,
reason);
}
private boolean checkRateLimit(String ip) {
ConnectionTracker tracker = connectionTrackers.get(ip);
if (tracker == null) return false;
return tracker.getPacketsPerMinute() > PACKET_RATE_LIMIT;
}
private void updateConnectionTracker(String sourceIP, String destIP, int destPort, String protocol) {
ConnectionTracker tracker = connectionTrackers.computeIfAbsent(sourceIP, k -> new ConnectionTracker(sourceIP));
tracker.recordConnection(destIP, destPort, protocol);
}
private void triggerAlert(String sourceIP, String destIP, IPSRule rule) {
IPSAlert alert = new IPSAlert(
sourceIP,
destIP,
rule.getName(),
rule.getSeverity(),
rule.getDescription(),
LocalDateTime.now()
);
alertQueue.offer(alert);
if (alertQueue.size() > 1000) {
alertQueue.poll();
}
}
public void enableRule(String ruleName) {
IPSRule rule = rules.get(ruleName);
if (rule != null) {
rule.setEnabled(true);
logger.info("Enabled IPS rule: {}", ruleName);
}
}
public void disableRule(String ruleName) {
IPSRule rule = rules.get(ruleName);
if (rule != null) {
rule.setEnabled(false);
logger.info("Disabled IPS rule: {}", ruleName);
}
}
public void addBlockedIP(String ip, String reason, int durationMinutes) {
blockIP(ip, reason, durationMinutes);
}
public Map<String, Object> getStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("totalPacketsProcessed", totalPacketsProcessed.get());
stats.put("totalPacketsBlocked", totalPacketsBlocked.get());
stats.put("totalAttacksPrevented", totalAttacksPrevented.get());
stats.put("activeBlocks", blockedIPs.size());
stats.put("rulesLoaded", rules.size());
stats.put("activeTrackers", connectionTrackers.size());
long highSeverity = rules.values().stream()
.filter(r -> "HIGH".equals(r.getSeverity()) && r.isEnabled())
.count();
stats.put("highSeverityRules", highSeverity);
return stats;
}
public List<BlockedEntry> getBlockedIPs() {
return new ArrayList<>(blockedIPs.values());
}
public List<IPSAlert> getRecentAlerts(int limit) {
List<IPSAlert> alerts = new ArrayList<>();
int count = 0;
for (IPSAlert alert : alertQueue) {
if (count++ >= limit) break;
alerts.add(alert);
}
return alerts;
}
public Map<String, ConnectionTracker> getConnectionTrackers() {
return new HashMap<>(connectionTrackers);
}
public void cleanupExpiredBlocks() {
List<String> expired = new ArrayList<>();
for (Map.Entry<String, BlockedEntry> entry : blockedIPs.entrySet()) {
if (entry.getValue().isExpired()) {
expired.add(entry.getKey());
}
}
for (String ip : expired) {
blockedIPs.remove(ip);
}
if (!expired.isEmpty()) {
logger.info("Cleaned up {} expired blocks", expired.size());
}
}
public static class IPSRule {
private final String name;
private final String severity;
private final String protocol;
private final int port;
private final Pattern pattern;
private final String description;
private volatile boolean enabled = true;
public IPSRule(String name, String severity, String protocol, int port, String pattern, String description) {
this.name = name;
this.severity = severity;
this.protocol = protocol;
this.port = port;
this.pattern = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE);
this.description = description;
}
public boolean matchesProtocol(String protocol) {
return this.protocol.equalsIgnoreCase(protocol) || this.protocol.equalsIgnoreCase("ALL");
}
public boolean matchesPayload(String payload) {
if (payload == null || payload.isEmpty()) return false;
return pattern.matcher(payload).find();
}
public String getName() { return name; }
public String getSeverity() { return severity; }
public String getProtocol() { return protocol; }
public int getPort() { return port; }
public Pattern getPattern() { return pattern; }
public String getDescription() { return description; }
public boolean isEnabled() { return enabled; }
public void setEnabled(boolean enabled) { this.enabled = enabled; }
}
public static class BlockedEntry {
private final String ip;
private final String reason;
private final long blockedAt;
private final long expiresAt;
public BlockedEntry(String ip, String reason, int durationMinutes) {
this.ip = ip;
this.reason = reason;
this.blockedAt = System.currentTimeMillis();
this.expiresAt = blockedAt + (durationMinutes * 60 * 1000L);
}
public boolean isExpired() {
return System.currentTimeMillis() > expiresAt;
}
public String getIp() { return ip; }
public String getReason() { return reason; }
public long getBlockedAt() { return blockedAt; }
public long getExpiresAt() { return expiresAt; }
}
public static class ConnectionTracker {
private final String ip;
private final Map<String, Integer> destConnections;
private final AtomicLong totalPackets;
private volatile long windowStart;
private volatile long packetsInWindow;
public ConnectionTracker(String ip) {
this.ip = ip;
this.destConnections = new ConcurrentHashMap<>();
this.totalPackets = new AtomicLong(0);
this.windowStart = System.currentTimeMillis();
this.packetsInWindow = 0;
}
public synchronized void recordConnection(String destIP, int port, String protocol) {
totalPackets.incrementAndGet();
packetsInWindow++;
String key = destIP + ":" + port;
destConnections.merge(key, 1, Integer::sum);
long now = System.currentTimeMillis();
if (now - windowStart > 60000) {
packetsInWindow = 0;
windowStart = now;
}
}
public long getPacketsPerMinute() {
return packetsInWindow;
}
public String getIp() { return ip; }
public long getTotalPackets() { return totalPackets.get(); }
public Map<String, Integer> getDestConnections() { return destConnections; }
}
public static class IPSResult {
private String sourceIP;
private String destIP;
private int sourcePort;
private int destPort;
private String protocol;
private boolean blocked;
private boolean threatDetected;
private String reason;
private String warning;
private List<String> matchedRules;
private LocalDateTime timestamp;
public IPSResult() {
this.matchedRules = new ArrayList<>();
}
public String getSourceIP() { return sourceIP; }
public void setSourceIP(String sourceIP) { this.sourceIP = sourceIP; }
public String getDestIP() { return destIP; }
public void setDestIP(String destIP) { this.destIP = destIP; }
public int getSourcePort() { return sourcePort; }
public void setSourcePort(int sourcePort) { this.sourcePort = sourcePort; }
public int getDestPort() { return destPort; }
public void setDestPort(int destPort) { this.destPort = destPort; }
public String getProtocol() { return protocol; }
public void setProtocol(String protocol) { this.protocol = protocol; }
public boolean isBlocked() { return blocked; }
public void setBlocked(boolean blocked) { this.blocked = blocked; }
public boolean isThreatDetected() { return threatDetected; }
public void setThreatDetected(boolean threatDetected) { this.threatDetected = threatDetected; }
public String getReason() { return reason; }
public void setReason(String reason) { this.reason = reason; }
public String getWarning() { return warning; }
public void setWarning(String warning) { this.warning = warning; }
public List<String> getMatchedRules() { return matchedRules; }
public void addMatchedRule(String rule) { this.matchedRules.add(rule); }
public LocalDateTime getTimestamp() { return timestamp; }
public void setTimestamp(LocalDateTime timestamp) { this.timestamp = timestamp; }
}
public static class IPSAlert {
private final String sourceIP;
private final String destIP;
private final String ruleName;
private final String severity;
private final String description;
private final LocalDateTime timestamp;
public IPSAlert(String sourceIP, String destIP, String ruleName, String severity, String description, LocalDateTime timestamp) {
this.sourceIP = sourceIP;
this.destIP = destIP;
this.ruleName = ruleName;
this.severity = severity;
this.description = description;
this.timestamp = timestamp;
}
public String getSourceIP() { return sourceIP; }
public String getDestIP() { return destIP; }
public String getRuleName() { return ruleName; }
public String getSeverity() { return severity; }
public String getDescription() { return description; }
public LocalDateTime getTimestamp() { return timestamp; }
}
}
@@ -0,0 +1,404 @@
package com.aluer.security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicLong;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@Component
public class LoadBalancerService {
private static final Logger logger = LoggerFactory.getLogger(LoadBalancerService.class);
private final Map<String, BackendServer> backendServers = new ConcurrentHashMap<>();
private final Map<String, LoadBalancerRule> rules = new ConcurrentHashMap<>();
private final Map<String, Queue<Request>> requestQueue = new ConcurrentHashMap<>();
private final Map<String, LoadBalancerStats> stats = new ConcurrentHashMap<>();
private final Queue<LoadBalancerEvent> eventLog = new ConcurrentLinkedQueue<>();
private final AtomicLong totalRequests = new AtomicLong(0);
private final AtomicLong totalFailedRequests = new AtomicLong(0);
private final AtomicLong totalRedirects = new AtomicLong(0);
private String currentAlgorithm = "ROUND_ROBIN";
private volatile boolean enabled = true;
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private static final int MAX_QUEUE_SIZE = 1000;
private static final int HEALTH_CHECK_INTERVAL = 30;
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public LoadBalancerService() {
initializeDefaultRules();
startHealthCheck();
logger.info("Load Balancer Service initialized");
}
private void initializeDefaultRules() {
addRule("round-robin", "ROUND_ROBIN", "Simple round robin distribution");
addRule("least-connections", "LEAST_CONNECTIONS", "Route to server with fewest connections");
addRule("weighted", "WEIGHTED", "Weighted distribution based on server capacity");
addRule("ip-hash", "IP_HASH", "Sticky sessions based on client IP");
addRule("response-time", "RESPONSE_TIME", "Route to fastest responding server");
}
private void addRule(String name, String algorithm, String description) {
LoadBalancerRule rule = new LoadBalancerRule(name, algorithm, description);
rules.put(name, rule);
}
public void addBackendServer(String serverId, String host, int port, int weight) {
BackendServer server = new BackendServer(serverId, host, port, weight);
backendServers.put(serverId, server);
stats.put(serverId, new LoadBalancerStats(serverId));
logger.info("Added backend server: {} -> {}:{}", serverId, host, port);
}
public void removeBackendServer(String serverId) {
backendServers.remove(serverId);
stats.remove(serverId);
logger.info("Removed backend server: {}", serverId);
}
public BackendServer selectBackendServer(String clientIP) {
if (!enabled) return null;
List<BackendServer> healthyServers = getHealthyServers();
if (healthyServers.isEmpty()) {
logger.warn("No healthy backend servers available");
return null;
}
totalRequests.incrementAndGet();
BackendServer selected;
switch (currentAlgorithm) {
case "LEAST_CONNECTIONS":
selected = selectLeastConnections(healthyServers);
break;
case "WEIGHTED":
selected = selectWeighted(healthyServers);
break;
case "IP_HASH":
selected = selectByIPHash(clientIP, healthyServers);
break;
case "RESPONSE_TIME":
selected = selectByResponseTime(healthyServers);
break;
default:
selected = selectRoundRobin(healthyServers);
}
if (selected != null) {
LoadBalancerStats serverStats = stats.get(selected.getServerId());
if (serverStats != null) {
serverStats.incrementRequestCount();
}
logEvent("ROUTED", clientIP, selected.getHost() + ":" + selected.getPort());
}
return selected;
}
private List<BackendServer> getHealthyServers() {
List<BackendServer> healthy = new ArrayList<>();
for (BackendServer server : backendServers.values()) {
if (server.isHealthy()) {
healthy.add(server);
}
}
return healthy;
}
private BackendServer selectRoundRobin(List<BackendServer> servers) {
int index = (int) (totalRequests.get() % servers.size());
return servers.get(index);
}
private BackendServer selectLeastConnections(List<BackendServer> servers) {
BackendServer selected = null;
long minConnections = Long.MAX_VALUE;
for (BackendServer server : servers) {
LoadBalancerStats serverStats = stats.get(server.getServerId());
long connections = serverStats != null ? serverStats.getActiveConnections() : 0;
if (connections < minConnections) {
minConnections = connections;
selected = server;
}
}
return selected;
}
private BackendServer selectWeighted(List<BackendServer> servers) {
int totalWeight = servers.stream().mapToInt(BackendServer::getWeight).sum();
int random = new Random().nextInt(totalWeight);
int cumulative = 0;
for (BackendServer server : servers) {
cumulative += server.getWeight();
if (random < cumulative) {
return server;
}
}
return servers.get(0);
}
private BackendServer selectByIPHash(String clientIP, List<BackendServer> servers) {
int hash = clientIP.hashCode();
int index = Math.abs(hash) % servers.size();
return servers.get(index);
}
private BackendServer selectByResponseTime(List<BackendServer> servers) {
BackendServer selected = null;
long fastestResponse = Long.MAX_VALUE;
for (BackendServer server : servers) {
LoadBalancerStats serverStats = stats.get(server.getServerId());
long avgResponse = serverStats != null ? serverStats.getAverageResponseTime() : 0;
if (avgResponse < fastestResponse) {
fastestResponse = avgResponse;
selected = server;
}
}
return selected;
}
public void recordRequestSuccess(String serverId, long responseTime) {
LoadBalancerStats serverStats = stats.get(serverId);
if (serverStats != null) {
serverStats.recordSuccess(responseTime);
}
}
public void recordRequestFailure(String serverId) {
LoadBalancerStats serverStats = stats.get(serverId);
if (serverStats != null) {
serverStats.recordFailure();
}
totalFailedRequests.incrementAndGet();
BackendServer server = backendServers.get(serverId);
if (server != null) {
server.incrementFailureCount();
if (server.getFailureCount() >= 5) {
server.setHealthy(false);
logger.warn("Backend server {} marked as unhealthy after {} failures", serverId, server.getFailureCount());
logEvent("SERVER_UNHEALTHY", serverId, "Marked as unhealthy");
}
}
}
public void setAlgorithm(String algorithm) {
this.currentAlgorithm = algorithm;
logger.info("Load balancer algorithm changed to: {}", algorithm);
}
public void enable() {
this.enabled = true;
logger.info("Load balancer enabled");
}
public void disable() {
this.enabled = false;
logger.info("Load balancer disabled");
}
private void startHealthCheck() {
scheduler.scheduleAtFixedRate(() -> {
checkBackendHealth();
}, HEALTH_CHECK_INTERVAL, HEALTH_CHECK_INTERVAL, TimeUnit.SECONDS);
}
private void checkBackendHealth() {
for (BackendServer server : backendServers.values()) {
boolean healthy = performHealthCheck(server);
if (healthy && !server.isHealthy()) {
server.setHealthy(true);
server.resetFailureCount();
logger.info("Backend server {} is healthy again", server.getServerId());
logEvent("SERVER_HEALTHY", server.getServerId(), "Health check passed");
} else if (!healthy && server.isHealthy()) {
server.setHealthy(false);
logger.warn("Backend server {} failed health check", server.getServerId());
logEvent("SERVER_UNHEALTHY", server.getServerId(), "Health check failed");
}
}
}
private boolean performHealthCheck(BackendServer server) {
return true;
}
public Map<String, Object> getStats() {
Map<String, Object> statsMap = new HashMap<>();
statsMap.put("enabled", enabled);
statsMap.put("algorithm", currentAlgorithm);
statsMap.put("totalRequests", totalRequests.get());
statsMap.put("totalFailedRequests", totalFailedRequests.get());
statsMap.put("totalRedirects", totalRedirects.get());
statsMap.put("backendServers", backendServers.size());
long healthyServers = backendServers.values().stream().filter(BackendServer::isHealthy).count();
statsMap.put("healthyServers", healthyServers);
double successRate = totalRequests.get() > 0 ?
(totalRequests.get() - totalFailedRequests.get()) * 100.0 / totalRequests.get() : 0;
statsMap.put("successRate", String.format("%.2f%%", successRate));
return statsMap;
}
public Map<String, BackendServer> getBackendServers() {
return new HashMap<>(backendServers);
}
public Map<String, LoadBalancerStats> getServerStats() {
return new HashMap<>(stats);
}
public List<LoadBalancerEvent> getRecentEvents(int limit) {
List<LoadBalancerEvent> events = new ArrayList<>();
int count = 0;
for (LoadBalancerEvent event : eventLog) {
if (count++ >= limit) break;
events.add(event);
}
return events;
}
private void logEvent(String type, String source, String details) {
LoadBalancerEvent event = new LoadBalancerEvent(type, source, details, LocalDateTime.now());
eventLog.offer(event);
if (eventLog.size() > 1000) {
eventLog.poll();
}
}
public static class BackendServer {
private final String serverId;
private final String host;
private final int port;
private final int weight;
private volatile boolean healthy = true;
private volatile int failureCount = 0;
public BackendServer(String serverId, String host, int port, int weight) {
this.serverId = serverId;
this.host = host;
this.port = port;
this.weight = weight;
}
public void incrementFailureCount() { failureCount++; }
public void resetFailureCount() { failureCount = 0; }
public String getServerId() { return serverId; }
public String getHost() { return host; }
public int getPort() { return port; }
public int getWeight() { return weight; }
public boolean isHealthy() { return healthy; }
public void setHealthy(boolean healthy) { this.healthy = healthy; }
public int getFailureCount() { return failureCount; }
}
public static class LoadBalancerRule {
private final String name;
private final String algorithm;
private final String description;
public LoadBalancerRule(String name, String algorithm, String description) {
this.name = name;
this.algorithm = algorithm;
this.description = description;
}
public String getName() { return name; }
public String getAlgorithm() { return algorithm; }
public String getDescription() { return description; }
}
public static class LoadBalancerStats {
private final String serverId;
private final AtomicLong requestCount = new AtomicLong(0);
private final AtomicLong failureCount = new AtomicLong(0);
private final AtomicLong totalResponseTime = new AtomicLong(0);
private volatile long activeConnections = 0;
public LoadBalancerStats(String serverId) {
this.serverId = serverId;
}
public void incrementRequestCount() { requestCount.incrementAndGet(); activeConnections++; }
public void recordSuccess(long responseTime) {
totalResponseTime.addAndGet(responseTime);
activeConnections = Math.max(0, activeConnections - 1);
}
public void recordFailure() {
failureCount.incrementAndGet();
activeConnections = Math.max(0, activeConnections - 1);
}
public long getAverageResponseTime() {
long count = requestCount.get();
return count > 0 ? totalResponseTime.get() / count : 0;
}
public String getServerId() { return serverId; }
public long getRequestCount() { return requestCount.get(); }
public long getFailureCount() { return failureCount.get(); }
public long getActiveConnections() { return activeConnections; }
}
public static class Request {
private final String requestId;
private final String clientIP;
private final String path;
private final long timestamp;
public Request(String requestId, String clientIP, String path) {
this.requestId = requestId;
this.clientIP = clientIP;
this.path = path;
this.timestamp = System.currentTimeMillis();
}
public String getRequestId() { return requestId; }
public String getClientIP() { return clientIP; }
public String getPath() { return path; }
public long getTimestamp() { return timestamp; }
}
public static class LoadBalancerEvent {
private final String type;
private final String source;
private final String details;
private final LocalDateTime timestamp;
public LoadBalancerEvent(String type, String source, String details, LocalDateTime timestamp) {
this.type = type;
this.source = source;
this.details = details;
this.timestamp = timestamp;
}
public String getType() { return type; }
public String getSource() { return source; }
public String getDetails() { return details; }
public LocalDateTime getTimestamp() { return timestamp; }
}
}
@@ -0,0 +1,230 @@
package com.aluer.security;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.security.MessageDigest;
@Service
public class LogAnalysisService {
private final Map<String, List<LogEntry>> logBuffer = new ConcurrentHashMap<>();
private final Map<String, PatternRule> patternRules = new ConcurrentHashMap<>();
private final Queue<SecurityEvent> securityEvents = new ConcurrentLinkedQueue<>();
private final Map<String, AtomicInteger> threatCounts = new ConcurrentHashMap<>();
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
private static final int MAX_BUFFER_SIZE = 10000;
private static final long ANALYSIS_INTERVAL = 30000;
private final AtomicLong totalLogsAnalyzed = new AtomicLong(0);
private final AtomicLong threatsDetected = new AtomicLong(0);
public LogAnalysisService() {
initializePatternRules();
startAnalysisTask();
}
private void initializePatternRules() {
addPatternRule("SQL_INJECTION", ".*(union|select|insert|update|delete|drop).*", 80, true);
addPatternRule("XSS_ATTACK", ".*(<script|javascript:|onerror=|onload=).*", 80, true);
addPatternRule("PATH_TRAVERSAL", ".*(\\.\\./|\\.\\.\\\\).*", 70, true);
addPatternRule("COMMAND_INJECTION", ".*(;|\\||\\$\\(|`).*", 75, true);
addPatternRule("BRUTE_FORCE", ".*(failed login|authentication failure|invalid password).*", 60, true);
addPatternRule("FILE_ACCESS", ".*(\\.\\./etc/passwd|\\.\\./etc/shadow).*", 90, true);
addPatternRule("PORT_SCAN", ".*(port scan|connection attempt).*", 50, true);
addPatternRule("DDOS_PATTERN", ".*(flood| amplification|botnet).*", 70, true);
}
public void addPatternRule(String name, String pattern, int severity, boolean enabled) {
try {
PatternRule rule = new PatternRule(name, pattern, severity, enabled);
patternRules.put(name, rule);
} catch (Exception e) {
}
}
public void analyzeLog(String source, String logMessage) {
totalLogsAnalyzed.incrementAndGet();
LogEntry entry = new LogEntry(source, logMessage, System.currentTimeMillis());
List<LogEntry> buffer = logBuffer.computeIfAbsent(source, k -> new CopyOnWriteArrayList<>());
buffer.add(entry);
while (buffer.size() > MAX_BUFFER_SIZE) {
buffer.remove(0);
}
for (PatternRule rule : patternRules.values()) {
if (!rule.enabled) continue;
if (rule.matches(logMessage)) {
handleThreatDetected(source, rule.name, rule.severity, logMessage);
}
}
}
private void handleThreatDetected(String source, String threatType, int severity, String details) {
threatsDetected.incrementAndGet();
AtomicInteger count = threatCounts.computeIfAbsent(threatType, k -> new AtomicInteger(0));
count.incrementAndGet();
SecurityEvent event = new SecurityEvent(threatType, source, severity, details, System.currentTimeMillis());
securityEvents.offer(event);
while (securityEvents.size() > 5000) {
securityEvents.poll();
}
}
public void addCustomLog(String source, String message, Map<String, Object> metadata) {
LogEntry entry = new LogEntry(source, message, System.currentTimeMillis());
entry.metadata = metadata;
List<LogEntry> buffer = logBuffer.computeIfAbsent(source, k -> new CopyOnWriteArrayList<>());
buffer.add(entry);
}
public List<LogEntry> getLogs(String source, int limit) {
List<LogEntry> buffer = logBuffer.get(source);
if (buffer == null) {
return new ArrayList<>();
}
List<LogEntry> result = new ArrayList<>();
int count = 0;
for (LogEntry entry : buffer) {
if (count++ >= limit) break;
result.add(entry);
}
return result;
}
public List<LogEntry> getRecentLogs(int limit) {
List<LogEntry> allLogs = new ArrayList<>();
for (List<LogEntry> buffer : logBuffer.values()) {
allLogs.addAll(buffer);
}
allLogs.sort((a, b) -> Long.compare(b.timestamp, a.timestamp));
return allLogs.stream().limit(limit).toList();
}
public List<SecurityEvent> getSecurityEvents(int limit) {
List<SecurityEvent> result = new ArrayList<>();
int count = 0;
for (SecurityEvent event : securityEvents) {
if (count++ >= limit) break;
result.add(event);
}
return result;
}
public Map<String, Integer> getThreatCounts() {
Map<String, Integer> result = new HashMap<>();
threatCounts.forEach((k, v) -> result.put(k, v.get()));
return result;
}
public Map<String, Object> getStatistics() {
Map<String, Object> stats = new HashMap<>();
stats.put("totalLogsAnalyzed", totalLogsAnalyzed.get());
stats.put("threatsDetected", threatsDetected.get());
stats.put("bufferedSources", logBuffer.size());
stats.put("activeRules", patternRules.size());
return stats;
}
public boolean enableRule(String ruleName) {
PatternRule rule = patternRules.get(ruleName);
if (rule == null) return false;
rule.enabled = true;
return true;
}
public boolean disableRule(String ruleName) {
PatternRule rule = patternRules.get(ruleName);
if (rule == null) return false;
rule.enabled = false;
return true;
}
public PatternRule getRule(String ruleName) {
return patternRules.get(ruleName);
}
public Collection<PatternRule> getAllRules() {
return patternRules.values();
}
private void startAnalysisTask() {
scheduler.scheduleAtFixedRate(() -> {
long now = System.currentTimeMillis();
for (Map.Entry<String, List<LogEntry>> entry : logBuffer.entrySet()) {
List<LogEntry> buffer = entry.getValue();
buffer.removeIf(e -> now - e.timestamp > 3600000);
if (buffer.isEmpty()) {
logBuffer.remove(entry.getKey());
}
}
threatCounts.entrySet().removeIf(e -> e.getValue().get() == 0);
}, ANALYSIS_INTERVAL, ANALYSIS_INTERVAL, TimeUnit.MILLISECONDS);
}
public static class PatternRule {
public final String name;
public final String pattern;
public final int severity;
public volatile boolean enabled;
private final java.util.regex.Pattern compiledPattern;
public PatternRule(String name, String pattern, int severity, boolean enabled) {
this.name = name;
this.pattern = pattern;
this.severity = severity;
this.enabled = enabled;
this.compiledPattern = java.util.regex.Pattern.compile(pattern, java.util.regex.Pattern.CASE_INSENSITIVE);
}
public boolean matches(String input) {
return compiledPattern.matcher(input).find();
}
}
public static class LogEntry {
public final String source;
public final String message;
public final long timestamp;
public Map<String, Object> metadata;
public LogEntry(String source, String message, long timestamp) {
this.source = source;
this.message = message;
this.timestamp = timestamp;
}
}
public static class SecurityEvent {
public final String threatType;
public final String source;
public final int severity;
public final String details;
public final long timestamp;
public SecurityEvent(String threatType, String source, int severity, String details, long timestamp) {
this.threatType = threatType;
this.source = source;
this.severity = severity;
this.details = details;
this.timestamp = timestamp;
}
}
}
@@ -0,0 +1,327 @@
package com.aluer.security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicLong;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Component
public class LogCorrelationService {
private static final Logger logger = LoggerFactory.getLogger(LogCorrelationService.class);
private final Map<String, LogSource> logSources = new ConcurrentHashMap<>();
private final Map<String, LogEntry> logBuffer = new ConcurrentHashMap<>();
private final Queue<CorrelatedEvent> correlatedEvents = new ConcurrentLinkedQueue<>();
private final Map<String, CorrelationPattern> patterns = new ConcurrentHashMap<>();
private final Map<String, List<LogEntry>> logTimeline = new ConcurrentHashMap<>();
private final AtomicLong totalLogsProcessed = new AtomicLong(0);
private final AtomicLong correlatedEventsFound = new AtomicLong(0);
private static final int MAX_BUFFER_SIZE = 50000;
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public LogCorrelationService() {
initializeDefaultPatterns();
logger.info("Log Correlation Service initialized");
}
private void initializeDefaultPatterns() {
addPattern("SQL_INJECTION", "SQL.*(union|select|insert|update|delete).*", Arrays.asList("SQL_INJECTION_START", "SQL_INJECTION_END"), 300);
addPattern("BRUTE_FORCE", "AUTH.*(failed|invalid)", Arrays.asList("LOGIN_FAILED", "LOGIN_FAILED", "LOGIN_FAILED"), 60);
addPattern("XSS_ATTACK", "HTTP.*(<script|javascript:)", Arrays.asList("XSS_START", "XSS_PAYLOAD"), 120);
addPattern("DATA_EXFILTRATION", "(upload|download).*large", Arrays.asList("LARGE_UPLOAD", "DATA_TRANSFER"), 600);
addPattern("PRIVILEGE_ESCALATION", "(sudo|admin|root).*(success|granted)", Arrays.asList("ELEVATED_ACCESS", "PERMISSION_CHANGE"), 300);
addPattern("CREDENTIALS_COMPROMISED", "AUTH.*success.*(unusual|unknown)", Arrays.asList("ANOMALY_LOGIN", "CREDENTIAL_CHANGE"), 180);
addPattern("DDoS_ATTACK", "NET.*(flood|storm|amplification)", Arrays.asList("HIGH_TRAFFIC", "CONNECTION_LIMIT"), 60);
addPattern("MALWARE_INFECTION", "PROC.*(suspicious|malicious|infected)", Arrays.asList("SUSPICIOUS_PROCESS", "MALWARE_DETECTED"), 600);
logger.info("Initialized {} correlation patterns", patterns.size());
}
public void addPattern(String name, String matchRegex, List<String> sequence, int timeWindow) {
CorrelationPattern pattern = new CorrelationPattern(name, matchRegex, sequence, timeWindow);
patterns.put(name, pattern);
}
public void addLogSource(String sourceId, String sourceType, String host, int port) {
LogSource source = new LogSource(sourceId, sourceType, host, port);
logSources.put(sourceId, source);
logger.info("Added log source: {} ({})", sourceId, sourceType);
}
public void processLogEntry(String sourceId, String level, String category, String message, Map<String, Object> metadata) {
String entryId = UUID.randomUUID().toString();
LogEntry entry = new LogEntry(entryId, sourceId, level, category, message, metadata, LocalDateTime.now());
logBuffer.put(entryId, entry);
if (logBuffer.size() > MAX_BUFFER_SIZE) {
String firstKey = logBuffer.keySet().iterator().next();
logBuffer.remove(firstKey);
}
totalLogsProcessed.incrementAndGet();
List<LogEntry> timeline = logTimeline.computeIfAbsent(sourceId, k -> new ArrayList<>());
timeline.add(entry);
if (timeline.size() > 1000) {
timeline.remove(0);
}
checkCorrelationPatterns(entry);
logger.debug("Processed log entry: {} [{}]", category, level);
}
private void checkCorrelationPatterns(LogEntry entry) {
for (CorrelationPattern pattern : patterns.values()) {
if (matchesPattern(entry, pattern)) {
List<LogEntry> sourceTimeline = logTimeline.get(entry.getSourceId());
if (sourceTimeline == null) continue;
List<LogEntry> recentEntries = new ArrayList<>();
long cutoffTime = System.currentTimeMillis() - (pattern.getTimeWindow() * 1000);
for (LogEntry e : sourceTimeline) {
if (e.getTimestamp().isAfter(LocalDateTime.now().minusSeconds(pattern.getTimeWindow()))) {
recentEntries.add(e);
}
}
if (checkSequenceMatch(recentEntries, pattern)) {
CorrelatedEvent event = new CorrelatedEvent(
pattern.getName(),
entry.getSourceId(),
recentEntries,
"CORRELATION_DETECTED",
LocalDateTime.now()
);
correlatedEvents.offer(event);
correlatedEventsFound.incrementAndGet();
if (correlatedEvents.size() > 1000) {
correlatedEvents.poll();
}
logger.warn("Correlation detected: {} from source: {}", pattern.getName(), entry.getSourceId());
}
}
}
}
private boolean matchesPattern(LogEntry entry, CorrelationPattern pattern) {
try {
return entry.getMessage().matches(pattern.getMatchRegex()) ||
entry.getCategory().matches(pattern.getMatchRegex());
} catch (Exception e) {
return false;
}
}
private boolean checkSequenceMatch(List<LogEntry> entries, CorrelationPattern pattern) {
List<String> sequence = pattern.getSequence();
if (entries.size() < sequence.size()) return false;
int matchCount = 0;
for (int i = 0; i <= entries.size() - sequence.size(); i++) {
boolean allMatch = true;
for (int j = 0; j < sequence.size(); j++) {
String entryCategory = entries.get(i + j).getCategory();
if (!entryCategory.matches(sequence.get(j)) && !entryCategory.contains(sequence.get(j))) {
allMatch = false;
break;
}
}
if (allMatch) return true;
}
return false;
}
public List<CorrelatedEvent> queryCorrelatedEvents(String patternName, int limit) {
List<CorrelatedEvent> results = new ArrayList<>();
for (CorrelatedEvent event : correlatedEvents) {
if (patternName == null || event.getPatternName().equals(patternName)) {
results.add(event);
}
if (results.size() >= limit) break;
}
return results;
}
public List<LogEntry> queryLogs(String sourceId, String level, String category, int limit) {
List<LogEntry> results = new ArrayList<>();
for (LogEntry entry : logBuffer.values()) {
boolean matches = true;
if (sourceId != null && !entry.getSourceId().equals(sourceId)) matches = false;
if (level != null && !entry.getLevel().equals(level)) matches = false;
if (category != null && !entry.getCategory().equals(category)) matches = false;
if (matches) {
results.add(entry);
}
if (results.size() >= limit) break;
}
results.sort((a, b) -> b.getTimestamp().compareTo(a.getTimestamp()));
return results;
}
public Map<String, Object> getStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("totalLogsProcessed", totalLogsProcessed.get());
stats.put("correlatedEventsFound", correlatedEventsFound.get());
stats.put("logSources", logSources.size());
stats.put("correlationPatterns", patterns.size());
stats.put("bufferSize", logBuffer.size());
Map<String, Long> categoryCounts = new HashMap<>();
for (LogEntry entry : logBuffer.values()) {
categoryCounts.merge(entry.getCategory(), 1L, Long::sum);
}
stats.put("categoryCounts", categoryCounts);
Map<String, Long> levelCounts = new HashMap<>();
for (LogEntry entry : logBuffer.values()) {
levelCounts.merge(entry.getLevel(), 1L, Long::sum);
}
stats.put("levelCounts", levelCounts);
return stats;
}
public Map<String, LogSource> getLogSources() {
return new HashMap<>(logSources);
}
public Map<String, CorrelationPattern> getPatterns() {
return new HashMap<>(patterns);
}
public void enablePattern(String patternName) {
CorrelationPattern pattern = patterns.get(patternName);
if (pattern != null) {
pattern.setEnabled(true);
logger.info("Enabled correlation pattern: {}", patternName);
}
}
public void disablePattern(String patternName) {
CorrelationPattern pattern = patterns.get(patternName);
if (pattern != null) {
pattern.setEnabled(false);
logger.info("Disabled correlation pattern: {}", patternName);
}
}
public void clearBuffer() {
logBuffer.clear();
logger.info("Log buffer cleared");
}
public static class LogSource {
private final String sourceId;
private final String sourceType;
private final String host;
private final int port;
private volatile boolean active = true;
private volatile long lastLogTime;
public LogSource(String sourceId, String sourceType, String host, int port) {
this.sourceId = sourceId;
this.sourceType = sourceType;
this.host = host;
this.port = port;
}
public String getSourceId() { return sourceId; }
public String getSourceType() { return sourceType; }
public String getHost() { return host; }
public int getPort() { return port; }
public boolean isActive() { return active; }
public void setActive(boolean active) { this.active = active; }
public long getLastLogTime() { return lastLogTime; }
public void setLastLogTime(long lastLogTime) { this.lastLogTime = lastLogTime; }
}
public static class LogEntry {
private final String entryId;
private final String sourceId;
private final String level;
private final String category;
private final String message;
private final Map<String, Object> metadata;
private final LocalDateTime timestamp;
public LogEntry(String entryId, String sourceId, String level, String category,
String message, Map<String, Object> metadata, LocalDateTime timestamp) {
this.entryId = entryId;
this.sourceId = sourceId;
this.level = level;
this.category = category;
this.message = message;
this.metadata = metadata;
this.timestamp = timestamp;
}
public String getEntryId() { return entryId; }
public String getSourceId() { return sourceId; }
public String getLevel() { return level; }
public String getCategory() { return category; }
public String getMessage() { return message; }
public Map<String, Object> getMetadata() { return metadata; }
public LocalDateTime getTimestamp() { return timestamp; }
}
public static class CorrelationPattern {
private final String name;
private final String matchRegex;
private final List<String> sequence;
private final int timeWindow;
private volatile boolean enabled = true;
public CorrelationPattern(String name, String matchRegex, List<String> sequence, int timeWindow) {
this.name = name;
this.matchRegex = matchRegex;
this.sequence = sequence;
this.timeWindow = timeWindow;
}
public String getName() { return name; }
public String getMatchRegex() { return matchRegex; }
public List<String> getSequence() { return sequence; }
public int getTimeWindow() { return timeWindow; }
public boolean isEnabled() { return enabled; }
public void setEnabled(boolean enabled) { this.enabled = enabled; }
}
public static class CorrelatedEvent {
private final String patternName;
private final String sourceId;
private final List<LogEntry> relatedEntries;
private final String status;
private final LocalDateTime timestamp;
public CorrelatedEvent(String patternName, String sourceId, List<LogEntry> relatedEntries,
String status, LocalDateTime timestamp) {
this.patternName = patternName;
this.sourceId = sourceId;
this.relatedEntries = relatedEntries;
this.status = status;
this.timestamp = timestamp;
}
public String getPatternName() { return patternName; }
public String getSourceId() { return sourceId; }
public List<LogEntry> getRelatedEntries() { return relatedEntries; }
public String getStatus() { return status; }
public LocalDateTime getTimestamp() { return timestamp; }
}
}
@@ -0,0 +1,342 @@
package com.aluer.security;
import com.aluer.config.ServerGuardConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
@Service
public class MinecraftProtocolSecurityService {
private static final long WINDOW_MS = 60_000L;
private final ServerGuardConfig config;
private final Map<String, MinecraftSessionProfile> profiles = new ConcurrentHashMap<>();
private final ConcurrentLinkedQueue<MinecraftThreatSignal> signals = new ConcurrentLinkedQueue<>();
public MinecraftProtocolSecurityService() {
this(new ServerGuardConfig());
}
@Autowired
public MinecraftProtocolSecurityService(ServerGuardConfig config) {
this.config = config;
}
public List<MinecraftThreatSignal> analyzePacket(String sourceIP, String destIP, int sourcePort, int destPort, byte[] payload) {
if (!config.getSecurity().getMinecraftDefense().isEnabled()) {
return Collections.emptyList();
}
if (!isMinecraftRelevantPort(destPort)) {
return Collections.emptyList();
}
MinecraftSessionProfile profile = profiles.computeIfAbsent(sourceIP, MinecraftSessionProfile::new);
profile.destinations.add(destIP);
profile.totalPackets++;
profile.lastSeen = System.currentTimeMillis();
String stage = classifyStage(destPort, payload);
recordStage(profile, stage);
List<MinecraftThreatSignal> result = new ArrayList<>();
if ("STATUS".equals(stage) && profile.statusRequests.size() >= config.getSecurity().getMinecraftDefense().getStatusPingThreshold()) {
result.add(createSignal(sourceIP, "STATUS_PING_FLOOD", 88, "Frequent status probes on Minecraft port"));
}
if ("LOGIN".equals(stage) && profile.loginAttempts.size() >= config.getSecurity().getMinecraftDefense().getLoginBurstThreshold()) {
result.add(createSignal(sourceIP, "LOGIN_BURST", 84, "Burst of login attempts detected"));
}
if ("QUERY".equals(stage) && profile.queryRequests.size() >= config.getSecurity().getMinecraftDefense().getQueryFloodThreshold()) {
result.add(createSignal(sourceIP, "QUERY_ABUSE", 80, "Frequent query traffic detected"));
}
if ("RCON".equals(stage) && profile.rconAttempts.size() >= config.getSecurity().getMinecraftDefense().getRconBruteForceThreshold()) {
result.add(createSignal(sourceIP, "RCON_BRUTE_FORCE", 92, "Repeated RCON authentication attempts"));
}
if (detectInvalidVarint(payload)) {
result.add(createSignal(sourceIP, "INVALID_VARINT", 90, "Malformed VarInt header detected"));
}
if (detectMalformedHandshake(destPort, payload)) {
result.add(createSignal(sourceIP, "MALFORMED_HANDSHAKE", 82, "Unexpected or truncated handshake"));
}
if (detectCompressionAbuse(payload)) {
result.add(createSignal(sourceIP, "COMPRESSION_ABUSE", 72, "Large or repetitive payload suggests compression abuse"));
}
if (detectProtocolStateBypass(profile, stage)) {
result.add(createSignal(sourceIP, "PROTOCOL_STATE_BYPASS", 86, "Unexpected protocol stage transition"));
}
if (stage.equals("LOGIN") || stage.equals("STATUS")) {
int uniqueSources = countUniqueSourcesForStage(stage);
if (uniqueSources >= config.getSecurity().getMinecraftDefense().getBotSwarmThreshold()) {
result.add(createSignal(sourceIP, "BOT_SWARM", 78, "Multiple IPs are synchronously probing Minecraft"));
}
}
for (MinecraftThreatSignal signal : result) {
profile.signalsTriggered.merge(signal.type, 1, Integer::sum);
signals.offer(signal);
}
while (signals.size() > 1000) {
signals.poll();
}
return result;
}
public List<MinecraftThreatSignal> getRecentSignals(int limit) {
List<MinecraftThreatSignal> result = new ArrayList<>();
int count = 0;
for (MinecraftThreatSignal signal : signals) {
if (count++ >= limit) {
break;
}
result.add(signal);
}
result.sort(Comparator.comparingLong(MinecraftThreatSignal::getTimestamp).reversed());
return result;
}
public List<MinecraftThreatSignal> getSignalsForIp(String ip, int limit) {
List<MinecraftThreatSignal> result = new ArrayList<>();
for (MinecraftThreatSignal signal : getRecentSignals(200)) {
if (ip.equals(signal.sourceIP)) {
result.add(signal);
if (result.size() >= limit) {
break;
}
}
}
return result;
}
public Map<String, Object> getPosture() {
Map<String, Object> posture = new LinkedHashMap<>();
posture.put("activeSessions", profiles.size());
posture.put("recentSignals", signals.size());
posture.put("botSwarmSources", countSignals("BOT_SWARM"));
posture.put("rconRisk", countSignals("RCON_BRUTE_FORCE"));
posture.put("malformedPackets", countSignals("INVALID_VARINT") + countSignals("MALFORMED_HANDSHAKE"));
posture.put("topSources", getTopProfiles(5));
return posture;
}
public List<Map<String, Object>> getSessionProfiles(int limit) {
return getTopProfiles(limit);
}
private List<Map<String, Object>> getTopProfiles(int limit) {
List<MinecraftSessionProfile> sessionProfiles = new ArrayList<>(profiles.values());
sessionProfiles.sort(Comparator.comparingLong((MinecraftSessionProfile profile) -> profile.totalPackets).reversed());
List<Map<String, Object>> result = new ArrayList<>();
for (MinecraftSessionProfile profile : sessionProfiles) {
if (result.size() >= limit) {
break;
}
result.add(profile.toMap());
}
return result;
}
private int countSignals(String type) {
int count = 0;
for (MinecraftThreatSignal signal : signals) {
if (type.equals(signal.type)) {
count++;
}
}
return count;
}
private int countUniqueSourcesForStage(String stage) {
Set<String> sources = new HashSet<>();
long cutoff = System.currentTimeMillis() - WINDOW_MS;
for (MinecraftSessionProfile profile : profiles.values()) {
List<Long> timestamps = switch (stage) {
case "STATUS" -> profile.statusRequests;
case "LOGIN" -> profile.loginAttempts;
default -> List.of();
};
timestamps.removeIf(timestamp -> timestamp < cutoff);
if (!timestamps.isEmpty()) {
sources.add(profile.sourceIP);
}
}
return sources.size();
}
private boolean detectInvalidVarint(byte[] payload) {
if (payload == null || payload.length == 0) {
return false;
}
int continuation = 0;
for (int i = 0; i < Math.min(6, payload.length); i++) {
if ((payload[i] & 0x80) != 0) {
continuation++;
} else {
break;
}
}
return continuation > 4;
}
private boolean detectMalformedHandshake(int destPort, byte[] payload) {
if (payload == null) {
return true;
}
if (destPort == config.getSecurity().getMinecraftDefense().getGameTcpPort() && payload.length < 2) {
return true;
}
String content = payload.length == 0 ? "" : new String(payload, StandardCharsets.UTF_8).toLowerCase(Locale.ROOT);
return content.contains("handshake") && payload.length < 8;
}
private boolean detectCompressionAbuse(byte[] payload) {
if (payload == null || payload.length < config.getSecurity().getMinecraftDefense().getCompressionPayloadThreshold()) {
return false;
}
int repeated = 0;
for (int i = 1; i < payload.length; i++) {
if (payload[i] == payload[i - 1]) {
repeated++;
}
}
return repeated > payload.length / 3;
}
private boolean detectProtocolStateBypass(MinecraftSessionProfile profile, String stage) {
if (profile.lastStage == null || stage.equals(profile.lastStage)) {
return false;
}
if ("LOGIN".equals(stage) && !"HANDSHAKE".equals(profile.lastStage)) {
return true;
}
if ("QUERY".equals(stage) && "RCON".equals(profile.lastStage)) {
return true;
}
return "RCON".equals(stage) && "STATUS".equals(profile.lastStage);
}
private String classifyStage(int destPort, byte[] payload) {
if (destPort == config.getSecurity().getMinecraftDefense().getRconTcpPort()) {
return "RCON";
}
if (destPort == config.getSecurity().getMinecraftDefense().getQueryUdpPort() && payload != null && payload.length > 0 && payload[0] == (byte) 0xFE) {
return "QUERY";
}
String content = payload == null ? "" : new String(payload, StandardCharsets.UTF_8).toLowerCase(Locale.ROOT);
if (content.contains("status") || content.contains("ping")) {
return "STATUS";
}
if (content.contains("login") || content.contains("join")) {
return "LOGIN";
}
if (content.contains("handshake")) {
return "HANDSHAKE";
}
if (content.contains("query")) {
return "QUERY";
}
return destPort == config.getSecurity().getMinecraftDefense().getGameTcpPort() ? "HANDSHAKE" : "UNKNOWN";
}
private void recordStage(MinecraftSessionProfile profile, String stage) {
long now = System.currentTimeMillis();
profile.lastStage = stage;
switch (stage) {
case "STATUS" -> pruneAndAdd(profile.statusRequests, now);
case "LOGIN" -> pruneAndAdd(profile.loginAttempts, now);
case "QUERY" -> pruneAndAdd(profile.queryRequests, now);
case "RCON" -> pruneAndAdd(profile.rconAttempts, now);
default -> pruneAndAdd(profile.handshakes, now);
}
}
private void pruneAndAdd(List<Long> timestamps, long timestamp) {
timestamps.removeIf(existing -> existing < timestamp - WINDOW_MS);
timestamps.add(timestamp);
}
private MinecraftThreatSignal createSignal(String sourceIP, String type, int confidence, String details) {
return new MinecraftThreatSignal(sourceIP, type, confidence, details, Instant.now().toEpochMilli());
}
private boolean isMinecraftRelevantPort(int port) {
ServerGuardConfig.MinecraftDefenseConfig defense = config.getSecurity().getMinecraftDefense();
return port == defense.getGameTcpPort()
|| port == defense.getQueryUdpPort()
|| port == defense.getRconTcpPort();
}
public static class MinecraftThreatSignal {
private final String sourceIP;
private final String type;
private final int confidence;
private final String details;
private final long timestamp;
public MinecraftThreatSignal(String sourceIP, String type, int confidence, String details, long timestamp) {
this.sourceIP = sourceIP;
this.type = type;
this.confidence = confidence;
this.details = details;
this.timestamp = timestamp;
}
public String getSourceIP() { return sourceIP; }
public String getType() { return type; }
public int getConfidence() { return confidence; }
public String getDetails() { return details; }
public long getTimestamp() { return timestamp; }
}
public static class MinecraftSessionProfile {
private final String sourceIP;
private final Set<String> destinations = ConcurrentHashMap.newKeySet();
private final List<Long> statusRequests = Collections.synchronizedList(new ArrayList<>());
private final List<Long> loginAttempts = Collections.synchronizedList(new ArrayList<>());
private final List<Long> queryRequests = Collections.synchronizedList(new ArrayList<>());
private final List<Long> rconAttempts = Collections.synchronizedList(new ArrayList<>());
private final List<Long> handshakes = Collections.synchronizedList(new ArrayList<>());
private final Map<String, Integer> signalsTriggered = new ConcurrentHashMap<>();
private volatile long totalPackets = 0;
private volatile long lastSeen = System.currentTimeMillis();
private volatile String lastStage = null;
public MinecraftSessionProfile(String sourceIP) {
this.sourceIP = sourceIP;
}
public Map<String, Object> toMap() {
Map<String, Object> data = new HashMap<>();
data.put("sourceIP", sourceIP);
data.put("totalPackets", totalPackets);
data.put("destinations", destinations.size());
data.put("statusRequests", statusRequests.size());
data.put("loginAttempts", loginAttempts.size());
data.put("queryRequests", queryRequests.size());
data.put("rconAttempts", rconAttempts.size());
data.put("signalsTriggered", signalsTriggered);
data.put("lastStage", lastStage);
data.put("lastSeen", lastSeen);
return data;
}
}
}
@@ -0,0 +1,238 @@
package com.aluer.security;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
@Service
public class NetworkMonitorService {
private final Map<String, NetworkSession> sessions = new ConcurrentHashMap<>();
private final Map<String, BandwidthTracker> bandwidthTrackers = new ConcurrentHashMap<>();
private final Queue<NetworkAlert> alerts = new ConcurrentLinkedQueue<>();
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
private static final long SESSION_TIMEOUT = 300000;
private static final long BANDWIDTH_UPDATE_INTERVAL = 1000;
private final AtomicLong totalBytesIn = new AtomicLong(0);
private final AtomicLong totalBytesOut = new AtomicLong(0);
private final AtomicLong totalPacketsIn = new AtomicLong(0);
private final AtomicLong totalPacketsOut = new AtomicLong(0);
public NetworkMonitorService() {
startMonitoringTask();
}
public void recordInboundTraffic(String ip, long bytes, int packets) {
totalBytesIn.addAndGet(bytes);
totalPacketsIn.addAndGet(packets);
BandwidthTracker tracker = bandwidthTrackers.computeIfAbsent(ip, k -> new BandwidthTracker(ip));
tracker.recordInbound(bytes, packets);
NetworkSession session = sessions.computeIfAbsent(ip, k -> new NetworkSession(ip));
session.recordInbound(bytes, packets);
}
public void recordOutboundTraffic(String ip, long bytes, int packets) {
totalBytesOut.addAndGet(bytes);
totalPacketsOut.addAndGet(packets);
BandwidthTracker tracker = bandwidthTrackers.computeIfAbsent(ip, k -> new BandwidthTracker(ip));
tracker.recordOutbound(bytes, packets);
NetworkSession session = sessions.computeIfAbsent(ip, k -> new NetworkSession(ip));
session.recordOutbound(bytes, packets);
}
public void recordConnection(String ip, int port, String protocol) {
NetworkSession session = sessions.computeIfAbsent(ip, k -> new NetworkSession(ip));
session.addConnection(port, protocol);
}
public void closeConnection(String ip, int port) {
NetworkSession session = sessions.get(ip);
if (session != null) {
session.removeConnection(port);
}
}
public boolean isHighBandwidth(String ip) {
BandwidthTracker tracker = bandwidthTrackers.get(ip);
if (tracker == null) {
return false;
}
return tracker.isHighBandwidth();
}
public boolean isExcessiveConnections(String ip) {
NetworkSession session = sessions.get(ip);
if (session == null) {
return false;
}
return session.getConnectionCount() > 100;
}
public NetworkSession getSession(String ip) {
return sessions.get(ip);
}
public Collection<NetworkSession> getAllSessions() {
return sessions.values();
}
public BandwidthTracker getBandwidthTracker(String ip) {
return bandwidthTrackers.get(ip);
}
public void addAlert(String ip, String type, String details) {
NetworkAlert alert = new NetworkAlert(ip, type, details, System.currentTimeMillis());
alerts.offer(alert);
while (alerts.size() > 500) {
alerts.poll();
}
}
public List<NetworkAlert> getAlerts(int limit) {
List<NetworkAlert> result = new ArrayList<>();
int count = 0;
for (NetworkAlert alert : alerts) {
if (count++ >= limit) break;
result.add(alert);
}
return result;
}
public Map<String, Object> getGlobalStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("activeSessions", sessions.size());
stats.put("totalBytesIn", totalBytesIn.get());
stats.put("totalBytesOut", totalBytesOut.get());
stats.put("totalPacketsIn", totalPacketsIn.get());
stats.put("totalPacketsOut", totalPacketsOut.get());
return stats;
}
private void startMonitoringTask() {
scheduler.scheduleAtFixedRate(() -> {
long now = System.currentTimeMillis();
sessions.entrySet().removeIf(entry ->
now - entry.getValue().lastActivity > SESSION_TIMEOUT);
for (BandwidthTracker tracker : bandwidthTrackers.values()) {
tracker.resetIfNeeded();
}
}, 30, 30, TimeUnit.SECONDS);
}
public static class NetworkSession {
private final String ip;
private final Set<Integer> connections = ConcurrentHashMap.newKeySet();
private volatile long totalBytesIn = 0;
private volatile long totalBytesOut = 0;
private volatile long totalPacketsIn = 0;
private volatile long totalPacketsOut = 0;
private volatile long lastActivity;
public NetworkSession(String ip) {
this.ip = ip;
this.lastActivity = System.currentTimeMillis();
}
public void recordInbound(long bytes, int packets) {
totalBytesIn += bytes;
totalPacketsIn += packets;
lastActivity = System.currentTimeMillis();
}
public void recordOutbound(long bytes, int packets) {
totalBytesOut += bytes;
totalPacketsOut += packets;
lastActivity = System.currentTimeMillis();
}
public void addConnection(int port, String protocol) {
connections.add(port);
lastActivity = System.currentTimeMillis();
}
public void removeConnection(int port) {
connections.remove(port);
}
public int getConnectionCount() {
return connections.size();
}
public String getIp() { return ip; }
public long getTotalBytesIn() { return totalBytesIn; }
public long getTotalBytesOut() { return totalBytesOut; }
}
public static class BandwidthTracker {
private final String ip;
private volatile long windowBytesIn = 0;
private volatile long windowBytesOut = 0;
private volatile long windowPacketsIn = 0;
private volatile long windowPacketsOut = 0;
private volatile long lastUpdate;
public BandwidthTracker(String ip) {
this.ip = ip;
this.lastUpdate = System.currentTimeMillis();
}
public void recordInbound(long bytes, int packets) {
windowBytesIn += bytes;
windowPacketsIn += packets;
}
public void recordOutbound(long bytes, int packets) {
windowBytesOut += bytes;
windowPacketsOut += packets;
}
public void resetIfNeeded() {
long now = System.currentTimeMillis();
if (now - lastUpdate > BANDWIDTH_UPDATE_INTERVAL) {
windowBytesIn = 0;
windowBytesOut = 0;
windowPacketsIn = 0;
windowPacketsOut = 0;
lastUpdate = now;
}
}
public boolean isHighBandwidth() {
return windowBytesIn > 10_000_000 || windowBytesOut > 10_000_000;
}
public String getIp() { return ip; }
public long getWindowBytesIn() { return windowBytesIn; }
public long getWindowBytesOut() { return windowBytesOut; }
}
public static class NetworkAlert {
private final String ip;
private final String type;
private final String details;
private final long timestamp;
public NetworkAlert(String ip, String type, String details, long timestamp) {
this.ip = ip;
this.type = type;
this.details = details;
this.timestamp = timestamp;
}
public String getIp() { return ip; }
public String getType() { return type; }
public String getDetails() { return details; }
public long getTimestamp() { return timestamp; }
}
}
@@ -0,0 +1,309 @@
package com.aluer.security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicLong;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Component
public class NetworkSegmentationService {
private static final Logger logger = LoggerFactory.getLogger(NetworkSegmentationService.class);
private final Map<String, NetworkSegment> segments = new ConcurrentHashMap<>();
private final Map<String, SegmentPolicy> policies = new ConcurrentHashMap<>();
private final Map<String, List<String>> segmentConnections = new ConcurrentHashMap<>();
private final Queue<SegmentationEvent> eventLog = new ConcurrentLinkedQueue<>();
private final AtomicLong totalSegments = new AtomicLong(0);
private final AtomicLong violationsDetected = new AtomicLong(0);
private volatile boolean enabled = true;
private static final int MAX_EVENTS = 5000;
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public NetworkSegmentationService() {
initializeDefaultSegments();
initializeDefaultPolicies();
logger.info("Network Segmentation Service initialized");
}
private void initializeDefaultSegments() {
addSegment("DMZ", "Demilitarized zone for public-facing services", "10.0.1.0/24");
addSegment("APPLICATION", "Application servers and services", "10.0.2.0/24");
addSegment("DATABASE", "Database servers and storage", "10.0.3.0/24");
addSegment("MANAGEMENT", "Management and administrative systems", "10.0.4.0/24");
addSegment("GUEST", "Guest and visitor networks", "10.0.5.0/24");
addSegment("IOT", "IoT devices and sensors", "10.0.6.0/24");
addSegment("SECURE", "Highly sensitive data and systems", "10.0.7.0/24");
addConnection("DMZ", "APPLICATION");
addConnection("APPLICATION", "DATABASE");
addConnection("APPLICATION", "MANAGEMENT");
addConnection("MANAGEMENT", "DATABASE");
addConnection("DMZ", "GUEST", false);
addConnection("IOT", "APPLICATION");
logger.info("Initialized {} network segments", segments.size());
}
private void initializeDefaultPolicies() {
addPolicy("DENY_ALL", "DENY", "Default deny all traffic between segments", 0);
addPolicy("ALLOW_DMZ_TO_APP", "ALLOW", "Allow DMZ to Application traffic", 100);
addPolicy("ALLOW_APP_TO_DB", "ALLOW", "Allow Application to Database", 100);
addPolicy("ALLOW_MGMT_TO_ALL", "ALLOW", "Allow Management to all segments", 90);
addPolicy("RESTRICT_GUEST", "RESTRICT", "Restrict guest network", 50);
addPolicy("RESTRICT_IOT", "RESTRICT", "Restrict IoT devices", 60);
addPolicy("AUDIT_SECURE", "AUDIT", "Audit all traffic to Secure segment", 80);
logger.info("Initialized {} segmentation policies", policies.size());
}
public void addSegment(String name, String description, String cidr) {
NetworkSegment segment = new NetworkSegment(name, description, cidr);
segments.put(name, segment);
segmentConnections.put(name, new ArrayList<>());
totalSegments.incrementAndGet();
logger.info("Added network segment: {} ({})", name, cidr);
}
public void addConnection(String from, String to) {
addConnection(from, to, true);
}
public void addConnection(String from, String to, boolean allowed) {
List<String> fromConnections = segmentConnections.computeIfAbsent(from, k -> new ArrayList<>());
if (!fromConnections.contains(to)) {
fromConnections.add(to);
}
if (allowed) {
logEvent(from, to, "CONNECTION_ADDED", "Allowed connection added");
} else {
logEvent(from, to, "RESTRICTED_CONNECTION", "Restricted connection added");
}
logger.info("Added connection from {} to {}", from, to);
}
public void removeConnection(String from, String to) {
List<String> fromConnections = segmentConnections.get(from);
if (fromConnections != null) {
fromConnections.remove(to);
}
logEvent(from, to, "CONNECTION_REMOVED", "Connection removed");
logger.info("Removed connection from {} to {}", from, to);
}
public void addPolicy(String name, String type, String description, int priority) {
SegmentPolicy policy = new SegmentPolicy(name, type, description, priority);
policies.put(name, policy);
}
public boolean checkConnection(String sourceSegment, String destSegment) {
List<String> allowedDestinations = segmentConnections.get(sourceSegment);
if (allowedDestinations == null || allowedDestinations.isEmpty()) {
return false;
}
if (allowedDestinations.contains(destSegment)) {
return true;
}
SegmentPolicy policy = findMatchingPolicy(sourceSegment, destSegment);
if (policy != null) {
if ("DENY".equals(policy.getType())) {
violationsDetected.incrementAndGet();
logEvent(sourceSegment, destSegment, "VIOLATION", "Denied by policy: " + policy.getName());
return false;
}
if ("ALLOW".equals(policy.getType())) {
return true;
}
}
return false;
}
private SegmentPolicy findMatchingPolicy(String source, String dest) {
SegmentPolicy matched = null;
int highestPriority = -1;
for (SegmentPolicy policy : policies.values()) {
if (matchesPolicy(policy, source, dest) && policy.getPriority() > highestPriority) {
matched = policy;
highestPriority = policy.getPriority();
}
}
return matched;
}
private boolean matchesPolicy(SegmentPolicy policy, String source, String dest) {
return true;
}
public void enforceMicrosegmentation(String segmentName) {
NetworkSegment segment = segments.get(segmentName);
if (segment == null) return;
segment.setMicrosegmentationEnabled(true);
List<String> connections = segmentConnections.get(segmentName);
if (connections != null) {
for (String dest : new ArrayList<>(connections)) {
connections.clear();
connections.add(dest);
}
}
logEvent(segmentName, "ALL", "MICROSEGMENTATION", "Microsegmentation enforced");
logger.info("Microsegmentation enforced for segment: {}", segmentName);
}
public void monitorTraffic(String sourceIP, String destIP) {
String sourceSegment = identifySegment(sourceIP);
String destSegment = identifySegment(destIP);
if (sourceSegment == null || destSegment == null) {
return;
}
if (!checkConnection(sourceSegment, destSegment)) {
violationsDetected.incrementAndGet();
logEvent(sourceSegment, destSegment, "UNAUTHORIZED", "Unauthorized traffic detected: " + sourceIP + " -> " + destIP);
logger.warn("Unauthorized traffic: {} ({}) -> {} ({})", sourceIP, sourceSegment, destIP, destSegment);
}
}
private String identifySegment(String ip) {
for (NetworkSegment segment : segments.values()) {
if (ip.startsWith(segment.getCidr().replace("/24", "").replace("10.0.", "10.0.").split("\\.")[0] + ".")) {
return segment.getName();
}
}
return null;
}
public Map<String, Object> getStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("enabled", enabled);
stats.put("totalSegments", totalSegments.get());
stats.put("violationsDetected", violationsDetected.get());
stats.put("segmentsConfigured", segments.size());
stats.put("policiesConfigured", policies.size());
Map<String, Integer> connectionCounts = new HashMap<>();
for (Map.Entry<String, List<String>> entry : segmentConnections.entrySet()) {
connectionCounts.put(entry.getKey(), entry.getValue().size());
}
stats.put("connectionCounts", connectionCounts);
return stats;
}
public Map<String, NetworkSegment> getSegments() {
return new HashMap<>(segments);
}
public Map<String, SegmentPolicy> getPolicies() {
return new HashMap<>(policies);
}
public Map<String, List<String>> getConnections() {
return new HashMap<>(segmentConnections);
}
public List<SegmentationEvent> getRecentEvents(int limit) {
List<SegmentationEvent> events = new ArrayList<>();
int count = 0;
for (SegmentationEvent event : eventLog) {
if (count++ >= limit) break;
events.add(event);
}
return events;
}
private void logEvent(String source, String dest, String action, String details) {
SegmentationEvent event = new SegmentationEvent(source, dest, action, details, LocalDateTime.now());
eventLog.offer(event);
if (eventLog.size() > MAX_EVENTS) {
eventLog.poll();
}
}
public void enable() {
enabled = true;
logger.info("Network segmentation enabled");
}
public void disable() {
enabled = false;
logger.info("Network segmentation disabled");
}
public static class NetworkSegment {
private final String name;
private final String description;
private final String cidr;
private volatile boolean microsegmentationEnabled = false;
public NetworkSegment(String name, String description, String cidr) {
this.name = name;
this.description = description;
this.cidr = cidr;
}
public String getName() { return name; }
public String getDescription() { return description; }
public String getCidr() { return cidr; }
public boolean isMicrosegmentationEnabled() { return microsegmentationEnabled; }
public void setMicrosegmentationEnabled(boolean enabled) { this.microsegmentationEnabled = enabled; }
}
public static class SegmentPolicy {
private final String name;
private final String type;
private final String description;
private final int priority;
public SegmentPolicy(String name, String type, String description, int priority) {
this.name = name;
this.type = type;
this.description = description;
this.priority = priority;
}
public String getName() { return name; }
public String getType() { return type; }
public String getDescription() { return description; }
public int getPriority() { return priority; }
}
public static class SegmentationEvent {
private final String source;
private final String destination;
private final String action;
private final String details;
private final LocalDateTime timestamp;
public SegmentationEvent(String source, String destination, String action, String details, LocalDateTime timestamp) {
this.source = source;
this.destination = destination;
this.action = action;
this.details = details;
this.timestamp = timestamp;
}
public String getSource() { return source; }
public String getDestination() { return destination; }
public String getAction() { return action; }
public String getDetails() { return details; }
public LocalDateTime getTimestamp() { return timestamp; }
}
}
@@ -0,0 +1,388 @@
package com.aluer.security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicLong;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.Map.Entry;
@Component
public class NetworkSnifferService {
private static final Logger logger = LoggerFactory.getLogger(NetworkSnifferService.class);
private final Map<String, CapturedPacket> packetBuffer = new LinkedHashMap<>();
private final Queue<SnifferAlert> alertQueue = new ConcurrentLinkedQueue<>();
private final Map<String, PacketStatistics> protocolStats = new ConcurrentHashMap<>();
private final Map<String, java.util.List<CapturedPacket>> packetHistory = new java.util.concurrent.ConcurrentHashMap<>();
private final Map<String, SessionInfo> sessions = new ConcurrentHashMap<>();
private final AtomicLong totalPacketsCaptured = new AtomicLong(0);
private final AtomicLong totalBytesCaptured = new AtomicLong(0);
private final AtomicLong suspiciousPackets = new AtomicLong(0);
private volatile boolean capturing = false;
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private static final int MAX_BUFFER_SIZE = 10000;
private static final int PACKET_HISTORY_SIZE = 1000;
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public NetworkSnifferService() {
initializeProtocolStats();
logger.info("Network Sniffer Service initialized");
}
private void initializeProtocolStats() {
protocolStats.put("TCP", new PacketStatistics("TCP"));
protocolStats.put("UDP", new PacketStatistics("UDP"));
protocolStats.put("ICMP", new PacketStatistics("ICMP"));
protocolStats.put("HTTP", new PacketStatistics("HTTP"));
protocolStats.put("HTTPS", new PacketStatistics("HTTPS"));
protocolStats.put("DNS", new PacketStatistics("DNS"));
protocolStats.put("SSH", new PacketStatistics("SSH"));
protocolStats.put("FTP", new PacketStatistics("FTP"));
protocolStats.put("OTHER", new PacketStatistics("OTHER"));
}
public void startCapture() {
capturing = true;
logger.info("Packet capture started");
scheduler.scheduleAtFixedRate(() -> {
analyzeCapturedTraffic();
detectAnomalies();
cleanupOldData();
}, 5, 5, TimeUnit.SECONDS);
}
public void stopCapture() {
capturing = false;
logger.info("Packet capture stopped");
}
public void capturePacket(String sourceIP, String destIP, int sourcePort, int destPort,
String protocol, byte[] payload, int length) {
if (!capturing) return;
totalPacketsCaptured.incrementAndGet();
totalBytesCaptured.addAndGet(length);
String packetId = UUID.randomUUID().toString();
CapturedPacket packet = new CapturedPacket(
packetId, sourceIP, destIP, sourcePort, destPort,
protocol, payload, length, LocalDateTime.now()
);
packetBuffer.put(packetId, packet);
if (packetBuffer.size() > MAX_BUFFER_SIZE) {
String firstKey = packetBuffer.keySet().iterator().next();
packetBuffer.remove(firstKey);
}
String sessionKey = sourceIP + "-" + destIP + "-" + destPort;
SessionInfo session = sessions.computeIfAbsent(sessionKey, k -> new SessionInfo(sourceIP, destIP, destPort));
session.addPacket(packet);
updateProtocolStats(protocol, length);
updatePacketHistory(sourceIP, packet);
if (isSuspiciousPacket(packet)) {
suspiciousPackets.incrementAndGet();
triggerAlert(packet, "Suspicious packet detected");
}
analyzePacketContent(packet);
}
private void updateProtocolStats(String protocol, int length) {
PacketStatistics stats = protocolStats.computeIfAbsent(protocol, k -> new PacketStatistics(protocol));
stats.incrementPacketCount();
stats.addBytes(length);
}
private void updatePacketHistory(String ip, CapturedPacket packet) {
List<CapturedPacket> history = packetHistory.computeIfAbsent(ip, k -> new ArrayList<>());
history.add(packet);
if (history.size() > PACKET_HISTORY_SIZE) {
history.remove(0);
}
}
private boolean isSuspiciousPacket(CapturedPacket packet) {
if (packet.getPayload() != null && packet.getPayload().length > 10000) {
return true;
}
if (packet.getPayload() != null) {
String payloadStr = new String(packet.getPayload());
if (payloadStr.contains("NULL") || payloadStr.contains("\\x00")) {
return true;
}
}
return false;
}
private void analyzePacketContent(CapturedPacket packet) {
if (packet.getPayload() == null || packet.getPayload().length == 0) return;
String payloadStr = new String(packet.getPayload());
if (payloadStr.matches(".*(?i)(union|select|insert|update|delete).*")) {
triggerAlert(packet, "SQL Injection attempt detected");
}
if (payloadStr.matches(".*(?i)(<script|javascript:|onerror=).*")) {
triggerAlert(packet, "XSS attempt detected");
}
if (payloadStr.matches(".*(?i)(\\.\\./|\\.\\.\\\\).*")) {
triggerAlert(packet, "Directory traversal attempt detected");
}
if (payloadStr.matches(".*(?i)(cmd\\.exe|powershell|/bin/bash).*")) {
triggerAlert(packet, "Command injection attempt detected");
}
}
private void analyzeCapturedTraffic() {
if (packetBuffer.isEmpty()) return;
Map<String, Integer> ipCounts = new HashMap<>();
for (CapturedPacket packet : packetBuffer.values()) {
ipCounts.merge(packet.getSourceIP(), 1, Integer::sum);
}
for (Map.Entry<String, Integer> entry : ipCounts.entrySet()) {
if (entry.getValue() > 1000) {
logger.warn("High packet count from IP: {} - {} packets", entry.getKey(), entry.getValue());
}
}
}
private void detectAnomalies() {
for (SessionInfo session : sessions.values()) {
if (session.getPacketCount() > 5000 && session.getTotalBytes() < session.getPacketCount() * 10) {
logger.warn("Potential slowloris attack from {} to {}", session.getSourceIP(), session.getDestIP());
}
if (session.getPacketCount() > 10000) {
triggerAlert(session.getLatestPacket(), "Potential DoS attack detected");
}
}
}
private void cleanupOldData() {
long now = System.currentTimeMillis();
List<String> expiredSessions = new ArrayList<>();
for (Map.Entry<String, SessionInfo> entry : sessions.entrySet()) {
if (now - entry.getValue().getLastPacketTime() > 300000) {
expiredSessions.add(entry.getKey());
}
}
for (String key : expiredSessions) {
sessions.remove(key);
}
}
private void triggerAlert(CapturedPacket packet, String reason) {
SnifferAlert alert = new SnifferAlert(
packet.getSourceIP(),
packet.getDestIP(),
packet.getProtocol(),
reason,
LocalDateTime.now()
);
alertQueue.offer(alert);
if (alertQueue.size() > 500) {
alertQueue.poll();
}
logger.warn("Sniffer Alert: {} -> {} : {}", packet.getSourceIP(), packet.getDestIP(), reason);
}
public Map<String, Object> getStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("capturing", capturing);
stats.put("totalPacketsCaptured", totalPacketsCaptured.get());
stats.put("totalBytesCaptured", totalBytesCaptured.get());
stats.put("suspiciousPackets", suspiciousPackets.get());
stats.put("bufferSize", packetBuffer.size());
stats.put("activeSessions", sessions.size());
stats.put("alertQueueSize", alertQueue.size());
Map<String, PacketStatistics> protoStats = new HashMap<>();
for (Map.Entry<String, PacketStatistics> entry : protocolStats.entrySet()) {
protoStats.put(entry.getKey(), entry.getValue());
}
stats.put("protocolStats", protoStats);
return stats;
}
public List<CapturedPacket> getRecentPackets(int limit) {
List<CapturedPacket> packets = new ArrayList<>();
int count = 0;
for (CapturedPacket packet : packetBuffer.values()) {
if (count++ >= limit) break;
packets.add(packet);
}
return packets;
}
public List<CapturedPacket> getPacketsByIP(String ip, int limit) {
List<CapturedPacket> packets = new ArrayList<>();
List<CapturedPacket> history = packetHistory.get(ip);
if (history != null) {
int count = 0;
for (CapturedPacket packet : history) {
if (count++ >= limit) break;
packets.add(packet);
}
}
return packets;
}
public List<SnifferAlert> getRecentAlerts(int limit) {
List<SnifferAlert> alerts = new ArrayList<>();
int count = 0;
for (SnifferAlert alert : alertQueue) {
if (count++ >= limit) break;
alerts.add(alert);
}
return alerts;
}
public Map<String, SessionInfo> getActiveSessions() {
return new HashMap<>(sessions);
}
public void clearBuffer() {
packetBuffer.clear();
logger.info("Packet buffer cleared");
}
public void exportPackets(String format) {
logger.info("Exporting packets in {} format", format);
}
public static class CapturedPacket {
private final String packetId;
private final String sourceIP;
private final String destIP;
private final int sourcePort;
private final int destPort;
private final String protocol;
private final byte[] payload;
private final int length;
private final LocalDateTime timestamp;
public CapturedPacket(String packetId, String sourceIP, String destIP, int sourcePort,
int destPort, String protocol, byte[] payload, int length, LocalDateTime timestamp) {
this.packetId = packetId;
this.sourceIP = sourceIP;
this.destIP = destIP;
this.sourcePort = sourcePort;
this.destPort = destPort;
this.protocol = protocol;
this.payload = payload;
this.length = length;
this.timestamp = timestamp;
}
public String getPacketId() { return packetId; }
public String getSourceIP() { return sourceIP; }
public String getDestIP() { return destIP; }
public int getSourcePort() { return sourcePort; }
public int getDestPort() { return destPort; }
public String getProtocol() { return protocol; }
public byte[] getPayload() { return payload; }
public int getLength() { return length; }
public LocalDateTime getTimestamp() { return timestamp; }
}
public static class PacketStatistics {
private final String protocolName;
private final AtomicLong packetCount = new AtomicLong(0);
private final AtomicLong byteCount = new AtomicLong(0);
public PacketStatistics(String protocolName) {
this.protocolName = protocolName;
}
public void incrementPacketCount() { packetCount.incrementAndGet(); }
public void addBytes(int bytes) { byteCount.addAndGet(bytes); }
public String getProtocolName() { return protocolName; }
public long getPacketCount() { return packetCount.get(); }
public long getByteCount() { return byteCount.get(); }
}
public static class SessionInfo {
private final String sourceIP;
private final String destIP;
private final int destPort;
private volatile long packetCount;
private volatile long totalBytes;
private volatile long startTime;
private volatile long lastPacketTime;
private volatile CapturedPacket latestPacket;
public SessionInfo(String sourceIP, String destIP, int destPort) {
this.sourceIP = sourceIP;
this.destIP = destIP;
this.destPort = destPort;
this.startTime = System.currentTimeMillis();
this.lastPacketTime = startTime;
}
public void addPacket(CapturedPacket packet) {
packetCount++;
totalBytes += packet.getLength();
lastPacketTime = System.currentTimeMillis();
latestPacket = packet;
}
public String getSourceIP() { return sourceIP; }
public String getDestIP() { return destIP; }
public int getDestPort() { return destPort; }
public long getPacketCount() { return packetCount; }
public long getTotalBytes() { return totalBytes; }
public long getStartTime() { return startTime; }
public long getLastPacketTime() { return lastPacketTime; }
public CapturedPacket getLatestPacket() { return latestPacket; }
}
public static class SnifferAlert {
private final String sourceIP;
private final String destIP;
private final String protocol;
private final String reason;
private final LocalDateTime timestamp;
public SnifferAlert(String sourceIP, String destIP, String protocol, String reason, LocalDateTime timestamp) {
this.sourceIP = sourceIP;
this.destIP = destIP;
this.protocol = protocol;
this.reason = reason;
this.timestamp = timestamp;
}
public String getSourceIP() { return sourceIP; }
public String getDestIP() { return destIP; }
public String getProtocol() { return protocol; }
public String getReason() { return reason; }
public LocalDateTime getTimestamp() { return timestamp; }
}
}
@@ -0,0 +1,661 @@
package com.aluer.security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.Deque;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
@Service
public class NetworkThreatFusionService {
private static final Logger logger = LoggerFactory.getLogger(NetworkThreatFusionService.class);
private static final int EVENT_SAMPLE_SIZE = 200;
private static final int HIGH_RISK_THRESHOLD = 60;
private static final int CRITICAL_RISK_THRESHOLD = 80;
private final DDoSProtectionService ddosProtectionService;
private final FirewallService firewallService;
private final IntrusionDetectionService intrusionDetectionService;
private final NetworkMonitorService networkMonitorService;
private final TrafficAnalysisService trafficAnalysisService;
private final PortScanDetectionService portScanDetectionService;
private final PacketInspectionService packetInspectionService;
private final IPReputationService ipReputationService;
private final GeoIPService geoIPService;
private final RateLimitService rateLimitService;
private final Map<String, QuarantineRecord> quarantinedIps = new ConcurrentHashMap<>();
private final Deque<FusionIncident> incidentLog = new ConcurrentLinkedDeque<>();
public NetworkThreatFusionService(DDoSProtectionService ddosProtectionService,
FirewallService firewallService,
IntrusionDetectionService intrusionDetectionService,
NetworkMonitorService networkMonitorService,
TrafficAnalysisService trafficAnalysisService,
PortScanDetectionService portScanDetectionService,
PacketInspectionService packetInspectionService,
IPReputationService ipReputationService,
GeoIPService geoIPService,
RateLimitService rateLimitService) {
this.ddosProtectionService = ddosProtectionService;
this.firewallService = firewallService;
this.intrusionDetectionService = intrusionDetectionService;
this.networkMonitorService = networkMonitorService;
this.trafficAnalysisService = trafficAnalysisService;
this.portScanDetectionService = portScanDetectionService;
this.packetInspectionService = packetInspectionService;
this.ipReputationService = ipReputationService;
this.geoIPService = geoIPService;
this.rateLimitService = rateLimitService;
}
public Map<String, Object> getPosture() {
List<ThreatAssessment> assessments = collectThreatAssessments();
long highRiskCount = assessments.stream()
.filter(assessment -> assessment.riskScore >= HIGH_RISK_THRESHOLD)
.count();
long criticalRiskCount = assessments.stream()
.filter(assessment -> assessment.riskScore >= CRITICAL_RISK_THRESHOLD)
.count();
Map<String, Object> ddosStats = ddosProtectionService.getStats();
Map<String, Object> intrusionStats = intrusionDetectionService.getStats();
Map<String, Object> firewallStats = firewallService.getStats();
Map<String, Object> portScanStats = portScanDetectionService.getStats();
Map<String, Object> packetStats = packetInspectionService.getStats();
Map<String, Object> networkStats = networkMonitorService.getGlobalStats();
int threatPressure = 0;
threatPressure += toInt(ddosStats.get("blockedIPs")) * 6;
threatPressure += toInt(intrusionStats.get("activeAlerts")) * 10;
threatPressure += toInt(portScanStats.get("blockedScanners")) * 8;
threatPressure += Math.min(20, toInt(packetStats.get("maliciousBlocked")));
threatPressure += toInt(firewallStats.get("blacklistSize")) * 4;
threatPressure += quarantinedIps.size() * 8;
threatPressure += (int) highRiskCount * 5;
threatPressure += (int) criticalRiskCount * 8;
int maxObservedRisk = assessments.stream()
.mapToInt(assessment -> assessment.riskScore)
.max()
.orElse(0);
threatPressure += maxObservedRisk / 3;
int postureScore = Math.max(0, 100 - Math.min(100, threatPressure));
String threatLevel = determineThreatLevel(postureScore, maxObservedRisk);
Map<String, Object> signals = new LinkedHashMap<>();
signals.put("ddosBlockedIPs", ddosStats.getOrDefault("blockedIPs", 0));
signals.put("firewallBlacklist", firewallStats.getOrDefault("blacklistSize", 0));
signals.put("intrusionAlerts", intrusionStats.getOrDefault("activeAlerts", 0));
signals.put("portScanBlocks", portScanStats.getOrDefault("blockedScanners", 0));
signals.put("packetBlocks", packetStats.getOrDefault("maliciousBlocked", 0));
signals.put("activeNetworkSessions", networkStats.getOrDefault("activeSessions", 0));
Map<String, Object> posture = new LinkedHashMap<>();
posture.put("postureScore", postureScore);
posture.put("threatLevel", threatLevel);
posture.put("highRiskIPs", highRiskCount);
posture.put("criticalRiskIPs", criticalRiskCount);
posture.put("quarantinedIPs", quarantinedIps.size());
posture.put("signals", signals);
posture.put("topRiskIPs", toAssessmentMaps(assessments, 5));
posture.put("recommendations", buildRecommendations(postureScore, assessments));
return posture;
}
public Map<String, Object> inspectIP(String ip) {
ThreatAssessment assessment = assessIp(ip);
return assessment.toMap();
}
public List<Map<String, Object>> getTopRiskIPs(int limit) {
return toAssessmentMaps(collectThreatAssessments(), limit);
}
public List<Map<String, Object>> getRecentIncidents(int limit) {
List<ThreatAssessment> assessments = collectThreatAssessments();
Map<String, Integer> currentRisk = new ConcurrentHashMap<>();
for (ThreatAssessment assessment : assessments) {
currentRisk.put(assessment.ip, assessment.riskScore);
}
List<FusionIncident> incidents = new ArrayList<>(incidentLog);
for (DDoSProtectionService.AttackEvent event : ddosProtectionService.getAttackLog(EVENT_SAMPLE_SIZE)) {
incidents.add(new FusionIncident("ddos", event.ip, event.type, event.details, event.timestamp,
currentRisk.getOrDefault(event.ip, 0)));
}
for (PortScanDetectionService.ScanEvent event : portScanDetectionService.getScanLog(EVENT_SAMPLE_SIZE)) {
incidents.add(new FusionIncident("port-scan", event.ip, event.reason, event.details, event.timestamp,
currentRisk.getOrDefault(event.ip, 0)));
}
for (PacketInspectionService.PacketAlert alert : packetInspectionService.getAlerts(EVENT_SAMPLE_SIZE)) {
incidents.add(new FusionIncident("packet-inspection", alert.sourceIP, alert.ruleName, alert.details, alert.timestamp,
currentRisk.getOrDefault(alert.sourceIP, 0)));
}
for (IntrusionDetectionService.IntrusionEvent event : intrusionDetectionService.getEvents(EVENT_SAMPLE_SIZE)) {
if (isActionableSource(event.sourceIP)) {
incidents.add(new FusionIncident("intrusion", event.sourceIP, event.type, event.details, event.timestamp,
currentRisk.getOrDefault(event.sourceIP, 0)));
}
}
for (NetworkMonitorService.NetworkAlert alert : networkMonitorService.getAlerts(EVENT_SAMPLE_SIZE)) {
incidents.add(new FusionIncident("network-monitor", alert.getIp(), alert.getType(), alert.getDetails(), alert.getTimestamp(),
currentRisk.getOrDefault(alert.getIp(), 0)));
}
incidents.sort(Comparator.comparingLong((FusionIncident incident) -> incident.timestamp).reversed());
List<Map<String, Object>> result = new ArrayList<>();
int maxItems = Math.max(1, limit);
for (FusionIncident incident : incidents) {
if (result.size() >= maxItems) {
break;
}
result.add(incident.toMap());
}
return result;
}
public Map<String, Object> quarantineIP(String ip, String actor, String reason) {
String targetIp = normalizeTarget(ip);
if (targetIp == null) {
return invalidTarget("invalid", "IP 不能为空");
}
String operator = defaultText(actor, "system");
String details = defaultText(reason, "Manual quarantine triggered");
ddosProtectionService.blockIP(targetIp, "THREAT_FUSION_QUARANTINE", details);
firewallService.addToBlacklist(targetIp);
ipReputationService.addToBlacklist(targetIp);
networkMonitorService.addAlert(targetIp, "QUARANTINED", details);
QuarantineRecord record = quarantinedIps.compute(targetIp, (key, existing) -> {
if (existing == null) {
return new QuarantineRecord(targetIp, operator, details);
}
existing.actor = operator;
existing.reason = details;
existing.lastUpdated = System.currentTimeMillis();
existing.count++;
return existing;
});
logger.warn("Threat fusion quarantined IP {} by {}: {}", targetIp, operator, details);
logInternalIncident("quarantine", targetIp, "THREAT_FUSION_QUARANTINE", details, 100);
Map<String, Object> response = new LinkedHashMap<>(inspectIP(targetIp));
response.put("status", "quarantined");
response.put("quarantine", record.toMap());
return response;
}
public Map<String, Object> releaseIP(String ip, String actor, String reason) {
String targetIp = normalizeTarget(ip);
if (targetIp == null) {
return invalidTarget("invalid", "IP 不能为空");
}
String operator = defaultText(actor, "system");
String details = defaultText(reason, "Manual release triggered");
ddosProtectionService.unblockIP(targetIp);
firewallService.removeFromBlacklist(targetIp);
ipReputationService.removeFromBlacklist(targetIp);
networkMonitorService.addAlert(targetIp, "RELEASED", details);
QuarantineRecord removed = quarantinedIps.remove(targetIp);
logger.info("Threat fusion released IP {} by {}: {}", targetIp, operator, details);
logInternalIncident("release", targetIp, "THREAT_FUSION_RELEASE", details, 0);
Map<String, Object> response = new LinkedHashMap<>(inspectIP(targetIp));
response.put("status", removed != null ? "released" : "not-quarantined");
if (removed != null) {
response.put("releasedQuarantine", removed.toMap());
}
return response;
}
private List<ThreatAssessment> collectThreatAssessments() {
Set<String> candidates = new HashSet<>();
for (DDoSProtectionService.BlockedIP blockedIP : ddosProtectionService.getAllBlockedIPs()) {
addCandidate(candidates, blockedIP.ip);
}
for (FirewallService.ConnectionState connection : firewallService.getActiveConnections()) {
addCandidate(candidates, connection.sourceIP);
}
for (FirewallService.FirewallLog log : firewallService.getLogs(EVENT_SAMPLE_SIZE)) {
addCandidate(candidates, log.sourceIP);
}
for (NetworkMonitorService.NetworkSession session : networkMonitorService.getAllSessions()) {
addCandidate(candidates, session.getIp());
}
for (NetworkMonitorService.NetworkAlert alert : networkMonitorService.getAlerts(EVENT_SAMPLE_SIZE)) {
addCandidate(candidates, alert.getIp());
}
for (PortScanDetectionService.BlockedScanner scanner : portScanDetectionService.getBlockedScanners()) {
addCandidate(candidates, scanner.ip);
}
for (PortScanDetectionService.ScanEvent event : portScanDetectionService.getScanLog(EVENT_SAMPLE_SIZE)) {
addCandidate(candidates, event.ip);
}
for (PacketInspectionService.PacketAlert alert : packetInspectionService.getAlerts(EVENT_SAMPLE_SIZE)) {
addCandidate(candidates, alert.sourceIP);
}
for (TrafficAnalysisService.TrafficSession session : trafficAnalysisService.getAllSessions()) {
addCandidate(candidates, session.getIp());
}
for (IPReputationService.IPProfile profile : ipReputationService.getAllProfiles()) {
addCandidate(candidates, profile.ip);
}
for (GeoIPService.GeoEvent event : geoIPService.getRecentEvents(EVENT_SAMPLE_SIZE)) {
addCandidate(candidates, event.ip);
}
for (IntrusionDetectionService.IntrusionEvent event : intrusionDetectionService.getEvents(EVENT_SAMPLE_SIZE)) {
addCandidate(candidates, event.sourceIP);
}
candidates.addAll(quarantinedIps.keySet());
List<ThreatAssessment> assessments = new ArrayList<>();
for (String candidate : candidates) {
ThreatAssessment assessment = assessIp(candidate);
if (assessment.riskScore > 0 || assessment.blocked || assessment.quarantined) {
assessments.add(assessment);
}
}
assessments.sort(Comparator.comparingInt((ThreatAssessment assessment) -> assessment.riskScore)
.reversed()
.thenComparing(assessment -> assessment.ip));
return assessments;
}
private ThreatAssessment assessIp(String ip) {
ThreatAssessment assessment = new ThreatAssessment(normalizeTarget(ip));
if (assessment.ip == null) {
return assessment;
}
DDoSProtectionService.BlockedIP ddosBlock = ddosProtectionService.getBlockInfo(assessment.ip);
if (ddosBlock != null) {
assessment.addRisk(35, "DDoS 引擎已封禁,原因: " + ddosBlock.reason);
assessment.blocked = true;
}
QuarantineRecord quarantineRecord = quarantinedIps.get(assessment.ip);
if (quarantineRecord != null) {
assessment.addRisk(40, "融合防御已隔离该 IP");
assessment.quarantined = true;
assessment.blocked = true;
}
if (firewallService.isBlacklisted(assessment.ip)) {
assessment.addRisk(25, "防火墙黑名单命中");
assessment.blocked = true;
}
PortScanDetectionService.BlockedScanner blockedScanner = portScanDetectionService.getBlockInfo(assessment.ip);
if (blockedScanner != null) {
assessment.addRisk(30, "端口扫描检测已封禁,原因: " + blockedScanner.reason);
}
NetworkMonitorService.NetworkSession session = networkMonitorService.getSession(assessment.ip);
if (session != null) {
if (session.getConnectionCount() >= 40) {
assessment.addRisk(Math.min(20, session.getConnectionCount() / 2),
"短时间连接端口过多: " + session.getConnectionCount());
}
long totalBytes = session.getTotalBytesIn() + session.getTotalBytesOut();
if (totalBytes >= 50_000_000L) {
assessment.addRisk(10, "观测到高流量会话");
}
}
NetworkMonitorService.BandwidthTracker bandwidthTracker = networkMonitorService.getBandwidthTracker(assessment.ip);
if (bandwidthTracker != null && bandwidthTracker.isHighBandwidth()) {
assessment.addRisk(15, "带宽窗口突增");
}
TrafficAnalysisService.AnomalyScore anomalyScore = trafficAnalysisService.getAnomalyScore(assessment.ip);
if (anomalyScore != null && anomalyScore.getScore() > 0.2) {
int contribution = (int) Math.round(anomalyScore.getScore() * 30);
assessment.addRisk(contribution, String.format(Locale.ROOT,
"流量异常评分偏高: %.2f", anomalyScore.getScore()));
}
int packetAlerts = countPacketAlerts(assessment.ip);
if (packetAlerts > 0) {
assessment.addRisk(Math.min(20, packetAlerts * 5), "包检测已触发 " + packetAlerts + " 次告警");
}
int intrusionEvents = countIntrusionEvents(assessment.ip);
if (intrusionEvents > 0) {
assessment.addRisk(Math.min(25, intrusionEvents * 5), "入侵检测记录到 " + intrusionEvents + " 个相关事件");
}
int ddosEvents = countDdosEvents(assessment.ip);
if (ddosEvents > 0) {
assessment.addRisk(Math.min(15, ddosEvents * 3), "近期 DDoS/泛洪事件: " + ddosEvents);
}
int firewallBlocks = countFirewallBlocks(assessment.ip);
if (firewallBlocks > 0) {
assessment.addRisk(Math.min(12, firewallBlocks * 3), "防火墙近期阻断次数: " + firewallBlocks);
}
boolean reputationBlacklisted = ipReputationService.isBlacklisted(assessment.ip);
if (reputationBlacklisted) {
assessment.addRisk(20, "IP 信誉黑名单命中");
assessment.blocked = true;
}
IPReputationService.IPProfile profile = ipReputationService.getProfile(assessment.ip);
if (profile != null) {
double reputationScore = profile.calculateScore();
assessment.metadata.put("reputationScore", roundToOneDecimal(reputationScore));
if (profile.blacklisted && !reputationBlacklisted) {
assessment.addRisk(20, "IP 信誉黑名单命中");
assessment.blocked = true;
} else if (reputationScore < 30) {
assessment.addRisk((int) Math.round(30 - reputationScore),
"IP 信誉分过低: " + roundToOneDecimal(reputationScore));
}
}
GeoIPService.GeoLocation geoLocation = geoIPService.getGeoLocation(assessment.ip);
if (geoLocation != null) {
assessment.metadata.put("country", geoLocation.country);
Set<String> blockedCountries = geoIPService.getBlockedCountries();
Set<String> allowedCountries = geoIPService.getAllowedCountries();
if (blockedCountries.contains(geoLocation.country)) {
assessment.addRisk(15, "来源国家已被封锁: " + geoLocation.country);
} else if (!allowedCountries.isEmpty() && !allowedCountries.contains(geoLocation.country)) {
assessment.addRisk(10, "来源国家不在白名单中: " + geoLocation.country);
}
}
RateLimitService.RateLimitStats rateLimitStats = rateLimitService.getStats(assessment.ip);
if (rateLimitStats != null && rateLimitStats.rejections.get() > 0) {
long rejections = rateLimitStats.rejections.get();
assessment.addRisk((int) Math.min(10, rejections * 2), "限流拒绝次数: " + rejections);
}
assessment.riskScore = Math.min(100, assessment.riskScore);
assessment.riskLevel = riskLevelFor(assessment.riskScore);
return assessment;
}
private List<Map<String, Object>> toAssessmentMaps(List<ThreatAssessment> assessments, int limit) {
List<Map<String, Object>> result = new ArrayList<>();
int maxItems = Math.max(1, limit);
for (ThreatAssessment assessment : assessments) {
if (result.size() >= maxItems) {
break;
}
result.add(assessment.toMap());
}
return result;
}
private List<String> buildRecommendations(int postureScore, List<ThreatAssessment> assessments) {
List<String> recommendations = new ArrayList<>();
if (assessments.isEmpty()) {
recommendations.add("当前网络态势平稳,继续观察连接基线即可。");
return recommendations;
}
if (assessments.stream().anyMatch(assessment -> assessment.riskScore >= CRITICAL_RISK_THRESHOLD)) {
recommendations.add("优先隔离高风险 IP,并同步检查上游代理、防火墙或云清洗规则。");
}
if (portScanDetectionService.getStats().getOrDefault("blockedScanners", 0) instanceof Number blockedScanners
&& blockedScanners.longValue() > 0) {
recommendations.add("当前存在端口扫描迹象,建议只暴露 Minecraft 与必要的管理入口。");
}
Map<String, Object> packetStats = packetInspectionService.getStats();
if (toInt(packetStats.get("maliciousBlocked")) > 0) {
recommendations.add("已检测到异常报文,建议复核包检测规则和上游流量清洗策略。");
}
if (postureScore < 60) {
recommendations.add("建议把防火墙切到更严格的连接阈值,并临时提高关键接口限流。");
}
if (recommendations.isEmpty()) {
recommendations.add("风险可控,继续观察高风险 IP 的后续行为。");
}
return recommendations.stream().limit(3).toList();
}
private String determineThreatLevel(int postureScore, int maxObservedRisk) {
int compositeRisk = Math.max(maxObservedRisk, 100 - postureScore);
return riskLevelFor(compositeRisk);
}
private String riskLevelFor(int riskScore) {
if (riskScore >= 80) {
return "critical";
}
if (riskScore >= 60) {
return "high";
}
if (riskScore >= 40) {
return "elevated";
}
if (riskScore >= 20) {
return "guarded";
}
return "low";
}
private int countPacketAlerts(String ip) {
int count = 0;
for (PacketInspectionService.PacketAlert alert : packetInspectionService.getAlerts(EVENT_SAMPLE_SIZE)) {
if (ip.equals(alert.sourceIP)) {
count++;
}
}
return count;
}
private int countIntrusionEvents(String ip) {
int count = 0;
for (IntrusionDetectionService.IntrusionEvent event : intrusionDetectionService.getEvents(EVENT_SAMPLE_SIZE)) {
if (ip.equals(event.sourceIP)) {
count++;
}
}
return count;
}
private int countDdosEvents(String ip) {
int count = 0;
for (DDoSProtectionService.AttackEvent event : ddosProtectionService.getAttackLog(EVENT_SAMPLE_SIZE)) {
if (ip.equals(event.ip)) {
count++;
}
}
return count;
}
private int countFirewallBlocks(String ip) {
int count = 0;
for (FirewallService.FirewallLog log : firewallService.getLogs(EVENT_SAMPLE_SIZE)) {
if (ip.equals(log.sourceIP) && log.type.startsWith("BLOCK")) {
count++;
}
}
return count;
}
private void addCandidate(Collection<String> candidates, String source) {
String normalized = normalizeTarget(source);
if (normalized != null && isActionableSource(normalized)) {
candidates.add(normalized);
}
}
private boolean isActionableSource(String source) {
String lower = source.toLowerCase(Locale.ROOT);
return !lower.equals("system") && !lower.equals("request") && !lower.equals("unknown");
}
private String normalizeTarget(String ip) {
if (ip == null) {
return null;
}
String normalized = ip.trim();
return normalized.isEmpty() ? null : normalized;
}
private Map<String, Object> invalidTarget(String status, String message) {
Map<String, Object> response = new LinkedHashMap<>();
response.put("status", status);
response.put("message", message);
return response;
}
private String defaultText(String value, String fallback) {
String normalized = normalizeTarget(value);
return normalized != null ? normalized : fallback;
}
private int toInt(Object value) {
if (value instanceof Number number) {
return number.intValue();
}
if (value instanceof String text) {
try {
return Integer.parseInt(text);
} catch (NumberFormatException ignored) {
return 0;
}
}
return 0;
}
private double roundToOneDecimal(double value) {
return Math.round(value * 10.0) / 10.0;
}
private void logInternalIncident(String source, String ip, String type, String details, int riskScore) {
FusionIncident incident = new FusionIncident(source, ip, type, details, System.currentTimeMillis(), riskScore);
incidentLog.addFirst(incident);
while (incidentLog.size() > 500) {
incidentLog.removeLast();
}
}
private static final class ThreatAssessment {
private final String ip;
private int riskScore;
private String riskLevel = "low";
private boolean blocked;
private boolean quarantined;
private final List<String> reasons = new ArrayList<>();
private final Map<String, Object> metadata = new LinkedHashMap<>();
private ThreatAssessment(String ip) {
this.ip = ip;
}
private void addRisk(int value, String reason) {
if (value <= 0) {
return;
}
riskScore += value;
reasons.add(reason);
}
private Map<String, Object> toMap() {
Map<String, Object> data = new LinkedHashMap<>();
data.put("ip", ip);
data.put("riskScore", Math.min(100, riskScore));
data.put("riskLevel", riskLevel);
data.put("blocked", blocked);
data.put("quarantined", quarantined);
data.put("reasons", reasons);
data.put("metadata", metadata);
return data;
}
}
private static final class QuarantineRecord {
private final String ip;
private volatile String actor;
private volatile String reason;
private final long createdAt;
private volatile long lastUpdated;
private volatile int count = 1;
private QuarantineRecord(String ip, String actor, String reason) {
this.ip = ip;
this.actor = actor;
this.reason = reason;
this.createdAt = System.currentTimeMillis();
this.lastUpdated = createdAt;
}
private Map<String, Object> toMap() {
Map<String, Object> data = new LinkedHashMap<>();
data.put("ip", ip);
data.put("actor", actor);
data.put("reason", reason);
data.put("createdAt", createdAt);
data.put("lastUpdated", lastUpdated);
data.put("count", count);
return data;
}
}
private static final class FusionIncident {
private final String source;
private final String ip;
private final String type;
private final String details;
private final long timestamp;
private final int riskScore;
private FusionIncident(String source, String ip, String type, String details, long timestamp, int riskScore) {
this.source = source;
this.ip = ip;
this.type = type;
this.details = details;
this.timestamp = timestamp;
this.riskScore = riskScore;
}
private Map<String, Object> toMap() {
Map<String, Object> data = new LinkedHashMap<>();
data.put("source", source);
data.put("ip", ip);
data.put("type", type);
data.put("details", details);
data.put("timestamp", timestamp);
data.put("riskScore", riskScore);
return data;
}
}
}
@@ -0,0 +1,219 @@
package com.aluer.security;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
@Service
public class PacketInspectionService {
private final Map<String, PacketRule> rules = new ConcurrentHashMap<>();
private final Map<String, List<PacketLog>> packetLogs = new ConcurrentHashMap<>();
private final Queue<PacketAlert> alerts = new ConcurrentLinkedQueue<>();
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
private static final int MAX_PACKET_SIZE = 65535;
private static final int MAX_LOGS_PER_IP = 1000;
private final AtomicLong totalPacketsInspected = new AtomicLong(0);
private final AtomicLong maliciousPacketsBlocked = new AtomicLong(0);
public PacketInspectionService() {
initializeDefaultRules();
startCleanupTask();
}
private void initializeDefaultRules() {
addRule("BLOCK_LARGE_PACKETS", "size", ">", 10000, true, "Block oversized packets");
addRule("BLOCK_NULL_PACKETS", "size", "==", 0, true, "Block null size packets");
addRule("BLOCK_FRAGMENTED", "fragmented", "==", true, true, "Block fragmented packets");
addRule("ALERT_SYN_FLOOD", "tcp_flags", "==", "SYN", false, "Alert on SYN packets");
addRule("BLOCK_MALFORMED", "malformed", "==", true, true, "Block malformed packets");
}
public void addRule(String name, String field, String operator, Object value, boolean block, String description) {
PacketRule rule = new PacketRule(name, field, operator, value, block, description);
rules.put(name, rule);
}
public boolean inspectPacket(String sourceIP, Map<String, Object> packetData) {
totalPacketsInspected.incrementAndGet();
int packetSize = getIntValue(packetData, "size");
if (packetSize > MAX_PACKET_SIZE || packetSize < 0) {
logPacket(sourceIP, "INVALID_SIZE", packetData);
maliciousPacketsBlocked.incrementAndGet();
return false;
}
for (PacketRule rule : rules.values()) {
if (!rule.enabled) {
continue;
}
if (matchesRule(packetData, rule)) {
if (rule.block) {
logPacket(sourceIP, "BLOCKED:" + rule.name, packetData);
alerts.offer(new PacketAlert(sourceIP, rule.name, "Packet blocked by rule: " + rule.description, System.currentTimeMillis()));
maliciousPacketsBlocked.incrementAndGet();
return false;
} else {
logPacket(sourceIP, "ALERT:" + rule.name, packetData);
alerts.offer(new PacketAlert(sourceIP, rule.name, "Alert: " + rule.description, System.currentTimeMillis()));
}
}
}
logPacket(sourceIP, "ALLOWED", packetData);
return true;
}
private boolean matchesRule(Map<String, Object> packetData, PacketRule rule) {
Object fieldValue = packetData.get(rule.field);
if (fieldValue == null) {
return false;
}
return switch (rule.operator) {
case "==" -> fieldValue.equals(rule.value);
case "!=" -> !fieldValue.equals(rule.value);
case ">" -> compareValues(fieldValue, rule.value) > 0;
case "<" -> compareValues(fieldValue, rule.value) < 0;
case ">=" -> compareValues(fieldValue, rule.value) >= 0;
case "<=" -> compareValues(fieldValue, rule.value) <= 0;
case "contains" -> fieldValue.toString().contains(rule.value.toString());
default -> false;
};
}
private int compareValues(Object a, Object b) {
if (a instanceof Number && b instanceof Number) {
return Double.compare(((Number) a).doubleValue(), ((Number) b).doubleValue());
}
return 0;
}
private int getIntValue(Map<String, Object> data, String key) {
Object value = data.get(key);
if (value instanceof Number) {
return ((Number) value).intValue();
}
return 0;
}
private void logPacket(String sourceIP, String status, Map<String, Object> packetData) {
PacketLog log = new PacketLog(sourceIP, status, packetData, System.currentTimeMillis());
List<PacketLog> logs = packetLogs.computeIfAbsent(sourceIP, k -> new CopyOnWriteArrayList<>());
logs.add(log);
while (logs.size() > MAX_LOGS_PER_IP) {
logs.remove(0);
}
}
public List<PacketLog> getPacketLogs(String sourceIP, int limit) {
List<PacketLog> logs = packetLogs.get(sourceIP);
if (logs == null) {
return new ArrayList<>();
}
return logs.stream().limit(limit).toList();
}
public List<PacketAlert> getAlerts(int limit) {
List<PacketAlert> result = new ArrayList<>();
int count = 0;
for (PacketAlert alert : alerts) {
if (count++ >= limit) break;
result.add(alert);
}
return result;
}
public void enableRule(String ruleName) {
PacketRule rule = rules.get(ruleName);
if (rule != null) {
rule.enabled = true;
}
}
public void disableRule(String ruleName) {
PacketRule rule = rules.get(ruleName);
if (rule != null) {
rule.enabled = false;
}
}
public Collection<PacketRule> getRules() {
return rules.values();
}
private void startCleanupTask() {
scheduler.scheduleAtFixedRate(() -> {
long cutoff = System.currentTimeMillis() - 3600000;
packetLogs.entrySet().removeIf(entry -> {
List<PacketLog> logs = entry.getValue();
logs.removeIf(log -> log.timestamp < cutoff);
return logs.isEmpty();
});
alerts.removeIf(alert -> alert.timestamp < cutoff);
}, 300, 300, TimeUnit.SECONDS);
}
public Map<String, Object> getStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("totalInspected", totalPacketsInspected.get());
stats.put("maliciousBlocked", maliciousPacketsBlocked.get());
stats.put("activeRules", rules.size());
return stats;
}
public static class PacketRule {
public final String name;
public final String field;
public final String operator;
public final Object value;
public final boolean block;
public final String description;
public volatile boolean enabled = true;
public PacketRule(String name, String field, String operator, Object value, boolean block, String description) {
this.name = name;
this.field = field;
this.operator = operator;
this.value = value;
this.block = block;
this.description = description;
}
}
public static class PacketLog {
public final String sourceIP;
public final String status;
public final Map<String, Object> packetData;
public final long timestamp;
public PacketLog(String sourceIP, String status, Map<String, Object> packetData, long timestamp) {
this.sourceIP = sourceIP;
this.status = status;
this.packetData = packetData;
this.timestamp = timestamp;
}
}
public static class PacketAlert {
public final String sourceIP;
public final String ruleName;
public final String details;
public final long timestamp;
public PacketAlert(String sourceIP, String ruleName, String details, long timestamp) {
this.sourceIP = sourceIP;
this.ruleName = ruleName;
this.details = details;
this.timestamp = timestamp;
}
}
}
@@ -0,0 +1,259 @@
package com.aluer.security;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.nio.file.*;
import java.io.*;
@Service
public class PortScanDetectionService {
private final Map<String, ScanRecord> scanRecords = new ConcurrentHashMap<>();
private final Map<String, BlockedScanner> blockedScanners = new ConcurrentHashMap<>();
private final Queue<ScanEvent> scanLog = new ConcurrentLinkedQueue<>();
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
private static final int MAX_PORTS_SCANNED = 20;
private static final long SCAN_WINDOW = 60000;
private static final long BLOCK_DURATION = 3600000;
private static final int MAX_SCAN_EVENTS = 100;
private final AtomicLong totalScansDetected = new AtomicLong(0);
public PortScanDetectionService() {
startMonitoring();
}
public boolean checkPortAccess(String sourceIP, int port) {
if (isBlocked(sourceIP)) {
return false;
}
ScanRecord record = scanRecords.computeIfAbsent(sourceIP, k -> new ScanRecord(sourceIP));
boolean isScanning = record.recordPortAccess(port);
if (isScanning) {
blockScanner(sourceIP, "PORT_SCAN", "Scanned " + record.getScannedPortCount() + " ports");
totalScansDetected.incrementAndGet();
return false;
}
return true;
}
public boolean checkMultipleConnections(String sourceIP, Set<Integer> ports) {
if (isBlocked(sourceIP)) {
return false;
}
ScanRecord record = scanRecords.computeIfAbsent(sourceIP, k -> new ScanRecord(sourceIP));
boolean isScanning = record.recordMultipleConnections(ports);
if (isScanning) {
blockScanner(sourceIP, "MULTI_PORT_CONNECTION", "Connected to " + ports.size() + " ports");
totalScansDetected.incrementAndGet();
return false;
}
return true;
}
public boolean checkConnectionRate(String sourceIP) {
if (isBlocked(sourceIP)) {
return false;
}
ScanRecord record = scanRecords.computeIfAbsent(sourceIP, k -> new ScanRecord(sourceIP));
boolean isRateExcessive = record.checkConnectionRate();
if (isRateExcessive) {
blockScanner(sourceIP, "HIGH_CONNECTION_RATE", "Connection rate exceeded");
return false;
}
return true;
}
public void recordConnection(String sourceIP, int port) {
ScanRecord record = scanRecords.get(sourceIP);
if (record != null) {
record.recordConnection(port);
}
}
public boolean isBlocked(String ip) {
BlockedScanner blocked = blockedScanners.get(ip);
if (blocked == null) {
return false;
}
if (System.currentTimeMillis() - blocked.blockedAt > BLOCK_DURATION) {
blockedScanners.remove(ip);
return false;
}
return true;
}
public void blockScanner(String ip, String reason, String details) {
BlockedScanner blocked = blockedScanners.computeIfAbsent(ip, k -> new BlockedScanner(ip));
blocked.reason = reason;
blocked.details = details;
blocked.blockedAt = System.currentTimeMillis();
blocked.count.incrementAndGet();
logScan(ip, reason, details);
}
public void unblockScanner(String ip) {
blockedScanners.remove(ip);
}
public BlockedScanner getBlockInfo(String ip) {
return blockedScanners.get(ip);
}
public Collection<BlockedScanner> getBlockedScanners() {
return blockedScanners.values();
}
public ScanRecord getScanRecord(String ip) {
return scanRecords.get(ip);
}
public Collection<ScanRecord> getAllScanRecords() {
return scanRecords.values();
}
private void logScan(String ip, String reason, String details) {
ScanEvent event = new ScanEvent(ip, reason, details, System.currentTimeMillis());
scanLog.offer(event);
while (scanLog.size() > 1000) {
scanLog.poll();
}
}
public List<ScanEvent> getScanLog(int limit) {
List<ScanEvent> result = new ArrayList<>();
int count = 0;
for (ScanEvent event : scanLog) {
if (count++ >= limit) break;
result.add(event);
}
return result;
}
private void startMonitoring() {
scheduler.scheduleAtFixedRate(() -> {
long now = System.currentTimeMillis();
scanRecords.entrySet().removeIf(entry ->
now - entry.getValue().lastActivity > 300000);
blockedScanners.entrySet().removeIf(entry ->
now - entry.getValue().blockedAt > BLOCK_DURATION);
}, 30, 30, TimeUnit.SECONDS);
}
public Map<String, Object> getStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("activeScanners", scanRecords.size());
stats.put("blockedScanners", blockedScanners.size());
stats.put("totalDetected", totalScansDetected.get());
return stats;
}
public static class ScanRecord {
private final String ip;
private final Set<Integer> scannedPorts = ConcurrentHashMap.newKeySet();
private final List<Long> connectionTimestamps = new ArrayList<>();
private volatile long lastActivity;
public ScanRecord(String ip) {
this.ip = ip;
this.lastActivity = System.currentTimeMillis();
}
public boolean recordPortAccess(int port) {
scannedPorts.add(port);
lastActivity = System.currentTimeMillis();
cleanupOldRecords();
return scannedPorts.size() > MAX_PORTS_SCANNED;
}
public boolean recordMultipleConnections(Set<Integer> ports) {
for (int port : ports) {
scannedPorts.add(port);
}
lastActivity = System.currentTimeMillis();
cleanupOldRecords();
return scannedPorts.size() > MAX_PORTS_SCANNED;
}
public void recordConnection(int port) {
scannedPorts.add(port);
connectionTimestamps.add(System.currentTimeMillis());
lastActivity = System.currentTimeMillis();
cleanupOldRecords();
}
public boolean checkConnectionRate() {
cleanupOldRecords();
long now = System.currentTimeMillis();
connectionTimestamps.removeIf(t -> now - t > 10000);
return connectionTimestamps.size() > MAX_SCAN_EVENTS;
}
private void cleanupOldRecords() {
long cutoff = System.currentTimeMillis() - SCAN_WINDOW;
scannedPorts.removeIf(p -> false);
connectionTimestamps.removeIf(t -> t < cutoff);
}
public int getScannedPortCount() {
return scannedPorts.size();
}
public Set<Integer> getScannedPorts() {
return new HashSet<>(scannedPorts);
}
}
public static class BlockedScanner {
public final String ip;
public String reason;
public String details;
public volatile long blockedAt;
public final AtomicInteger count = new AtomicInteger(1);
public BlockedScanner(String ip) {
this.ip = ip;
this.blockedAt = System.currentTimeMillis();
}
}
public static class ScanEvent {
public final String ip;
public final String reason;
public final String details;
public final long timestamp;
public ScanEvent(String ip, String reason, String details, long timestamp) {
this.ip = ip;
this.reason = reason;
this.details = details;
this.timestamp = timestamp;
}
}
}
@@ -0,0 +1,441 @@
package com.aluer.security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicLong;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.nio.ByteBuffer;
@Component
public class ProtocolAnalysisService {
private static final Logger logger = LoggerFactory.getLogger(ProtocolAnalysisService.class);
private final MinecraftProtocolSecurityService minecraftProtocolSecurityService;
private final DDoSDefenseCoordinator ddosDefenseCoordinator;
private final Map<String, ProtocolStatistics> protocolStats = new ConcurrentHashMap<>();
private final Map<String, ConnectionState> connectionStates = new ConcurrentHashMap<>();
private final Queue<ProtocolEvent> eventLog = new ConcurrentLinkedQueue<>();
private final Map<String, List<PacketFragment>> fragmentBuffers = new ConcurrentHashMap<>();
private final AtomicLong totalPacketsAnalyzed = new AtomicLong(0);
private final AtomicLong totalMalformedPackets = new AtomicLong(0);
private final AtomicLong totalSuspiciousPackets = new AtomicLong(0);
private static final int MAX_PACKET_SIZE = 1024 * 1024;
private static final int FRAGMENT_TIMEOUT_MS = 5000;
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public ProtocolAnalysisService() {
this(new MinecraftProtocolSecurityService(), new DDoSDefenseCoordinator());
}
@Autowired
public ProtocolAnalysisService(MinecraftProtocolSecurityService minecraftProtocolSecurityService,
DDoSDefenseCoordinator ddosDefenseCoordinator) {
this.minecraftProtocolSecurityService = minecraftProtocolSecurityService;
this.ddosDefenseCoordinator = ddosDefenseCoordinator;
initializeProtocols();
}
private void initializeProtocols() {
protocolStats.put("TCP", new ProtocolStatistics("TCP"));
protocolStats.put("UDP", new ProtocolStatistics("UDP"));
protocolStats.put("ICMP", new ProtocolStatistics("ICMP"));
protocolStats.put("HTTP", new ProtocolStatistics("HTTP"));
protocolStats.put("HTTPS", new ProtocolStatistics("HTTPS"));
protocolStats.put("RCON", new ProtocolStatistics("RCON"));
}
public AnalysisResult analyzePacket(byte[] packetData, String sourceIP, String destIP, int sourcePort, int destPort) {
AnalysisResult result = new AnalysisResult();
result.setSourceIP(sourceIP);
result.setDestIP(destIP);
result.setSourcePort(sourcePort);
result.setDestPort(destPort);
result.setTimestamp(LocalDateTime.now());
if (packetData == null || packetData.length == 0) {
result.setValid(false);
result.setReason("Empty packet");
totalMalformedPackets.incrementAndGet();
return result;
}
if (packetData.length > MAX_PACKET_SIZE) {
result.setValid(false);
result.setReason("Packet too large");
totalMalformedPackets.incrementAndGet();
return result;
}
totalPacketsAnalyzed.incrementAndGet();
String protocol = detectProtocol(packetData, destPort);
result.setProtocol(protocol);
ProtocolStatistics stats = protocolStats.get(protocol);
if (stats != null) {
stats.incrementPacketCount();
stats.addBytes(packetData.length);
}
if (isMalformedPacket(packetData, protocol)) {
result.setValid(false);
result.setReason("Malformed packet structure");
result.setThreatLevel("HIGH");
totalMalformedPackets.incrementAndGet();
if (stats != null) {
stats.incrementMalformedCount();
}
logEvent(sourceIP, destIP, protocol, "MALFORMED", "Malformed packet detected");
return result;
}
if (isSuspiciousPacket(packetData, protocol)) {
result.setThreatLevel("MEDIUM");
result.addWarning("Suspicious packet pattern detected");
totalSuspiciousPackets.incrementAndGet();
if (stats != null) {
stats.incrementSuspiciousCount();
}
logEvent(sourceIP, destIP, protocol, "SUSPICIOUS", "Suspicious packet pattern");
}
List<MinecraftProtocolSecurityService.MinecraftThreatSignal> minecraftSignals =
minecraftProtocolSecurityService.analyzePacket(sourceIP, destIP, sourcePort, destPort, packetData);
for (MinecraftProtocolSecurityService.MinecraftThreatSignal signal : minecraftSignals) {
result.addWarning(signal.getType() + ": " + signal.getDetails());
result.setThreatLevel("HIGH");
logEvent(sourceIP, destIP, "MINECRAFT", signal.getType(), signal.getDetails());
}
for (DDoSDefenseCoordinator.DDoSIncidentSummary incident : ddosDefenseCoordinator.analyzeTraffic(
sourceIP, destIP, sourcePort, destPort, protocol, packetData)) {
result.addWarning(incident.getType() + ": " + incident.getDetails());
if (!"HIGH".equals(result.getThreatLevel())) {
result.setThreatLevel(incident.getSeverity() >= 85 ? "HIGH" : "MEDIUM");
}
}
if (isFragmentedPacket(packetData)) {
result.setFragmented(true);
handleFragment(sourceIP, packetData, result);
}
updateConnectionState(sourceIP, destIP, protocol, result);
result.setValid(true);
return result;
}
private String detectProtocol(byte[] packetData, int destPort) {
if (destPort == 25565) return "MINECRAFT";
if (destPort == 25575) return "RCON";
if (destPort == 80) return "HTTP";
if (destPort == 443) return "HTTPS";
if (packetData.length >= 20) {
int protocol = packetData[9] & 0xFF;
switch (protocol) {
case 6: return "TCP";
case 17: return "UDP";
case 1: return "ICMP";
}
}
return "UNKNOWN";
}
private boolean isMalformedPacket(byte[] packetData, String protocol) {
if ("TCP".equals(protocol) || "MINECRAFT".equals(protocol) || "RCON".equals(protocol)) {
if (packetData.length < 20) return true;
int headerLength = (packetData[0] & 0x0F) * 4;
if (headerLength < 20) return true;
int dataOffset = headerLength;
if (packetData.length > dataOffset) {
byte flags = packetData[dataOffset];
if ((flags & 0x3F) == 0) return false;
int payloadLength = packetData.length - dataOffset;
if (payloadLength < 0) return true;
}
}
if ("UDP".equals(protocol)) {
if (packetData.length < 8) return true;
}
return false;
}
private boolean isSuspiciousPacket(byte[] packetData, String protocol) {
if (packetData.length > 65535) return true;
if (packetData.length > 1400 && "UDP".equals(protocol)) {
return true;
}
for (int i = 0; i < Math.min(packetData.length, 100); i++) {
if (packetData[i] == 0x00 && i % 10 == 0) {
int zeroCount = 0;
for (int j = i; j < Math.min(i + 10, packetData.length); j++) {
if (packetData[j] == 0x00) zeroCount++;
}
if (zeroCount > 8) return true;
}
}
return false;
}
private boolean isFragmentedPacket(byte[] packetData) {
if (packetData.length < 20) return false;
short flags = (short) ((packetData[6] << 8) | (packetData[7] & 0xFF));
boolean moreFragments = (flags & 0x2000) != 0;
boolean fragmentOffset = (flags & 0x1FFF) != 0;
return moreFragments || fragmentOffset;
}
private void handleFragment(String sourceIP, byte[] packetData, AnalysisResult result) {
String key = sourceIP + "-" + result.getDestIP();
List<PacketFragment> fragments = fragmentBuffers.computeIfAbsent(key, k -> new ArrayList<>());
short identification = (short) ((packetData[4] << 8) | (packetData[5] & 0xFF));
short flags = (short) ((packetData[6] << 8) | (packetData[7] & 0xFF));
short offset = (short) (flags & 0x1FFF);
PacketFragment fragment = new PacketFragment(identification, offset, packetData, System.currentTimeMillis());
fragments.add(fragment);
cleanupOldFragments(fragments);
int totalLength = fragments.stream().mapToInt(f -> f.getData().length).sum();
if (totalLength > MAX_PACKET_SIZE) {
result.addWarning("Fragment buffer overflow prevented");
fragments.clear();
}
}
private void cleanupOldFragments(List<PacketFragment> fragments) {
long now = System.currentTimeMillis();
fragments.removeIf(f -> now - f.getTimestamp() > FRAGMENT_TIMEOUT_MS);
}
private void updateConnectionState(String sourceIP, String destIP, String protocol, AnalysisResult result) {
String key = sourceIP + "-" + destIP;
ConnectionState state = connectionStates.computeIfAbsent(key, k -> new ConnectionState(sourceIP, destIP, protocol));
state.update(result);
if (state.getPacketCount() > 10000) {
result.addWarning("High packet count on connection");
logEvent(sourceIP, destIP, protocol, "HIGH_VOLUME", "Connection high volume warning");
}
long connectionAge = System.currentTimeMillis() - state.getStartTime();
if (connectionAge > 3600000 && state.getPacketCount() < 10) {
result.addWarning("Stale connection detected");
}
}
public Map<String, Object> getStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("totalPacketsAnalyzed", totalPacketsAnalyzed.get());
stats.put("totalMalformedPackets", totalMalformedPackets.get());
stats.put("totalSuspiciousPackets", totalSuspiciousPackets.get());
stats.put("activeConnections", connectionStates.size());
Map<String, ProtocolStatistics> protoStats = new HashMap<>();
for (Map.Entry<String, ProtocolStatistics> entry : protocolStats.entrySet()) {
protoStats.put(entry.getKey(), entry.getValue());
}
stats.put("protocolStats", protoStats);
return stats;
}
public Map<String, ConnectionState> getConnectionStates() {
return new HashMap<>(connectionStates);
}
public List<ProtocolEvent> getRecentEvents(int limit) {
List<ProtocolEvent> events = new ArrayList<>();
int count = 0;
for (ProtocolEvent event : eventLog) {
if (count++ >= limit) break;
events.add(event);
}
return events;
}
private void logEvent(String sourceIP, String destIP, String protocol, String eventType, String details) {
ProtocolEvent event = new ProtocolEvent(
sourceIP, destIP, protocol, eventType, details, LocalDateTime.now()
);
eventLog.offer(event);
if (eventLog.size() > 10000) {
eventLog.poll();
}
}
public static class AnalysisResult {
private String sourceIP;
private String destIP;
private int sourcePort;
private int destPort;
private String protocol;
private boolean valid;
private String reason;
private String threatLevel;
private boolean fragmented;
private List<String> warnings = new ArrayList<>();
private LocalDateTime timestamp;
public String getSourceIP() { return sourceIP; }
public void setSourceIP(String sourceIP) { this.sourceIP = sourceIP; }
public String getDestIP() { return destIP; }
public void setDestIP(String destIP) { this.destIP = destIP; }
public int getSourcePort() { return sourcePort; }
public void setSourcePort(int sourcePort) { this.sourcePort = sourcePort; }
public int getDestPort() { return destPort; }
public void setDestPort(int destPort) { this.destPort = destPort; }
public String getProtocol() { return protocol; }
public void setProtocol(String protocol) { this.protocol = protocol; }
public boolean isValid() { return valid; }
public void setValid(boolean valid) { this.valid = valid; }
public String getReason() { return reason; }
public void setReason(String reason) { this.reason = reason; }
public String getThreatLevel() { return threatLevel; }
public void setThreatLevel(String threatLevel) { this.threatLevel = threatLevel; }
public boolean isFragmented() { return fragmented; }
public void setFragmented(boolean fragmented) { this.fragmented = fragmented; }
public List<String> getWarnings() { return warnings; }
public void addWarning(String warning) { this.warnings.add(warning); }
public LocalDateTime getTimestamp() { return timestamp; }
public void setTimestamp(LocalDateTime timestamp) { this.timestamp = timestamp; }
}
public static class ProtocolStatistics {
private final String protocolName;
private final AtomicLong packetCount = new AtomicLong(0);
private final AtomicLong byteCount = new AtomicLong(0);
private final AtomicLong malformedCount = new AtomicLong(0);
private final AtomicLong suspiciousCount = new AtomicLong(0);
public ProtocolStatistics(String protocolName) {
this.protocolName = protocolName;
}
public void incrementPacketCount() { packetCount.incrementAndGet(); }
public void addBytes(int bytes) { byteCount.addAndGet(bytes); }
public void incrementMalformedCount() { malformedCount.incrementAndGet(); }
public void incrementSuspiciousCount() { suspiciousCount.incrementAndGet(); }
public String getProtocolName() { return protocolName; }
public long getPacketCount() { return packetCount.get(); }
public long getByteCount() { return byteCount.get(); }
public long getMalformedCount() { return malformedCount.get(); }
public long getSuspiciousCount() { return suspiciousCount.get(); }
}
public static class ConnectionState {
private final String sourceIP;
private final String destIP;
private final String protocol;
private final long startTime;
private volatile long lastPacketTime;
private volatile long packetCount;
private volatile long totalBytes;
private volatile String currentState;
public ConnectionState(String sourceIP, String destIP, String protocol) {
this.sourceIP = sourceIP;
this.destIP = destIP;
this.protocol = protocol;
this.startTime = System.currentTimeMillis();
this.lastPacketTime = startTime;
this.packetCount = 0;
this.totalBytes = 0;
this.currentState = "ESTABLISHED";
}
public synchronized void update(AnalysisResult result) {
lastPacketTime = System.currentTimeMillis();
packetCount++;
if (!result.isValid()) {
currentState = "ERROR";
} else if ("HIGH".equals(result.getThreatLevel())) {
currentState = "THREAT";
}
}
public String getSourceIP() { return sourceIP; }
public String getDestIP() { return destIP; }
public String getProtocol() { return protocol; }
public long getStartTime() { return startTime; }
public long getLastPacketTime() { return lastPacketTime; }
public long getPacketCount() { return packetCount; }
public long getTotalBytes() { return totalBytes; }
public String getCurrentState() { return currentState; }
}
public static class PacketFragment {
private final short identification;
private final short offset;
private final byte[] data;
private final long timestamp;
public PacketFragment(short identification, short offset, byte[] data, long timestamp) {
this.identification = identification;
this.offset = offset;
this.data = data;
this.timestamp = timestamp;
}
public short getIdentification() { return identification; }
public short getOffset() { return offset; }
public byte[] getData() { return data; }
public long getTimestamp() { return timestamp; }
}
public static class ProtocolEvent {
private final String sourceIP;
private final String destIP;
private final String protocol;
private final String eventType;
private final String details;
private final LocalDateTime timestamp;
public ProtocolEvent(String sourceIP, String destIP, String protocol,
String eventType, String details, LocalDateTime timestamp) {
this.sourceIP = sourceIP;
this.destIP = destIP;
this.protocol = protocol;
this.eventType = eventType;
this.details = details;
this.timestamp = timestamp;
}
public String getSourceIP() { return sourceIP; }
public String getDestIP() { return destIP; }
public String getProtocol() { return protocol; }
public String getEventType() { return eventType; }
public String getDetails() { return details; }
public LocalDateTime getTimestamp() { return timestamp; }
}
}
@@ -0,0 +1,194 @@
package com.aluer.security;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.security.MessageDigest;
@Service
public class RateLimitService {
private final Map<String, RateLimitRule> rules = new ConcurrentHashMap<>();
private final Map<String, List<Long>> requestTimestamps = new ConcurrentHashMap<>();
private final Map<String, AtomicInteger> requestCounts = new ConcurrentHashMap<>();
private final Map<String, RateLimitStats> stats = new ConcurrentHashMap<>();
private final Queue<RateLimitEvent> events = new ConcurrentLinkedQueue<>();
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
private static final int DEFAULT_MAX_REQUESTS = 100;
private static final long DEFAULT_WINDOW_MS = 60000;
private static final long BAN_DURATION = 300000;
public RateLimitService() {
initializeDefaultRules();
startCleanupTask();
}
private void initializeDefaultRules() {
addRule("api", DEFAULT_MAX_REQUESTS, DEFAULT_WINDOW_MS, "API requests");
addRule("login", 5, 60000, "Login attempts");
addRule("chat", 10, 5000, "Chat messages");
addRule("command", 30, 60000, "Commands");
addRule("file_upload", 5, 60000, "File uploads");
}
public void addRule(String name, int maxRequests, long windowMs, String description) {
RateLimitRule rule = new RateLimitRule(name, maxRequests, windowMs, description);
rules.put(name, rule);
}
public boolean checkRateLimit(String identifier, String ruleName) {
RateLimitRule rule = rules.get(ruleName);
if (rule == null) {
rule = rules.get("api");
}
if (rule == null) {
return true;
}
final RateLimitRule finalRule = rule;
String key = identifier + ":" + ruleName;
List<Long> timestamps = requestTimestamps.computeIfAbsent(key, k -> new CopyOnWriteArrayList<>());
long now = System.currentTimeMillis();
timestamps.removeIf(t -> now - t > finalRule.windowMs);
if (timestamps.size() >= finalRule.maxRequests) {
recordRejection(identifier, ruleName, "Rate limit exceeded");
return false;
}
timestamps.add(now);
recordRequest(identifier, ruleName);
return true;
}
public void recordRejection(String identifier, String ruleName, String reason) {
RateLimitStats stat = stats.computeIfAbsent(identifier, k -> new RateLimitStats(identifier));
stat.rejections.incrementAndGet();
RateLimitEvent event = new RateLimitEvent(identifier, ruleName, reason, false, System.currentTimeMillis());
events.offer(event);
while (events.size() > 1000) {
events.poll();
}
}
public void recordRequest(String identifier, String ruleName) {
RateLimitStats stat = stats.computeIfAbsent(identifier, k -> new RateLimitStats(identifier));
stat.requests.incrementAndGet();
AtomicInteger count = requestCounts.computeIfAbsent(identifier, k -> new AtomicInteger(0));
count.incrementAndGet();
}
public void resetLimits(String identifier) {
String prefix = identifier + ":";
requestTimestamps.keySet().removeIf(k -> k.startsWith(prefix));
stats.remove(identifier);
requestCounts.remove(identifier);
}
public RateLimitStats getStats(String identifier) {
return stats.get(identifier);
}
public Map<String, RateLimitStats> getAllStats() {
return new HashMap<>(stats);
}
public List<RateLimitEvent> getEvents(int limit) {
List<RateLimitEvent> result = new ArrayList<>();
int count = 0;
for (RateLimitEvent event : events) {
if (count++ >= limit) break;
result.add(event);
}
return result;
}
public Collection<RateLimitRule> getRules() {
return rules.values();
}
private void startCleanupTask() {
scheduler.scheduleAtFixedRate(() -> {
long now = System.currentTimeMillis();
for (Map.Entry<String, List<Long>> entry : requestTimestamps.entrySet()) {
List<Long> list = entry.getValue();
String ruleName = entry.getKey().split(":")[1];
RateLimitRule rule = rules.get(ruleName);
if (rule != null) {
list.removeIf(t -> now - t > rule.windowMs);
if (list.isEmpty()) {
requestTimestamps.remove(entry.getKey());
}
}
}
stats.entrySet().removeIf(entry ->
entry.getValue().requests.get() == 0 &&
entry.getValue().rejections.get() == 0);
}, 60, 60, TimeUnit.SECONDS);
}
public Map<String, Object> getStats() {
Map<String, Object> result = new HashMap<>();
result.put("rulesCount", rules.size());
result.put("trackedIdentifiers", stats.size());
result.put("totalRequests", stats.values().stream()
.mapToLong(s -> s.requests.get())
.sum());
result.put("totalRejections", stats.values().stream()
.mapToLong(s -> s.rejections.get())
.sum());
return result;
}
public static class RateLimitRule {
public final String name;
public final int maxRequests;
public final long windowMs;
public final String description;
public RateLimitRule(String name, int maxRequests, long windowMs, String description) {
this.name = name;
this.maxRequests = maxRequests;
this.windowMs = windowMs;
this.description = description;
}
}
public static class RateLimitStats {
public final String identifier;
public final AtomicLong requests = new AtomicLong(0);
public final AtomicLong rejections = new AtomicLong(0);
public RateLimitStats(String identifier) {
this.identifier = identifier;
}
}
public static class RateLimitEvent {
public final String identifier;
public final String ruleName;
public final String reason;
public final boolean allowed;
public final long timestamp;
public RateLimitEvent(String identifier, String ruleName, String reason, boolean allowed, long timestamp) {
this.identifier = identifier;
this.ruleName = ruleName;
this.reason = reason;
this.allowed = allowed;
this.timestamp = timestamp;
}
}
}
@@ -0,0 +1,374 @@
package com.aluer.security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicLong;
import java.time.LocalDateTime;
import java.time.Duration;
import java.time.format.DateTimeFormatter;
import java.util.stream.Collectors;
@Component
public class SIEMService {
private static final Logger logger = LoggerFactory.getLogger(SIEMService.class);
private final Map<String, SecurityEvent> eventDatabase = new ConcurrentHashMap<>();
private final Queue<Alert> alertQueue = new ConcurrentLinkedQueue<>();
private final Map<String, CorrelationRule> correlationRules = new ConcurrentHashMap<>();
private final Map<String, List<SecurityEvent>> eventTimeline = new ConcurrentHashMap<>();
private final AtomicLong totalEvents = new AtomicLong(0);
private final AtomicLong totalAlerts = new AtomicLong(0);
private final Map<String, AtomicLong> eventTypeCounts = new ConcurrentHashMap<>();
private static final int MAX_EVENTS = 100000;
private static final int ALERT_THRESHOLD = 10;
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public SIEMService() {
initializeCorrelationRules();
logger.info("SIEM Service initialized");
}
private void initializeCorrelationRules() {
addCorrelationRule("BRUTE_FORCE_ATTACK",
Arrays.asList("LOGIN_FAILED", "LOGIN_FAILED", "LOGIN_FAILED"),
"在短时间内多次登录失败",
3, 300);
addCorrelationRule("DDOS_DETECTED",
Arrays.asList("HIGH_CONNECTION", "HIGH_CONNECTION", "HIGH_CONNECTION", "HIGH_CONNECTION"),
"检测到DDoS攻击特征",
4, 60);
addCorrelationRule("DATA_EXFILTRATION",
Arrays.asList("LARGE_UPLOAD", "UNUSUAL_ACCESS", "LARGE_UPLOAD"),
"可能的数据外泄",
3, 600);
addCorrelationRule("PRIVILEGE_ESCALATION",
Arrays.asList("ADMIN_LOGIN", "USER_CREATED", "PERMISSION_CHANGED"),
"权限提升攻击",
3, 300);
addCorrelationRule("PERSISTENT_THREAT",
Arrays.asList("SUSPICIOUS_PROCESS", "SCHEDULED_TASK", "STARTUP_ITEM"),
"可能存在持久性威胁",
3, 3600);
addCorrelationRule("LATERAL_MOVEMENT",
Arrays.asList("NEW_SERVICE", "PORT_OPEN", "REMOTE_ACCESS"),
"横向移动检测",
3, 600);
logger.info("Initialized {} correlation rules", correlationRules.size());
}
public void addCorrelationRule(String name, List<String> sequence, String description, int minMatches, int timeWindowSeconds) {
CorrelationRule rule = new CorrelationRule(name, sequence, description, minMatches, timeWindowSeconds);
correlationRules.put(name, rule);
logger.info("Added correlation rule: {}", name);
}
public void logEvent(String source, String eventType, String severity, String description, Map<String, Object> metadata) {
String eventId = UUID.randomUUID().toString();
SecurityEvent event = new SecurityEvent(eventId, source, eventType, severity, description, metadata, LocalDateTime.now());
eventDatabase.put(eventId, event);
totalEvents.incrementAndGet();
eventTypeCounts.computeIfAbsent(eventType, k -> new AtomicLong(0)).incrementAndGet();
eventTimeline.computeIfAbsent(source, k -> new ArrayList<>()).add(event);
cleanupOldEvents();
checkCorrelationRules(event);
logger.debug("Logged security event: {} [{}]", eventType, severity);
}
public void logSimpleEvent(String source, String eventType, String severity, String description) {
logEvent(source, eventType, severity, description, new HashMap<>());
}
private void checkCorrelationRules(SecurityEvent event) {
for (CorrelationRule rule : correlationRules.values()) {
if (!rule.isEnabled()) continue;
List<SecurityEvent> recentEvents = eventTimeline.get(event.getSource());
if (recentEvents == null || recentEvents.size() < rule.getMinMatches()) continue;
List<String> recentTypes = recentEvents.stream()
.map(SecurityEvent::getEventType)
.collect(Collectors.toList());
if (rule.matchesSequence(recentTypes)) {
triggerAlert(rule.getName(), rule.getDescription(), "HIGH", event);
}
}
}
public void triggerAlert(String ruleName, String description, String severity, SecurityEvent relatedEvent) {
String alertId = UUID.randomUUID().toString();
Alert alert = new Alert(alertId, ruleName, description, severity, relatedEvent, LocalDateTime.now());
alertQueue.offer(alert);
totalAlerts.incrementAndGet();
logger.warn("ALERT: {} - {}", ruleName, description);
}
public List<SecurityEvent> queryEvents(EventQuery query) {
return eventDatabase.values().stream()
.filter(e -> query.getEventType() == null || e.getEventType().equals(query.getEventType()))
.filter(e -> query.getSeverity() == null || e.getSeverity().equals(query.getSeverity()))
.filter(e -> query.getSource() == null || e.getSource().contains(query.getSource()))
.filter(e -> query.getStartTime() == null || e.getTimestamp().isAfter(query.getStartTime()))
.filter(e -> query.getEndTime() == null || e.getTimestamp().isBefore(query.getEndTime()))
.sorted((a, b) -> b.getTimestamp().compareTo(a.getTimestamp()))
.limit(query.getLimit())
.collect(Collectors.toList());
}
public Map<String, Object> getDashboardData() {
Map<String, Object> data = new HashMap<>();
data.put("totalEvents", totalEvents.get());
data.put("totalAlerts", totalAlerts.get());
Map<String, Long> typeCounts = new HashMap<>();
for (Map.Entry<String, AtomicLong> entry : eventTypeCounts.entrySet()) {
typeCounts.put(entry.getKey(), entry.getValue().get());
}
data.put("eventTypeCounts", typeCounts);
Map<String, Long> severityCounts = new HashMap<>();
severityCounts.put("CRITICAL", eventDatabase.values().stream().filter(e -> "CRITICAL".equals(e.getSeverity())).count());
severityCounts.put("HIGH", eventDatabase.values().stream().filter(e -> "HIGH".equals(e.getSeverity())).count());
severityCounts.put("MEDIUM", eventDatabase.values().stream().filter(e -> "MEDIUM".equals(e.getSeverity())).count());
severityCounts.put("LOW", eventDatabase.values().stream().filter(e -> "LOW".equals(e.getSeverity())).count());
data.put("severityCounts", severityCounts);
LocalDateTime oneHourAgo = LocalDateTime.now().minusHours(1);
long recentEvents = eventDatabase.values().stream()
.filter(e -> e.getTimestamp().isAfter(oneHourAgo))
.count();
data.put("eventsLastHour", recentEvents);
List<Alert> recentAlerts = alertQueue.stream()
.sorted((a, b) -> b.getTimestamp().compareTo(a.getTimestamp()))
.limit(10)
.collect(Collectors.toList());
data.put("recentAlerts", recentAlerts);
return data;
}
public List<Alert> getAlerts(String severity, int limit) {
return alertQueue.stream()
.filter(a -> severity == null || a.getSeverity().equals(severity))
.sorted((a, b) -> b.getTimestamp().compareTo(a.getTimestamp()))
.limit(limit)
.collect(Collectors.toList());
}
public Map<String, Object> getThreatAnalysis() {
Map<String, Object> analysis = new HashMap<>();
Map<String, Long> sourceCounts = eventDatabase.values().stream()
.collect(Collectors.groupingBy(SecurityEvent::getSource, Collectors.counting()));
List<Map.Entry<String, Long>> topSources = sourceCounts.entrySet().stream()
.sorted(Map.Entry.<String, Long>comparingByValue().reversed())
.limit(10)
.collect(Collectors.toList());
analysis.put("topEventSources", topSources);
Map<String, Long> eventTypeAnalysis = eventDatabase.values().stream()
.collect(Collectors.groupingBy(SecurityEvent::getEventType, Collectors.counting()));
List<Map.Entry<String, Long>> topEventTypes = eventTypeAnalysis.entrySet().stream()
.sorted(Map.Entry.<String, Long>comparingByValue().reversed())
.limit(10)
.collect(Collectors.toList());
analysis.put("topEventTypes", topEventTypes);
Map<String, Long> attackPatterns = new HashMap<>();
long bruteForce = eventTypeCounts.getOrDefault("LOGIN_FAILED", new AtomicLong(0)).get();
attackPatterns.put("bruteForce", bruteForce);
long ddos = eventTypeCounts.getOrDefault("HIGH_CONNECTION", new AtomicLong(0)).get();
attackPatterns.put("ddos", ddos);
long sqlInjection = eventTypeCounts.getOrDefault("SQL_INJECTION", new AtomicLong(0)).get();
attackPatterns.put("sqlInjection", sqlInjection);
analysis.put("attackPatterns", attackPatterns);
return analysis;
}
private void cleanupOldEvents() {
if (eventDatabase.size() > MAX_EVENTS) {
List<SecurityEvent> sortedEvents = eventDatabase.values().stream()
.sorted((a, b) -> a.getTimestamp().compareTo(b.getTimestamp()))
.collect(Collectors.toList());
int toRemove = eventDatabase.size() - (MAX_EVENTS / 2);
for (int i = 0; i < toRemove && i < sortedEvents.size(); i++) {
eventDatabase.remove(sortedEvents.get(i).getEventId());
}
logger.info("Cleaned up old events, remaining: {}", eventDatabase.size());
}
}
public void enableRule(String ruleName) {
CorrelationRule rule = correlationRules.get(ruleName);
if (rule != null) {
rule.setEnabled(true);
logger.info("Enabled correlation rule: {}", ruleName);
}
}
public void disableRule(String ruleName) {
CorrelationRule rule = correlationRules.get(ruleName);
if (rule != null) {
rule.setEnabled(false);
logger.info("Disabled correlation rule: {}", ruleName);
}
}
public Map<String, Object> getStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("totalEvents", totalEvents.get());
stats.put("totalAlerts", totalAlerts.get());
stats.put("activeEvents", eventDatabase.size());
stats.put("correlationRules", correlationRules.size());
return stats;
}
public static class SecurityEvent {
private final String eventId;
private final String source;
private final String eventType;
private final String severity;
private final String description;
private final Map<String, Object> metadata;
private final LocalDateTime timestamp;
public SecurityEvent(String eventId, String source, String eventType, String severity,
String description, Map<String, Object> metadata, LocalDateTime timestamp) {
this.eventId = eventId;
this.source = source;
this.eventType = eventType;
this.severity = severity;
this.description = description;
this.metadata = metadata;
this.timestamp = timestamp;
}
public String getEventId() { return eventId; }
public String getSource() { return source; }
public String getEventType() { return eventType; }
public String getSeverity() { return severity; }
public String getDescription() { return description; }
public Map<String, Object> getMetadata() { return metadata; }
public LocalDateTime getTimestamp() { return timestamp; }
}
public static class Alert {
private final String alertId;
private final String ruleName;
private final String description;
private final String severity;
private final SecurityEvent relatedEvent;
private final LocalDateTime timestamp;
public Alert(String alertId, String ruleName, String description, String severity,
SecurityEvent relatedEvent, LocalDateTime timestamp) {
this.alertId = alertId;
this.ruleName = ruleName;
this.description = description;
this.severity = severity;
this.relatedEvent = relatedEvent;
this.timestamp = timestamp;
}
public String getAlertId() { return alertId; }
public String getRuleName() { return ruleName; }
public String getDescription() { return description; }
public String getSeverity() { return severity; }
public SecurityEvent getRelatedEvent() { return relatedEvent; }
public LocalDateTime getTimestamp() { return timestamp; }
}
public static class CorrelationRule {
private final String name;
private final List<String> sequence;
private final String description;
private final int minMatches;
private final int timeWindowSeconds;
private volatile boolean enabled = true;
public CorrelationRule(String name, List<String> sequence, String description, int minMatches, int timeWindowSeconds) {
this.name = name;
this.sequence = sequence;
this.description = description;
this.minMatches = minMatches;
this.timeWindowSeconds = timeWindowSeconds;
}
public boolean matchesSequence(List<String> eventTypes) {
if (eventTypes.size() < minMatches) return false;
int matches = 0;
for (int i = 0; i <= eventTypes.size() - sequence.size(); i++) {
boolean match = true;
for (int j = 0; j < sequence.size(); j++) {
if (!eventTypes.get(i + j).equals(sequence.get(j))) {
match = false;
break;
}
}
if (match) return true;
}
return false;
}
public String getName() { return name; }
public List<String> getSequence() { return sequence; }
public String getDescription() { return description; }
public int getMinMatches() { return minMatches; }
public int getTimeWindowSeconds() { return timeWindowSeconds; }
public boolean isEnabled() { return enabled; }
public void setEnabled(boolean enabled) { this.enabled = enabled; }
}
public static class EventQuery {
private String eventType;
private String severity;
private String source;
private LocalDateTime startTime;
private LocalDateTime endTime;
private int limit = 100;
public String getEventType() { return eventType; }
public void setEventType(String eventType) { this.eventType = eventType; }
public String getSeverity() { return severity; }
public void setSeverity(String severity) { this.severity = severity; }
public String getSource() { return source; }
public void setSource(String source) { this.source = source; }
public LocalDateTime getStartTime() { return startTime; }
public void setStartTime(LocalDateTime startTime) { this.startTime = startTime; }
public LocalDateTime getEndTime() { return endTime; }
public void setEndTime(LocalDateTime endTime) { this.endTime = endTime; }
public int getLimit() { return limit; }
public void setLimit(int limit) { this.limit = limit; }
}
}
@@ -0,0 +1,187 @@
package com.aluer.security;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
@Service
public class SSLMonitorService {
private final Map<String, SSLSession> sslSessions = new ConcurrentHashMap<>();
private final Queue<SSLAlert> alerts = new ConcurrentLinkedQueue<>();
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
private static final long SESSION_TIMEOUT = 60000;
private static final int MAX_CERTIFICATES = 1000;
private final AtomicLong totalHandshakes = new AtomicLong(0);
private final AtomicLong failedHandshakes = new AtomicLong(0);
public SSLMonitorService() {
startMonitoringTask();
}
public boolean recordHandshake(String ip, boolean success, String details) {
totalHandshakes.incrementAndGet();
if (!success) {
failedHandshakes.incrementAndGet();
addAlert(ip, "HANDSHAKE_FAILED", details);
return false;
}
SSLSession session = sslSessions.computeIfAbsent(ip, k -> new SSLSession(ip));
session.recordHandshake(success);
return true;
}
public void recordCertificate(String ip, String certInfo) {
SSLSession session = sslSessions.get(ip);
if (session != null) {
session.addCertificate(certInfo);
}
}
public void recordCipherSuite(String ip, String cipher) {
SSLSession session = sslSessions.get(ip);
if (session != null) {
session.setCipherSuite(cipher);
}
}
public void recordProtocolVersion(String ip, String version) {
SSLSession session = sslSessions.get(ip);
if (session != null) {
session.setProtocolVersion(version);
}
}
public boolean isWeakCipher(String ip) {
SSLSession session = sslSessions.get(ip);
if (session == null || session.cipherSuite == null) {
return false;
}
return isWeakCipherSuite(session.cipherSuite);
}
private boolean isWeakCipherSuite(String cipher) {
String[] weakCiphers = {"SSL", "TLSv1.0", "TLSv1.1", "3DES", "RC4", "MD5"};
for (String weak : weakCiphers) {
if (cipher.toUpperCase().contains(weak)) {
return true;
}
}
return false;
}
public boolean isOutdatedProtocol(String ip) {
SSLSession session = sslSessions.get(ip);
if (session == null || session.protocolVersion == null) {
return false;
}
return session.protocolVersion.contains("1.0") || session.protocolVersion.contains("1.1");
}
public SSLSession getSession(String ip) {
return sslSessions.get(ip);
}
public Collection<SSLSession> getAllSessions() {
return sslSessions.values();
}
public void addAlert(String ip, String type, String details) {
SSLAlert alert = new SSLAlert(ip, type, details, System.currentTimeMillis());
alerts.offer(alert);
while (alerts.size() > 500) {
alerts.poll();
}
}
public List<SSLAlert> getAlerts(int limit) {
List<SSLAlert> result = new ArrayList<>();
int count = 0;
for (SSLAlert alert : alerts) {
if (count++ >= limit) break;
result.add(alert);
}
return result;
}
public Map<String, Object> getStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("activeSessions", sslSessions.size());
stats.put("totalHandshakes", totalHandshakes.get());
stats.put("failedHandshakes", failedHandshakes.get());
return stats;
}
private void startMonitoringTask() {
scheduler.scheduleAtFixedRate(() -> {
long now = System.currentTimeMillis();
sslSessions.entrySet().removeIf(entry ->
now - entry.getValue().lastActivity > SESSION_TIMEOUT);
}, 30, 30, TimeUnit.SECONDS);
}
public static class SSLSession {
private final String ip;
private final List<String> certificates = new ArrayList<>();
private volatile String cipherSuite;
private volatile String protocolVersion;
private volatile long handshakeCount = 0;
private volatile long failedCount = 0;
private volatile long lastActivity;
public SSLSession(String ip) {
this.ip = ip;
this.lastActivity = System.currentTimeMillis();
}
public void recordHandshake(boolean success) {
handshakeCount++;
if (!success) {
failedCount++;
}
lastActivity = System.currentTimeMillis();
}
public void addCertificate(String certInfo) {
certificates.add(certInfo);
if (certificates.size() > MAX_CERTIFICATES) {
certificates.remove(0);
}
}
public String getIp() { return ip; }
public String getCipherSuite() { return cipherSuite; }
public void setCipherSuite(String cipherSuite) { this.cipherSuite = cipherSuite; }
public String getProtocolVersion() { return protocolVersion; }
public void setProtocolVersion(String protocolVersion) { this.protocolVersion = protocolVersion; }
public long getHandshakeCount() { return handshakeCount; }
public long getFailedCount() { return failedCount; }
}
public static class SSLAlert {
private final String ip;
private final String type;
private final String details;
private final long timestamp;
public SSLAlert(String ip, String type, String details, long timestamp) {
this.ip = ip;
this.type = type;
this.details = details;
this.timestamp = timestamp;
}
public String getIp() { return ip; }
public String getType() { return type; }
public String getDetails() { return details; }
public long getTimestamp() { return timestamp; }
}
}
@@ -0,0 +1,295 @@
package com.aluer.security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicLong;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Component
public class SSLTLSCertificateService {
private static final Logger logger = LoggerFactory.getLogger(SSLTLSCertificateService.class);
private final Map<String, CertificateInfo> certificates = new ConcurrentHashMap<>();
private final Map<String, CertificateChain> certificateChains = new ConcurrentHashMap<>();
private final Queue<CertificateAlert> alertQueue = new ConcurrentLinkedQueue<>();
private final Map<String, SSLConnectionStats> connectionStats = new ConcurrentHashMap<>();
private final AtomicLong totalConnections = new AtomicLong(0);
private final AtomicLong totalHandshakes = new AtomicLong(0);
private final AtomicLong failedHandshakes = new AtomicLong(0);
private static final int CERTIFICATE_VALIDITY_DAYS = 365;
private static final int RENEWAL_WARNING_DAYS = 30;
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public SSLTLSCertificateService() {
initializeDefaultCertificates();
logger.info("SSL/TLS Certificate Service initialized");
}
private void initializeDefaultCertificates() {
addCertificate("minecraft-server", "CN=mc.example.com, O=Example Server, C=US",
generateExpiryDate(365), "RSA", 2048, "SHA256withRSA");
addCertificate("rcon-server", "CN=rcon.example.com, O=Example Server, C=US",
generateExpiryDate(180), "RSA", 2048, "SHA256withRSA");
logger.info("Initialized {} default certificates", certificates.size());
}
private LocalDateTime generateExpiryDate(int days) {
return LocalDateTime.now().plusDays(days);
}
public void addCertificate(String name, String subject, LocalDateTime expiry,
String keyAlgorithm, int keySize, String signatureAlgorithm) {
CertificateInfo cert = new CertificateInfo(name, subject, expiry, keyAlgorithm, keySize, signatureAlgorithm);
certificates.put(name, cert);
CertificateChain chain = new CertificateChain(name);
chain.addCertificate(cert);
certificateChains.put(name, chain);
logger.info("Added certificate: {} (expires: {})", name, expiry);
}
public CertificateInfo getCertificate(String name) {
return certificates.get(name);
}
public List<CertificateInfo> getExpiringCertificates(int daysThreshold) {
List<CertificateInfo> expiring = new ArrayList<>();
LocalDateTime threshold = LocalDateTime.now().plusDays(daysThreshold);
for (CertificateInfo cert : certificates.values()) {
if (cert.getExpiryDate().isBefore(threshold)) {
expiring.add(cert);
}
}
return expiring;
}
public Map<String, Object> analyzeCertificate(String name) {
Map<String, Object> analysis = new HashMap<>();
CertificateInfo cert = certificates.get(name);
if (cert == null) {
analysis.put("error", "Certificate not found");
return analysis;
}
analysis.put("name", cert.getName());
analysis.put("subject", cert.getSubject());
analysis.put("expiryDate", cert.getExpiryDate());
analysis.put("daysUntilExpiry", cert.getDaysUntilExpiry());
boolean needsRenewal = cert.getDaysUntilExpiry() < RENEWAL_WARNING_DAYS;
analysis.put("needsRenewal", needsRenewal);
boolean isWeakAlgorithm = "MD5".equals(cert.getSignatureAlgorithm()) || "SHA1".equals(cert.getSignatureAlgorithm());
analysis.put("isWeakAlgorithm", isWeakAlgorithm);
boolean isWeakKey = cert.getKeySize() < 2048;
analysis.put("isWeakKey", isWeakKey);
if (isWeakAlgorithm || isWeakKey || needsRenewal) {
analysis.put("securityConcerns", new ArrayList<String>());
}
CertificateChain chain = certificateChains.get(name);
if (chain != null) {
analysis.put("chainLength", chain.getChainLength());
analysis.put("chainValid", chain.isChainValid());
}
return analysis;
}
public void recordHandshake(String serverName, boolean success, String error) {
totalHandshakes.incrementAndGet();
if (!success) {
failedHandshakes.incrementAndGet();
}
SSLConnectionStats stats = connectionStats.computeIfAbsent(serverName, k -> new SSLConnectionStats(serverName));
if (success) {
stats.incrementSuccessfulHandshakes();
} else {
stats.incrementFailedHandshakes();
}
logger.debug("SSL handshake for {}: {}", serverName, success ? "success" : "failed");
}
public void recordConnection(String sourceIP, String destIP, String protocol, boolean encrypted) {
totalConnections.incrementAndGet();
SSLConnectionStats stats = connectionStats.computeIfAbsent(destIP, k -> new SSLConnectionStats(destIP));
stats.incrementConnectionCount();
if (encrypted) {
stats.incrementEncryptedConnections();
}
}
public Map<String, Object> getStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("totalConnections", totalConnections.get());
stats.put("totalHandshakes", totalHandshakes.get());
stats.put("failedHandshakes", failedHandshakes.get());
stats.put("certificatesLoaded", certificates.size());
stats.put("connectionStats", connectionStats.size());
long successRate = totalHandshakes.get() > 0 ?
(totalHandshakes.get() - failedHandshakes.get()) * 100 / totalHandshakes.get() : 0;
stats.put("handshakeSuccessRate", successRate + "%");
return stats;
}
public List<CertificateAlert> getAlerts(int limit) {
List<CertificateAlert> alerts = new ArrayList<>();
int count = 0;
for (CertificateAlert alert : alertQueue) {
if (count++ >= limit) break;
alerts.add(alert);
}
return alerts;
}
public void checkCertificateExpiration() {
for (CertificateInfo cert : certificates.values()) {
int daysUntilExpiry = cert.getDaysUntilExpiry();
if (daysUntilExpiry <= 0) {
triggerAlert(cert.getName(), "EXPIRED", "Certificate has expired");
} else if (daysUntilExpiry <= 7) {
triggerAlert(cert.getName(), "CRITICAL", "Certificate expires in " + daysUntilExpiry + " days");
} else if (daysUntilExpiry <= 30) {
triggerAlert(cert.getName(), "WARNING", "Certificate expires in " + daysUntilExpiry + " days");
}
}
}
private void triggerAlert(String certName, String severity, String message) {
CertificateAlert alert = new CertificateAlert(certName, severity, message, LocalDateTime.now());
alertQueue.offer(alert);
if (alertQueue.size() > 100) {
alertQueue.poll();
}
logger.warn("Certificate Alert [{}]: {} - {}", severity, certName, message);
}
public Map<String, CertificateInfo> getAllCertificates() {
return new HashMap<>(certificates);
}
public static class CertificateInfo {
private final String name;
private final String subject;
private final LocalDateTime expiryDate;
private final String keyAlgorithm;
private final int keySize;
private final String signatureAlgorithm;
public CertificateInfo(String name, String subject, LocalDateTime expiryDate,
String keyAlgorithm, int keySize, String signatureAlgorithm) {
this.name = name;
this.subject = subject;
this.expiryDate = expiryDate;
this.keyAlgorithm = keyAlgorithm;
this.keySize = keySize;
this.signatureAlgorithm = signatureAlgorithm;
}
public int getDaysUntilExpiry() {
return (int) java.time.Duration.between(LocalDateTime.now(), expiryDate).toDays();
}
public String getName() { return name; }
public String getSubject() { return subject; }
public LocalDateTime getExpiryDate() { return expiryDate; }
public String getKeyAlgorithm() { return keyAlgorithm; }
public int getKeySize() { return keySize; }
public String getSignatureAlgorithm() { return signatureAlgorithm; }
}
public static class CertificateChain {
private final String serverName;
private final List<CertificateInfo> certificates = new ArrayList<>();
private volatile boolean chainValid = true;
public CertificateChain(String serverName) {
this.serverName = serverName;
}
public void addCertificate(CertificateInfo cert) {
certificates.add(cert);
}
public boolean isChainValid() {
return chainValid;
}
public void setChainValid(boolean valid) {
this.chainValid = valid;
}
public int getChainLength() {
return certificates.size();
}
public String getServerName() { return serverName; }
public List<CertificateInfo> getCertificates() { return certificates; }
}
public static class SSLConnectionStats {
private final String serverName;
private final AtomicLong connectionCount = new AtomicLong(0);
private final AtomicLong encryptedConnections = new AtomicLong(0);
private final AtomicLong successfulHandshakes = new AtomicLong(0);
private final AtomicLong failedHandshakes = new AtomicLong(0);
public SSLConnectionStats(String serverName) {
this.serverName = serverName;
}
public void incrementConnectionCount() { connectionCount.incrementAndGet(); }
public void incrementEncryptedConnections() { encryptedConnections.incrementAndGet(); }
public void incrementSuccessfulHandshakes() { successfulHandshakes.incrementAndGet(); }
public void incrementFailedHandshakes() { failedHandshakes.incrementAndGet(); }
public String getServerName() { return serverName; }
public long getConnectionCount() { return connectionCount.get(); }
public long getEncryptedConnections() { return encryptedConnections.get(); }
public long getSuccessfulHandshakes() { return successfulHandshakes.get(); }
public long getFailedHandshakes() { return failedHandshakes.get(); }
}
public static class CertificateAlert {
private final String certificateName;
private final String severity;
private final String message;
private final LocalDateTime timestamp;
public CertificateAlert(String certificateName, String severity, String message, LocalDateTime timestamp) {
this.certificateName = certificateName;
this.severity = severity;
this.message = message;
this.timestamp = timestamp;
}
public String getCertificateName() { return certificateName; }
public String getSeverity() { return severity; }
public String getMessage() { return message; }
public LocalDateTime getTimestamp() { return timestamp; }
}
}
@@ -0,0 +1,89 @@
package com.aluer.security;
import com.aluer.config.ServerGuardConfig;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@Component
public class SecurityAutomationScheduler {
private final ServerGuardConfig config;
private final ThreatIntelligenceService threatIntelligenceService;
private final FileIntegrityMonitorService fileIntegrityMonitorService;
private final HostEnforcementService hostEnforcementService;
private final DDoSDefenseCoordinator ddosDefenseCoordinator;
private final HostIntrusionCountermeasureService hostIntrusionCountermeasureService;
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private volatile boolean running = false;
public SecurityAutomationScheduler() {
this(new ServerGuardConfig(), new ThreatIntelligenceService(), new FileIntegrityMonitorService(),
new HostEnforcementService(), new DDoSDefenseCoordinator(), new HostIntrusionCountermeasureService());
}
@Autowired
public SecurityAutomationScheduler(ServerGuardConfig config,
ThreatIntelligenceService threatIntelligenceService,
FileIntegrityMonitorService fileIntegrityMonitorService,
HostEnforcementService hostEnforcementService,
DDoSDefenseCoordinator ddosDefenseCoordinator,
HostIntrusionCountermeasureService hostIntrusionCountermeasureService) {
this.config = config;
this.threatIntelligenceService = threatIntelligenceService;
this.fileIntegrityMonitorService = fileIntegrityMonitorService;
this.hostEnforcementService = hostEnforcementService;
this.ddosDefenseCoordinator = ddosDefenseCoordinator;
this.hostIntrusionCountermeasureService = hostIntrusionCountermeasureService;
}
@PostConstruct
public void start() {
if (running || !config.getSecurity().getAutomation().isEnabled()) {
return;
}
running = true;
int feedMinutes = Math.max(1, config.getSecurity().getAutomation().getFeedRefreshMinutes());
int syncMinutes = Math.max(1, config.getSecurity().getAutomation().getRuleSyncMinutes());
int integrityMinutes = Math.max(1, config.getSecurity().getAutomation().getIntegrityRescanMinutes());
scheduler.scheduleAtFixedRate(threatIntelligenceService::refreshFeeds, 1, feedMinutes, TimeUnit.MINUTES);
scheduler.scheduleAtFixedRate(hostEnforcementService::syncDesiredState, 1, syncMinutes, TimeUnit.MINUTES);
scheduler.scheduleAtFixedRate(fileIntegrityMonitorService::scanNow, 1, integrityMinutes, TimeUnit.MINUTES);
scheduler.scheduleAtFixedRate(hostIntrusionCountermeasureService::runFullScan, 2, integrityMinutes, TimeUnit.MINUTES);
}
public Map<String, Object> runMaintenanceCycle() {
Map<String, Object> cycle = new LinkedHashMap<>();
cycle.put("feeds", threatIntelligenceService.refreshFeeds());
cycle.put("hostRules", hostEnforcementService.syncDesiredState());
cycle.put("integrity", fileIntegrityMonitorService.scanNow());
cycle.put("antiIntrusion", hostIntrusionCountermeasureService.runFullScan());
cycle.put("ddos", ddosDefenseCoordinator.getPosture());
return cycle;
}
public Map<String, Object> getStatus() {
Map<String, Object> status = new LinkedHashMap<>();
status.put("running", running);
status.put("automationEnabled", config.getSecurity().getAutomation().isEnabled());
status.put("feedRefreshMinutes", config.getSecurity().getAutomation().getFeedRefreshMinutes());
status.put("integrityRescanMinutes", config.getSecurity().getAutomation().getIntegrityRescanMinutes());
status.put("ruleSyncMinutes", config.getSecurity().getAutomation().getRuleSyncMinutes());
return status;
}
@PreDestroy
public void shutdown() {
running = false;
scheduler.shutdownNow();
}
}
@@ -0,0 +1,265 @@
package com.aluer.security;
import com.aluer.config.ServerGuardConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Service
public class SecurityBaselineHardeningService {
private static final Pattern INLINE_SECRET_PATTERN = Pattern.compile(
"(?im)^\\s*(api-key|password|secret|token|apiKey):\\s*(?!\\$\\{)([^\\s#]+)"
);
private final ServerGuardConfig config;
private final ConcurrentLinkedDeque<HardeningFinding> findingLog = new ConcurrentLinkedDeque<>();
private final Path applicationConfigPath = Paths.get("src", "main", "resources", "application.yml");
public SecurityBaselineHardeningService() {
this(new ServerGuardConfig());
}
@Autowired
public SecurityBaselineHardeningService(ServerGuardConfig config) {
this.config = config;
}
public HardeningReport assessCurrentBaseline() {
List<HardeningFinding> findings = new ArrayList<>();
scanRuntimeConfiguration(findings);
scanConfigFile(findings);
record(findings);
return new HardeningReport(findings);
}
public List<HardeningFinding> getRecentFindings(int limit) {
List<HardeningFinding> result = new ArrayList<>();
int count = 0;
for (HardeningFinding finding : findingLog) {
if (count++ >= limit) {
break;
}
result.add(finding);
}
result.sort(Comparator.comparingLong(HardeningFinding::getTimestamp).reversed());
return result;
}
public Map<String, Object> getSummary() {
return assessCurrentBaseline().toMap();
}
private void scanRuntimeConfiguration(List<HardeningFinding> findings) {
ServerGuardConfig.RconConfig rcon = config.getMinecraft().getRcon();
if (rcon.isEnabled() && isBlank(rcon.getPassword())) {
findings.add(new HardeningFinding(
"critical",
"RCON",
"RCON 已启用但未配置口令",
"远程控制接口暴露时,空口令会直接放大入侵面。",
"为 RCON 设置强随机密码,并限制来源 IP。"
));
} else if (rcon.isEnabled() && rcon.getPassword().length() < 12) {
findings.add(new HardeningFinding(
"high",
"RCON",
"RCON 口令强度偏弱",
"当前口令长度过短,容易被暴力猜解或撞库命中。",
"将 RCON 口令提升到 16 位以上并只通过环境变量注入。"
));
}
if (!config.getSecurity().getAntiIntrusion().getFileIntegrity().isEnabled()) {
findings.add(new HardeningFinding(
"high",
"INTEGRITY",
"文件完整性监控已关闭",
"插件篡改、脚本替换和 systemd 劫持将更难被发现。",
"启用 file-integrity,并覆盖核心 jar、插件目录和启动脚本。"
));
}
if (!config.getSecurity().getHostEnforcement().isEnabled()) {
findings.add(new HardeningFinding(
"medium",
"HOST_ENFORCEMENT",
"主机侧封禁未启用",
"系统当前只能在应用层做隔离,真正的源地址拦截无法落到主机网络层。",
"启用 host-enforcement,至少保持 dry-run 观察,再逐步切到真实执行。"
));
} else if (config.getSecurity().getHostEnforcement().isDryRun()) {
findings.add(new HardeningFinding(
"low",
"HOST_ENFORCEMENT",
"主机侧封禁仍处于 dry-run",
"当前只生成阻断预览,不会真正下发防火墙规则。",
"验证命令预览无误后,把 dry-run 切换为 false。"
));
}
if (config.getAi().getDeepseek().getAutoExecute().isEnabled()
&& config.getAi().getDeepseek().getAutoExecute().getMinConfidence() < 85) {
findings.add(new HardeningFinding(
"medium",
"AUTONOMY",
"AI 自动执行置信度阈值过低",
"过低阈值会放大误封禁、误踢人和错误白名单切换的概率。",
"将 min-confidence 提升到 85 以上,并保留工作流冷却。"
));
}
if (config.getSecurity().getCloudEdge().isEnabled()
&& (isBlank(config.getSecurity().getCloudEdge().getZoneId())
|| isBlank(config.getSecurity().getCloudEdge().getApiKey()))) {
findings.add(new HardeningFinding(
"high",
"EDGE",
"云边协同已启用但凭据不完整",
"边缘拦截配置不完整会导致自治编排在关键阶段失效。",
"补齐 Cloudflare zone/API 凭据,或显式关闭 cloud-edge。"
));
}
}
private void scanConfigFile(List<HardeningFinding> findings) {
if (!Files.exists(applicationConfigPath)) {
return;
}
try {
String content = Files.readString(applicationConfigPath, StandardCharsets.UTF_8);
Matcher matcher = INLINE_SECRET_PATTERN.matcher(content);
while (matcher.find()) {
String key = matcher.group(1);
String value = matcher.group(2);
if (value != null && !value.isBlank()) {
findings.add(new HardeningFinding(
"critical",
"CONFIG_SECRET",
"配置文件中存在明文敏感项: " + key,
"明文凭据一旦进仓库、日志或备份,泄露面会持续扩大。",
"改为 `${ENV_VAR:}` 形式,并轮换已暴露的真实凭据。"
));
}
}
} catch (IOException ignored) {
}
}
private void record(List<HardeningFinding> findings) {
for (HardeningFinding finding : findings) {
findingLog.offer(finding);
}
while (findingLog.size() > 500) {
findingLog.poll();
}
}
private boolean isBlank(String value) {
return value == null || value.isBlank();
}
public static class HardeningReport {
private final List<HardeningFinding> findings;
private final int criticalCount;
private final int highCount;
private final int mediumCount;
private final int lowCount;
private final int score;
public HardeningReport(List<HardeningFinding> findings) {
this.findings = findings.stream()
.sorted(Comparator.comparing((HardeningFinding finding) -> severityWeight(finding.severity)).reversed())
.toList();
this.criticalCount = (int) this.findings.stream().filter(finding -> "critical".equals(finding.severity)).count();
this.highCount = (int) this.findings.stream().filter(finding -> "high".equals(finding.severity)).count();
this.mediumCount = (int) this.findings.stream().filter(finding -> "medium".equals(finding.severity)).count();
this.lowCount = (int) this.findings.stream().filter(finding -> "low".equals(finding.severity)).count();
this.score = Math.max(0, 100 - (criticalCount * 25 + highCount * 15 + mediumCount * 8 + lowCount * 3));
}
public List<HardeningFinding> getFindings() { return findings; }
public int getCriticalCount() { return criticalCount; }
public int getHighCount() { return highCount; }
public int getMediumCount() { return mediumCount; }
public int getLowCount() { return lowCount; }
public int getScore() { return score; }
public Map<String, Object> toMap() {
Map<String, Object> result = new LinkedHashMap<>();
result.put("score", score);
result.put("exposureLevel", score >= 85 ? "stable" : score >= 65 ? "guarded" : score >= 45 ? "exposed" : "critical");
result.put("critical", criticalCount);
result.put("high", highCount);
result.put("medium", mediumCount);
result.put("low", lowCount);
result.put("findings", findings.stream().limit(6).map(HardeningFinding::toMap).toList());
result.put("recommendations", findings.stream()
.map(HardeningFinding::getRecommendation)
.distinct()
.limit(5)
.toList());
return result;
}
private static int severityWeight(String severity) {
return switch (severity.toLowerCase(Locale.ROOT)) {
case "critical" -> 4;
case "high" -> 3;
case "medium" -> 2;
default -> 1;
};
}
}
public static class HardeningFinding {
private final String severity;
private final String category;
private final String title;
private final String detail;
private final String recommendation;
private final long timestamp;
public HardeningFinding(String severity, String category, String title, String detail, String recommendation) {
this.severity = severity;
this.category = category;
this.title = title;
this.detail = detail;
this.recommendation = recommendation;
this.timestamp = Instant.now().toEpochMilli();
}
public String getSeverity() { return severity; }
public String getCategory() { return category; }
public String getTitle() { return title; }
public String getDetail() { return detail; }
public String getRecommendation() { return recommendation; }
public long getTimestamp() { return timestamp; }
public Map<String, Object> toMap() {
Map<String, Object> result = new LinkedHashMap<>();
result.put("severity", severity);
result.put("category", category);
result.put("title", title);
result.put("detail", detail);
result.put("recommendation", recommendation);
result.put("timestamp", timestamp);
return result;
}
}
}
@@ -0,0 +1,666 @@
package com.aluer.security;
import com.aluer.audit.SecurityAuditService;
import com.aluer.service.RconClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicLong;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Component
public class SecurityOrchestrationService {
private static final Logger logger = LoggerFactory.getLogger(SecurityOrchestrationService.class);
private final HostEnforcementService hostEnforcementService;
private final CloudflareIntegrationService cloudflareIntegrationService;
private final RconClient rconClient;
private final SecurityAuditService securityAuditService;
private final Map<String, SecurityWorkflow> workflows = new ConcurrentHashMap<>();
private final Map<String, OrchestrationTask> activeTasks = new ConcurrentHashMap<>();
private final Queue<OrchestrationEvent> eventLog = new ConcurrentLinkedQueue<>();
private final Map<String, List<SecurityAction>> actionHistory = new ConcurrentHashMap<>();
private final AtomicLong totalWorkflowsExecuted = new AtomicLong(0);
private final AtomicLong successfulWorkflows = new AtomicLong(0);
private final AtomicLong failedWorkflows = new AtomicLong(0);
private volatile boolean enabled = true;
private static final int MAX_HISTORY = 10000;
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public SecurityOrchestrationService() {
this(new HostEnforcementService(), new CloudflareIntegrationService(), null, null);
}
@Autowired
public SecurityOrchestrationService(HostEnforcementService hostEnforcementService,
CloudflareIntegrationService cloudflareIntegrationService,
RconClient rconClient,
SecurityAuditService securityAuditService) {
this.hostEnforcementService = hostEnforcementService;
this.cloudflareIntegrationService = cloudflareIntegrationService;
this.rconClient = rconClient;
this.securityAuditService = securityAuditService;
initializeDefaultWorkflows();
logger.info("Security Orchestration Service initialized");
}
private void initializeDefaultWorkflows() {
addWorkflow("DDOS_MITIGATION", Arrays.asList(
new SecurityAction("DETECT", "threat-detection", "Analyze attack pattern"),
new SecurityAction("BLOCK", "firewall", "Block malicious IPs"),
new SecurityAction("NOTIFY", "alert-system", "Send alert to administrators"),
new SecurityAction("LOG", "audit-log", "Record incident details")
));
addWorkflow("INTRUSION_RESPONSE", Arrays.asList(
new SecurityAction("DETECT", "intrusion-detection", "Identify intrusion"),
new SecurityAction("ISOLATE", "network-isolation", "Isolate affected systems"),
new SecurityAction("COLLECT", "forensics", "Collect evidence"),
new SecurityAction("NOTIFY", "alert-system", "Notify security team"),
new SecurityAction("REMEDIATE", "remediation", "Apply fixes")
));
addWorkflow("DATA_BREACH", Arrays.asList(
new SecurityAction("DETECT", "data-loss-prevention", "Detect data breach"),
new SecurityAction("CONTAIN", "access-control", "Restrict access"),
new SecurityAction("INVESTIGATE", "forensics", "Investigate breach"),
new SecurityAction("NOTIFY", "compliance", "Notify stakeholders"),
new SecurityAction("REMEDIATE", "security-patch", "Apply security patches")
));
addWorkflow("MALWARE_DETECTION", Arrays.asList(
new SecurityAction("SCAN", "antivirus", "Scan for malware"),
new SecurityAction("QUARANTINE", "isolation", "Quarantine infected files"),
new SecurityAction("ANALYZE", "sandbox", "Analyze malware"),
new SecurityAction("REMEDIATE", "clean-tool", "Clean or remove malware")
));
addWorkflow("BRUTE_FORCE_PROTECTION", Arrays.asList(
new SecurityAction("DETECT", "auth-monitor", "Detect brute force"),
new SecurityAction("BLOCK", "rate-limiter", "Block attacker IP"),
new SecurityAction("NOTIFY", "alert-system", "Notify admin"),
new SecurityAction("AUDIT", "log-analysis", "Audit attack attempts")
));
addWorkflow("MC_STATUS_FLOOD_RESPONSE", Arrays.asList(
new SecurityAction("DETECT", "minecraft-status", "Detect status ping flood", true),
new SecurityAction("CORRELATE", "threat-fusion", "Correlate burst sources"),
new SecurityAction("SCORE", "risk-engine", "Score the incident"),
new SecurityAction("LOCAL_BLOCK_OR_RATE_LIMIT", "host-firewall", "Rate limit or block source", true),
new SecurityAction("EDGE_BLOCK_OR_CHALLENGE", "cloud-edge", "Challenge abusive source"),
new SecurityAction("MINECRAFT_DEFENSE_ACTION", "rcon", "Broadcast degraded state"),
new SecurityAction("AUDIT", "audit", "Record the incident"),
new SecurityAction("NOTIFY", "alert-system", "Notify operators")
));
addWorkflow("MC_LOGIN_FLOOD_RESPONSE", Arrays.asList(
new SecurityAction("DETECT", "minecraft-login", "Detect login burst", true),
new SecurityAction("CORRELATE", "identity-correlation", "Correlate bot swarm"),
new SecurityAction("SCORE", "risk-engine", "Score login abuse"),
new SecurityAction("LOCAL_BLOCK_OR_RATE_LIMIT", "host-firewall", "Block or slow source", true),
new SecurityAction("EDGE_BLOCK_OR_CHALLENGE", "cloud-edge", "Challenge edge"),
new SecurityAction("MINECRAFT_DEFENSE_ACTION", "rcon", "Enable temporary whitelist"),
new SecurityAction("AUDIT", "audit", "Record the incident"),
new SecurityAction("NOTIFY", "alert-system", "Notify operators")
));
addWorkflow("MC_BOT_SWARM_RESPONSE", Arrays.asList(
new SecurityAction("DETECT", "bot-swarm", "Detect multi-source swarm", true),
new SecurityAction("CORRELATE", "cluster-analysis", "Correlate source cohorts"),
new SecurityAction("SCORE", "risk-engine", "Score swarm severity"),
new SecurityAction("LOCAL_BLOCK_OR_RATE_LIMIT", "host-firewall", "Block swarm IPs", true),
new SecurityAction("EDGE_BLOCK_OR_CHALLENGE", "cloud-edge", "Challenge or block edge"),
new SecurityAction("MINECRAFT_DEFENSE_ACTION", "rcon", "Reduce access surface"),
new SecurityAction("AUDIT", "audit", "Record bot swarm"),
new SecurityAction("NOTIFY", "alert-system", "Notify operators")
));
addWorkflow("RCON_BRUTE_FORCE_RESPONSE", Arrays.asList(
new SecurityAction("DETECT", "rcon-monitor", "Detect RCON brute force", true),
new SecurityAction("CORRELATE", "credential-abuse", "Correlate repeated failures"),
new SecurityAction("SCORE", "risk-engine", "Score credential attack"),
new SecurityAction("LOCAL_BLOCK_OR_RATE_LIMIT", "host-firewall", "Block attacker", true),
new SecurityAction("EDGE_BLOCK_OR_CHALLENGE", "cloud-edge", "Challenge attacker"),
new SecurityAction("MINECRAFT_DEFENSE_ACTION", "rcon", "Enable whitelist and notify"),
new SecurityAction("AUDIT", "audit", "Record RCON abuse"),
new SecurityAction("NOTIFY", "alert-system", "Notify operators")
));
addWorkflow("L34_DDOS_RESPONSE", Arrays.asList(
new SecurityAction("DETECT", "l34-ddos", "Detect transport flood", true),
new SecurityAction("CORRELATE", "ddos-correlation", "Correlate flood vectors"),
new SecurityAction("SCORE", "risk-engine", "Score ddos"),
new SecurityAction("LOCAL_BLOCK_OR_RATE_LIMIT", "host-firewall", "Rate limit or block", true),
new SecurityAction("EDGE_BLOCK_OR_CHALLENGE", "cloud-edge", "Escalate to edge"),
new SecurityAction("AUDIT", "audit", "Record mitigation"),
new SecurityAction("NOTIFY", "alert-system", "Notify operators")
));
addWorkflow("L7_DDOS_RESPONSE", Arrays.asList(
new SecurityAction("DETECT", "l7-ddos", "Detect application flood", true),
new SecurityAction("CORRELATE", "request-patterns", "Correlate abusive paths"),
new SecurityAction("SCORE", "risk-engine", "Score app flood"),
new SecurityAction("LOCAL_BLOCK_OR_RATE_LIMIT", "host-firewall", "Rate limit clients", true),
new SecurityAction("EDGE_BLOCK_OR_CHALLENGE", "cloud-edge", "Challenge at edge"),
new SecurityAction("AUDIT", "audit", "Record flood"),
new SecurityAction("NOTIFY", "alert-system", "Notify operators")
));
addWorkflow("HOST_INTRUSION_RESPONSE", Arrays.asList(
new SecurityAction("DETECT", "host-edr", "Detect host intrusion", true),
new SecurityAction("CORRELATE", "host-fusion", "Correlate host evidence"),
new SecurityAction("SCORE", "risk-engine", "Score host intrusion"),
new SecurityAction("LOCAL_BLOCK_OR_RATE_LIMIT", "host-firewall", "Block source or isolate host", true),
new SecurityAction("AUDIT", "audit", "Record host intrusion"),
new SecurityAction("NOTIFY", "alert-system", "Notify operators")
));
addWorkflow("PLUGIN_TAMPER_RESPONSE", Arrays.asList(
new SecurityAction("DETECT", "integrity-monitor", "Detect plugin tamper", true),
new SecurityAction("CORRELATE", "artifact-correlation", "Correlate changed artifacts"),
new SecurityAction("SCORE", "risk-engine", "Score tamper impact"),
new SecurityAction("MINECRAFT_DEFENSE_ACTION", "rcon", "Freeze unsafe admin actions"),
new SecurityAction("AUDIT", "audit", "Record tamper event"),
new SecurityAction("NOTIFY", "alert-system", "Notify operators")
));
addWorkflow("COMMAND_ABUSE_RESPONSE", Arrays.asList(
new SecurityAction("DETECT", "command-guard", "Detect dangerous command", true),
new SecurityAction("CORRELATE", "command-history", "Correlate operator activity"),
new SecurityAction("SCORE", "risk-engine", "Score abuse"),
new SecurityAction("LOCAL_BLOCK_OR_RATE_LIMIT", "host-firewall", "Block remote source when applicable"),
new SecurityAction("AUDIT", "audit", "Record command abuse"),
new SecurityAction("NOTIFY", "alert-system", "Notify operators")
));
addWorkflow("VULNERABILITY_PATCH", Arrays.asList(
new SecurityAction("SCAN", "vulnerability-scanner", "Scan for vulnerabilities"),
new SecurityAction("ASSESS", "risk-assessment", "Assess severity"),
new SecurityAction("PRIORITIZE", "patch-management", "Prioritize patches"),
new SecurityAction("APPLY", "patch-manager", "Apply patches"),
new SecurityAction("VERIFY", "validation", "Verify patch effectiveness")
));
addWorkflow("INSIDER_THREAT", Arrays.asList(
new SecurityAction("DETECT", "ueba", "Detect anomalous behavior"),
new SecurityAction("ANALYZE", "behavior-analysis", "Analyze user behavior"),
new SecurityAction("INVESTIGATE", "forensics", "Investigate threat"),
new SecurityAction("CONTAIN", "access-control", "Restrict access if needed"),
new SecurityAction("REPORT", "compliance", "Generate compliance report")
));
logger.info("Initialized {} security workflows", workflows.size());
}
public void addWorkflow(String name, List<SecurityAction> actions) {
SecurityWorkflow workflow = new SecurityWorkflow(name, actions);
workflows.put(name, workflow);
logger.info("Added security workflow: {}", name);
}
public String executeWorkflow(String workflowName, Map<String, Object> context) {
return executeWorkflowDetailed(workflowName, context).getExecutionId();
}
public WorkflowExecutionResult executeWorkflowDetailed(String workflowName, Map<String, Object> context) {
if (!enabled) {
return new WorkflowExecutionResult("", workflowName, "DISABLED", true, new LinkedHashMap<>());
}
SecurityWorkflow workflow = workflows.get(workflowName);
if (workflow == null) {
return new WorkflowExecutionResult("", workflowName, "NOT_FOUND", true, new LinkedHashMap<>());
}
String executionId = UUID.randomUUID().toString();
totalWorkflowsExecuted.incrementAndGet();
OrchestrationTask task = new OrchestrationTask(executionId, workflowName, context);
activeTasks.put(executionId, task);
logger.info("Executing workflow: {} (ID: {})", workflowName, executionId);
for (SecurityAction action : workflow.getActions()) {
try {
boolean success = executeAction(action, context);
task.addActionResult(action.getName(), success);
if (!success && action.isCritical()) {
task.setStatus("FAILED");
failedWorkflows.incrementAndGet();
logEvent(executionId, workflowName, "FAILED", "Critical action failed: " + action.getName());
return new WorkflowExecutionResult(executionId, workflowName, "FAILED", false, new LinkedHashMap<>(task.getActionResults()));
}
logEvent(executionId, workflowName, "ACTION_COMPLETED", "Action: " + action.getName());
} catch (Exception e) {
logger.error("Error executing action {} in workflow {}: {}", action.getName(), workflowName, e.getMessage());
task.addActionResult(action.getName(), false);
if (action.isCritical()) {
task.setStatus("FAILED");
failedWorkflows.incrementAndGet();
return new WorkflowExecutionResult(executionId, workflowName, "FAILED", false, new LinkedHashMap<>(task.getActionResults()));
}
}
}
task.setStatus("COMPLETED");
successfulWorkflows.incrementAndGet();
logEvent(executionId, workflowName, "COMPLETED", "Workflow completed successfully");
return new WorkflowExecutionResult(executionId, workflowName, "COMPLETED", false, new LinkedHashMap<>(task.getActionResults()));
}
private boolean executeAction(SecurityAction action, Map<String, Object> context) {
switch (action.getType()) {
case "DETECT":
return executeDetection(action, context);
case "CORRELATE":
return executeCorrelation(action, context);
case "SCORE":
return executeScore(action, context);
case "BLOCK":
return executeBlocking(action, context);
case "LOCAL_BLOCK_OR_RATE_LIMIT":
return executeLocalBlockOrRateLimit(action, context);
case "NOTIFY":
return executeNotification(action, context);
case "LOG":
return executeLogging(action, context);
case "EDGE_BLOCK_OR_CHALLENGE":
return executeEdgeBlockOrChallenge(action, context);
case "ISOLATE":
return executeIsolation(action, context);
case "COLLECT":
return executeCollection(action, context);
case "INVESTIGATE":
return executeInvestigation(action, context);
case "REMEDIATE":
return executeRemediation(action, context);
case "SCAN":
return executeScan(action, context);
case "QUARANTINE":
return executeQuarantine(action, context);
case "ANALYZE":
return executeAnalysis(action, context);
case "CONTAIN":
return executeContainment(action, context);
case "ASSESS":
return executeAssessment(action, context);
case "PRIORITIZE":
return executePrioritization(action, context);
case "APPLY":
return executeApplication(action, context);
case "VERIFY":
return executeVerification(action, context);
case "REPORT":
return executeReporting(action, context);
case "MINECRAFT_DEFENSE_ACTION":
return executeMinecraftDefenseAction(action, context);
case "AUDIT":
return executeAuditAction(action, context);
default:
logger.warn("Unknown action type: {}", action.getType());
return true;
}
}
private boolean executeDetection(SecurityAction action, Map<String, Object> context) {
logger.info("Executing detection action: {}", action.getName());
context.put("detection-result", "threat-detected");
context.put("detection-time", System.currentTimeMillis());
return true;
}
private boolean executeCorrelation(SecurityAction action, Map<String, Object> context) {
logger.info("Executing correlation action: {}", action.getName());
context.put("correlated", true);
context.put("correlation-source", action.getName());
return true;
}
private boolean executeScore(SecurityAction action, Map<String, Object> context) {
logger.info("Executing score action: {}", action.getName());
int riskScore = ((Number) context.getOrDefault("riskScore", 85)).intValue();
context.put("riskScore", riskScore);
context.put("severity", riskScore >= 90 ? "CRITICAL" : riskScore >= 75 ? "HIGH" : "MEDIUM");
return true;
}
private boolean executeBlocking(SecurityAction action, Map<String, Object> context) {
logger.info("Executing blocking action: {}", action.getName());
String attackerIP = (String) context.get("attacker-ip");
if (attackerIP != null) {
context.put("blocked-ips", attackerIP);
}
return true;
}
private boolean executeLocalBlockOrRateLimit(SecurityAction action, Map<String, Object> context) {
logger.info("Executing local block/rate-limit action: {}", action.getName());
String attackerIP = (String) context.get("attacker-ip");
if (attackerIP == null || attackerIP.isBlank()) {
return true;
}
int riskScore = ((Number) context.getOrDefault("riskScore", 80)).intValue();
if (riskScore >= 90) {
context.put("local-action", hostEnforcementService.blockIp(attackerIP, action.getDescription(), 60));
} else {
context.put("local-action", hostEnforcementService.rateLimitIp(attackerIP, 60, action.getDescription()));
}
return true;
}
private boolean executeNotification(SecurityAction action, Map<String, Object> context) {
logger.info("Executing notification action: {}", action.getName());
context.put("notification-sent", true);
context.put("notification-time", System.currentTimeMillis());
return true;
}
private boolean executeEdgeBlockOrChallenge(SecurityAction action, Map<String, Object> context) {
logger.info("Executing edge block/challenge action: {}", action.getName());
String attackerIP = (String) context.get("attacker-ip");
if (attackerIP == null || attackerIP.isBlank()) {
return true;
}
int riskScore = ((Number) context.getOrDefault("riskScore", 80)).intValue();
if (riskScore >= 90) {
context.put("edge-action", cloudflareIntegrationService.applyBlock(attackerIP, action.getDescription()));
} else {
context.put("edge-action", cloudflareIntegrationService.applyChallenge(attackerIP, action.getDescription()));
}
return true;
}
private boolean executeLogging(SecurityAction action, Map<String, Object> context) {
logger.info("Executing logging action: {}", action.getName());
context.put("logged", true);
return true;
}
private boolean executeIsolation(SecurityAction action, Map<String, Object> context) {
logger.info("Executing isolation action: {}", action.getName());
context.put("isolated", true);
return true;
}
private boolean executeCollection(SecurityAction action, Map<String, Object> context) {
logger.info("Executing collection action: {}", action.getName());
context.put("evidence-collected", true);
return true;
}
private boolean executeInvestigation(SecurityAction action, Map<String, Object> context) {
logger.info("Executing investigation action: {}", action.getName());
context.put("investigation-complete", true);
return true;
}
private boolean executeRemediation(SecurityAction action, Map<String, Object> context) {
logger.info("Executing remediation action: {}", action.getName());
context.put("remediation-complete", true);
return true;
}
private boolean executeScan(SecurityAction action, Map<String, Object> context) {
logger.info("Executing scan action: {}", action.getName());
context.put("scan-complete", true);
return true;
}
private boolean executeQuarantine(SecurityAction action, Map<String, Object> context) {
logger.info("Executing quarantine action: {}", action.getName());
context.put("quarantined", true);
return true;
}
private boolean executeAnalysis(SecurityAction action, Map<String, Object> context) {
logger.info("Executing analysis action: {}", action.getName());
context.put("analysis-complete", true);
return true;
}
private boolean executeContainment(SecurityAction action, Map<String, Object> context) {
logger.info("Executing containment action: {}", action.getName());
context.put("contained", true);
return true;
}
private boolean executeAssessment(SecurityAction action, Map<String, Object> context) {
logger.info("Executing assessment action: {}", action.getName());
context.put("assessment-complete", true);
return true;
}
private boolean executePrioritization(SecurityAction action, Map<String, Object> context) {
logger.info("Executing prioritization action: {}", action.getName());
context.put("prioritized", true);
return true;
}
private boolean executeApplication(SecurityAction action, Map<String, Object> context) {
logger.info("Executing application action: {}", action.getName());
context.put("applied", true);
return true;
}
private boolean executeVerification(SecurityAction action, Map<String, Object> context) {
logger.info("Executing verification action: {}", action.getName());
context.put("verified", true);
return true;
}
private boolean executeReporting(SecurityAction action, Map<String, Object> context) {
logger.info("Executing reporting action: {}", action.getName());
context.put("reported", true);
return true;
}
private boolean executeMinecraftDefenseAction(SecurityAction action, Map<String, Object> context) {
logger.info("Executing Minecraft defense action: {}", action.getName());
if (rconClient == null) {
return true;
}
String workflow = (String) context.getOrDefault("workflow", "");
rconClient.executeCommand("say [Aluer] Security workflow active: " + workflow);
int riskScore = ((Number) context.getOrDefault("riskScore", 80)).intValue();
if (workflow.contains("LOGIN") || workflow.contains("RCON") || riskScore >= 95) {
rconClient.enableWhitelist();
}
context.put("minecraft-defense", "applied");
return true;
}
private boolean executeAuditAction(SecurityAction action, Map<String, Object> context) {
logger.info("Executing audit action: {}", action.getName());
if (securityAuditService != null) {
securityAuditService.logEvent(
"SECURITY_WORKFLOW",
String.valueOf(context.getOrDefault("actor", "system")),
String.valueOf(context.getOrDefault("workflow", "unknown")),
String.valueOf(context.getOrDefault("detection-result", action.getDescription()))
);
}
context.put("audited", true);
return true;
}
public OrchestrationTask getTaskStatus(String taskId) {
return activeTasks.get(taskId);
}
public Map<String, Object> getStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("enabled", enabled);
stats.put("totalWorkflowsExecuted", totalWorkflowsExecuted.get());
stats.put("successfulWorkflows", successfulWorkflows.get());
stats.put("failedWorkflows", failedWorkflows.get());
stats.put("workflowsConfigured", workflows.size());
stats.put("activeTasks", activeTasks.size());
double successRate = totalWorkflowsExecuted.get() > 0 ?
successfulWorkflows.get() * 100.0 / totalWorkflowsExecuted.get() : 0;
stats.put("successRate", String.format("%.2f%%", successRate));
return stats;
}
public Map<String, SecurityWorkflow> getWorkflows() {
return new HashMap<>(workflows);
}
public List<OrchestrationTask> getActiveTasks() {
return new ArrayList<>(activeTasks.values());
}
public List<OrchestrationEvent> getRecentEvents(int limit) {
List<OrchestrationEvent> events = new ArrayList<>();
int count = 0;
for (OrchestrationEvent event : eventLog) {
if (count++ >= limit) break;
events.add(event);
}
return events;
}
private void logEvent(String taskId, String workflowName, String status, String details) {
OrchestrationEvent event = new OrchestrationEvent(taskId, workflowName, status, details, LocalDateTime.now());
eventLog.offer(event);
if (eventLog.size() > 5000) {
eventLog.poll();
}
}
public void enable() {
enabled = true;
logger.info("Security Orchestration enabled");
}
public void disable() {
enabled = false;
logger.info("Security Orchestration disabled");
}
public static class SecurityWorkflow {
private final String name;
private final List<SecurityAction> actions;
public SecurityWorkflow(String name, List<SecurityAction> actions) {
this.name = name;
this.actions = actions;
}
public String getName() { return name; }
public List<SecurityAction> getActions() { return actions; }
}
public static class SecurityAction {
private final String type;
private final String name;
private final String description;
private final boolean critical;
public SecurityAction(String type, String name, String description) {
this(type, name, description, false);
}
public SecurityAction(String type, String name, String description, boolean critical) {
this.type = type;
this.name = name;
this.description = description;
this.critical = critical;
}
public String getType() { return type; }
public String getName() { return name; }
public String getDescription() { return description; }
public boolean isCritical() { return critical; }
}
public static class OrchestrationTask {
private final String taskId;
private final String workflowName;
private final Map<String, Object> context;
private final Map<String, Boolean> actionResults;
private volatile String status;
private final long startTime;
public OrchestrationTask(String taskId, String workflowName, Map<String, Object> context) {
this.taskId = taskId;
this.workflowName = workflowName;
this.context = context;
this.actionResults = new HashMap<>();
this.status = "RUNNING";
this.startTime = System.currentTimeMillis();
}
public void addActionResult(String actionName, boolean success) {
actionResults.put(actionName, success);
}
public String getTaskId() { return taskId; }
public String getWorkflowName() { return workflowName; }
public Map<String, Object> getContext() { return context; }
public Map<String, Boolean> getActionResults() { return actionResults; }
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
public long getStartTime() { return startTime; }
public long getDuration() { return System.currentTimeMillis() - startTime; }
}
public static class OrchestrationEvent {
private final String taskId;
private final String workflowName;
private final String status;
private final String details;
private final LocalDateTime timestamp;
public OrchestrationEvent(String taskId, String workflowName, String status, String details, LocalDateTime timestamp) {
this.taskId = taskId;
this.workflowName = workflowName;
this.status = status;
this.details = details;
this.timestamp = timestamp;
}
public String getTaskId() { return taskId; }
public String getWorkflowName() { return workflowName; }
public String getStatus() { return status; }
public String getDetails() { return details; }
public LocalDateTime getTimestamp() { return timestamp; }
}
public static class WorkflowExecutionResult {
private final String executionId;
private final String workflowName;
private final String status;
private final boolean dryRun;
private final Map<String, Boolean> actions;
public WorkflowExecutionResult(String executionId, String workflowName, String status, boolean dryRun, Map<String, Boolean> actions) {
this.executionId = executionId;
this.workflowName = workflowName;
this.status = status;
this.dryRun = dryRun;
this.actions = actions;
}
public String getExecutionId() { return executionId; }
public String getWorkflowName() { return workflowName; }
public String getStatus() { return status; }
public boolean isDryRun() { return dryRun; }
public Map<String, Boolean> getActions() { return actions; }
}
}
@@ -0,0 +1,369 @@
package com.aluer.security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicLong;
import java.time.LocalDateTime;
import java.time.Duration;
import java.time.format.DateTimeFormatter;
import java.security.MessageDigest;
import java.util.Base64;
@Component
public class SessionManagementService {
private static final Logger logger = LoggerFactory.getLogger(SessionManagementService.class);
private final Map<String, Session> sessions = new ConcurrentHashMap<>();
private final Map<String, SessionMetadata> sessionMetadata = new ConcurrentHashMap<>();
private final Queue<SessionEvent> eventLog = new ConcurrentLinkedQueue<>();
private final Map<String, List<String>> userSessions = new ConcurrentHashMap<>();
private final AtomicLong totalSessionsCreated = new AtomicLong(0);
private final AtomicLong totalSessionsExpired = new AtomicLong(0);
private final AtomicLong totalSessionsInvalidated = new AtomicLong(0);
private static final int DEFAULT_SESSION_TIMEOUT_MINUTES = 30;
private static final int MAX_SESSIONS_PER_USER = 5;
private static final int SESSION_CLEANUP_INTERVAL_MINUTES = 5;
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public SessionManagementService() {
logger.info("Session Management Service initialized");
}
public Session createSession(String username, String ipAddress, String userAgent) {
if (userSessions.containsKey(username)) {
List<String> existing = userSessions.get(username);
if (existing.size() >= MAX_SESSIONS_PER_USER) {
logger.warn("User {} has reached maximum session limit", username);
return null;
}
}
String sessionId = generateSessionId(username);
Session session = new Session(sessionId, username, ipAddress, userAgent);
sessions.put(sessionId, session);
SessionMetadata metadata = new SessionMetadata(username, ipAddress);
sessionMetadata.put(sessionId, metadata);
userSessions.computeIfAbsent(username, k -> new ArrayList<>()).add(sessionId);
totalSessionsCreated.incrementAndGet();
logEvent(sessionId, username, ipAddress, "CREATED", "New session created");
logger.info("Created session for user: {} from IP: {}", username, ipAddress);
return session;
}
public Session getSession(String sessionId) {
Session session = sessions.get(sessionId);
if (session != null && !session.isExpired()) {
session.updateLastActivity();
return session;
}
return null;
}
public boolean validateSession(String sessionId) {
Session session = getSession(sessionId);
return session != null;
}
public boolean invalidateSession(String sessionId) {
Session session = sessions.remove(sessionId);
if (session != null) {
SessionMetadata metadata = sessionMetadata.remove(sessionId);
List<String> userSessionList = userSessions.get(session.getUsername());
if (userSessionList != null) {
userSessionList.remove(sessionId);
if (userSessionList.isEmpty()) {
userSessions.remove(session.getUsername());
}
}
totalSessionsInvalidated.incrementAndGet();
logEvent(sessionId, session.getUsername(), session.getIpAddress(), "INVALIDATED", "Session invalidated");
logger.info("Invalidated session: {} for user: {}", sessionId, session.getUsername());
return true;
}
return false;
}
public boolean extendSession(String sessionId, int additionalMinutes) {
Session session = sessions.get(sessionId);
if (session != null) {
session.extendTimeout(additionalMinutes);
logEvent(sessionId, session.getUsername(), session.getIpAddress(), "EXTENDED", "Session extended by " + additionalMinutes + " minutes");
return true;
}
return false;
}
public void refreshSession(String sessionId) {
Session session = sessions.get(sessionId);
if (session != null) {
session.updateLastActivity();
SessionMetadata metadata = sessionMetadata.get(sessionId);
if (metadata != null) {
metadata.incrementActivityCount();
}
}
}
public List<Session> getUserSessions(String username) {
List<String> sessionIds = userSessions.get(username);
if (sessionIds == null) {
return Collections.emptyList();
}
List<Session> userSessionsList = new ArrayList<>();
for (String sessionId : sessionIds) {
Session session = sessions.get(sessionId);
if (session != null && !session.isExpired()) {
userSessionsList.add(session);
}
}
return userSessionsList;
}
public int invalidateUserSessions(String username) {
List<String> sessionIds = userSessions.remove(username);
if (sessionIds == null) {
return 0;
}
int count = 0;
for (String sessionId : sessionIds) {
Session session = sessions.remove(sessionId);
sessionMetadata.remove(sessionId);
if (session != null) {
count++;
totalSessionsInvalidated.incrementAndGet();
}
}
logger.info("Invalidated {} sessions for user: {}", count, username);
return count;
}
public void cleanupExpiredSessions() {
long now = System.currentTimeMillis();
int expiredCount = 0;
List<String> expiredSessionIds = new ArrayList<>();
for (Map.Entry<String, Session> entry : sessions.entrySet()) {
if (entry.getValue().isExpired()) {
expiredSessionIds.add(entry.getKey());
}
}
for (String sessionId : expiredSessionIds) {
Session session = sessions.remove(sessionId);
if (session != null) {
SessionMetadata metadata = sessionMetadata.remove(sessionId);
List<String> userSessionList = userSessions.get(session.getUsername());
if (userSessionList != null) {
userSessionList.remove(sessionId);
if (userSessionList.isEmpty()) {
userSessions.remove(session.getUsername());
}
}
expiredCount++;
totalSessionsExpired.incrementAndGet();
logEvent(sessionId, session.getUsername(), session.getIpAddress(), "EXPIRED", "Session expired");
}
}
if (expiredCount > 0) {
logger.info("Cleaned up {} expired sessions", expiredCount);
}
}
private String generateSessionId(String username) {
try {
String data = username + System.currentTimeMillis() + UUID.randomUUID().toString();
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] hash = md.digest(data.getBytes());
return Base64.getUrlEncoder().withoutPadding().encodeToString(hash);
} catch (Exception e) {
return UUID.randomUUID().toString();
}
}
public Map<String, Object> getStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("activeSessions", sessions.size());
stats.put("totalSessionsCreated", totalSessionsCreated.get());
stats.put("totalSessionsExpired", totalSessionsExpired.get());
stats.put("totalSessionsInvalidated", totalSessionsInvalidated.get());
stats.put("uniqueUsers", userSessions.size());
long now = System.currentTimeMillis();
long activeCount = sessions.values().stream()
.filter(s -> !s.isExpired())
.count();
stats.put("currentlyActive", activeCount);
return stats;
}
public List<SessionEvent> getRecentEvents(int limit) {
List<SessionEvent> events = new ArrayList<>();
int count = 0;
for (SessionEvent event : eventLog) {
if (count++ >= limit) break;
events.add(event);
}
return events;
}
public Map<String, Session> getAllActiveSessions() {
Map<String, Session> active = new HashMap<>();
for (Map.Entry<String, Session> entry : sessions.entrySet()) {
if (!entry.getValue().isExpired()) {
active.put(entry.getKey(), entry.getValue());
}
}
return active;
}
public List<Session> getSessionsByIP(String ipAddress) {
List<Session> result = new ArrayList<>();
for (Session session : sessions.values()) {
if (session.getIpAddress().equals(ipAddress) && !session.isExpired()) {
result.add(session);
}
}
return result;
}
private void logEvent(String sessionId, String username, String ipAddress, String eventType, String details) {
SessionEvent event = new SessionEvent(sessionId, username, ipAddress, eventType, details, LocalDateTime.now());
eventLog.offer(event);
if (eventLog.size() > 5000) {
eventLog.poll();
}
}
public void setDefaultSessionTimeout(int minutes) {
logger.info("Default session timeout set to {} minutes", minutes);
}
public static class Session {
private final String sessionId;
private final String username;
private final String ipAddress;
private final String userAgent;
private final long createdAt;
private volatile long lastActivityAt;
private volatile long expiresAt;
private volatile Map<String, Object> attributes = new ConcurrentHashMap<>();
public Session(String sessionId, String username, String ipAddress, String userAgent) {
this.sessionId = sessionId;
this.username = username;
this.ipAddress = ipAddress;
this.userAgent = userAgent;
this.createdAt = System.currentTimeMillis();
this.lastActivityAt = createdAt;
this.expiresAt = createdAt + (DEFAULT_SESSION_TIMEOUT_MINUTES * 60 * 1000L);
}
public void updateLastActivity() {
this.lastActivityAt = System.currentTimeMillis();
}
public void extendTimeout(int additionalMinutes) {
this.expiresAt = Math.max(expiresAt, System.currentTimeMillis()) + (additionalMinutes * 60 * 1000L);
}
public boolean isExpired() {
return System.currentTimeMillis() > expiresAt;
}
public long getIdleTime() {
return System.currentTimeMillis() - lastActivityAt;
}
public String getSessionId() { return sessionId; }
public String getUsername() { return username; }
public String getIpAddress() { return ipAddress; }
public String getUserAgent() { return userAgent; }
public long getCreatedAt() { return createdAt; }
public long getLastActivityAt() { return lastActivityAt; }
public long getExpiresAt() { return expiresAt; }
public Map<String, Object> getAttributes() { return attributes; }
public void setAttribute(String key, Object value) {
attributes.put(key, value);
}
public Object getAttribute(String key) {
return attributes.get(key);
}
}
public static class SessionMetadata {
private final String username;
private final String originalIP;
private volatile long activityCount;
private volatile String lastActivity;
private volatile long lastActivityTimestamp;
public SessionMetadata(String username, String originalIP) {
this.username = username;
this.originalIP = originalIP;
this.activityCount = 0;
this.lastActivity = "session_created";
this.lastActivityTimestamp = System.currentTimeMillis();
}
public void incrementActivityCount() {
activityCount++;
lastActivityTimestamp = System.currentTimeMillis();
}
public String getUsername() { return username; }
public String getOriginalIP() { return originalIP; }
public long getActivityCount() { return activityCount; }
public String getLastActivity() { return lastActivity; }
public void setLastActivity(String activity) { this.lastActivity = activity; }
public long getLastActivityTimestamp() { return lastActivityTimestamp; }
}
public static class SessionEvent {
private final String sessionId;
private final String username;
private final String ipAddress;
private final String eventType;
private final String details;
private final LocalDateTime timestamp;
public SessionEvent(String sessionId, String username, String ipAddress, String eventType, String details, LocalDateTime timestamp) {
this.sessionId = sessionId;
this.username = username;
this.ipAddress = ipAddress;
this.eventType = eventType;
this.details = details;
this.timestamp = timestamp;
}
public String getSessionId() { return sessionId; }
public String getUsername() { return username; }
public String getIpAddress() { return ipAddress; }
public String getEventType() { return eventType; }
public String getDetails() { return details; }
public LocalDateTime getTimestamp() { return timestamp; }
}
}
@@ -0,0 +1,553 @@
package com.aluer.security;
import com.aluer.config.ServerGuardConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicLong;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.net.URL;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.UnknownHostException;
@Component
public class ThreatIntelligenceService {
private static final Logger logger = LoggerFactory.getLogger(ThreatIntelligenceService.class);
private final ServerGuardConfig config;
private final Map<String, ThreatIndicator> threatDatabase = new ConcurrentHashMap<>();
private final Map<String, IPReputation> ipReputations = new ConcurrentHashMap<>();
private final Queue<ThreatEvent> eventLog = new ConcurrentLinkedQueue<>();
private final Map<String, List<String>> threatFeeds = new ConcurrentHashMap<>();
private final Map<String, FeedState> feedStates = new ConcurrentHashMap<>();
private final Map<String, CachedLookup> lookupCache = new ConcurrentHashMap<>();
private final AtomicLong totalLookups = new AtomicLong(0);
private final AtomicLong threatsDetected = new AtomicLong(0);
private final AtomicLong iocsIdentified = new AtomicLong(0);
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public ThreatIntelligenceService() {
this(new ServerGuardConfig());
}
@Autowired
public ThreatIntelligenceService(ServerGuardConfig config) {
this.config = config;
initializeDefaultThreatData();
}
private void initializeDefaultThreatData() {
addThreatIndicator("103.21.244.0/24", "NETWORK", "KNOWN_ATTACKER", "Known malicious IP range", 95);
addThreatIndicator("103.22.200.0/24", "NETWORK", "BOTNET", "Botnet command and control", 90);
addThreatIndicator("103.31.4.0/24", "NETWORK", "SPAM_SOURCE", "Spam sending infrastructure", 75);
addThreatIndicator("104.16.0.0/12", "NETWORK", "MALWARE_HOST", "Malware distribution network", 85);
addThreatIndicator("108.162.192.0/18", "NETWORK", "PHISHING", "Phishing campaign infrastructure", 80);
addThreatIndicator("141.101.64.0/18", "NETWORK", "ADWARE", "Adware distribution", 60);
addThreatIndicator("162.158.64.0/18", "NETWORK", "SUSPICIOUS", "Suspicious activity", 50);
addThreatIndicator("172.64.0.0/13", "NETWORK", "TOR_EXIT", "Tor exit node", 70);
addThreatIndicator("173.245.48.0/20", "NETWORK", "VPN_PROXY", "VPN/Proxy service", 65);
addThreatIndicator("188.114.96.0/20", "NETWORK", "MALICIOUS", "Known malicious activity", 85);
addThreatIndicator("bad-actor.exe", "FILE_HASH", "MALWARE", "Known malware sample", 100);
addThreatIndicator("eicar_test_file", "FILE_HASH", "TEST", "EICAR test file", 100);
addThreatIndicator("suspicious-script.js", "FILE_HASH", "MALWARE", "Malicious JavaScript", 95);
addThreatIndicator("evil-domain.com", "DOMAIN", "MALICIOUS", "Known malicious domain", 90);
addThreatIndicator("phishing-bank.fake", "DOMAIN", "PHISHING", "Phishing domain", 100);
addThreatIndicator("ransom-c2.evil", "DOMAIN", "RANSOMWARE", "Ransomware command and control", 100);
addThreatIndicator("malware-dist.net", "DOMAIN", "MALWARE_HOST", "Malware distribution", 95);
addThreatIndicator("coin-miner.pool", "DOMAIN", "CRYPTOMINING", "Cryptocurrency mining pool", 80);
addThreatIndicator("CVE-2024-0001", "CVE", "VULNERABILITY", "Critical vulnerability", 100);
addThreatIndicator("CVE-2024-0002", "CVE", "VULNERABILITY", "High severity vulnerability", 90);
addThreatIndicator("CVE-2024-0003", "CVE", "VULNERABILITY", "Medium severity vulnerability", 70);
logger.info("Initialized threat database with {} indicators", threatDatabase.size());
}
public void addThreatIndicator(String indicator, String type, String category, String description, int severity) {
ThreatIndicator ti = new ThreatIndicator(indicator, type, category, description, severity);
threatDatabase.put(indicator.toLowerCase(), ti);
logger.info("Added threat indicator: {} [{}] severity: {}", indicator, type, severity);
}
public ThreatLookupResult lookupIP(String ip) {
CachedLookup cached = lookupCache.get("IP:" + ip);
if (cached != null && !cached.isExpired(config.getSecurity().getThreatFeeds().getCacheTtlMinutes())) {
return cached.result.copy();
}
ThreatLookupResult result = new ThreatLookupResult();
result.setIndicator(ip);
result.setType("IP");
result.setTimestamp(LocalDateTime.now());
totalLookups.incrementAndGet();
IPReputation rep = ipReputations.get(ip);
if (rep != null) {
result.setReputationScore(rep.getScore());
result.setThreatCategories(new ArrayList<>(rep.getThreatCategories()));
result.setLastSeen(rep.getLastSeen());
result.setConfidence(rep.getConfidence());
}
for (Map.Entry<String, ThreatIndicator> entry : threatDatabase.entrySet()) {
if (isIPInRange(ip, entry.getKey())) {
ThreatIndicator ti = entry.getValue();
result.addMatchedIndicator(ti);
threatsDetected.incrementAndGet();
iocsIdentified.incrementAndGet();
}
}
if (result.getMatchedIndicators().isEmpty()) {
result.setReputationScore(calculateDefaultReputation(ip));
result.setThreatCategories(new ArrayList<>());
result.setConfidence(50);
}
updateIPReputation(ip, result);
lookupCache.put("IP:" + ip, new CachedLookup(result.copy()));
return result;
}
public ThreatLookupResult lookupDomain(String domain) {
CachedLookup cached = lookupCache.get("DOMAIN:" + domain.toLowerCase());
if (cached != null && !cached.isExpired(config.getSecurity().getThreatFeeds().getCacheTtlMinutes())) {
return cached.result.copy();
}
ThreatLookupResult result = new ThreatLookupResult();
result.setIndicator(domain);
result.setType("DOMAIN");
result.setTimestamp(LocalDateTime.now());
totalLookups.incrementAndGet();
ThreatIndicator ti = threatDatabase.get(domain.toLowerCase());
if (ti != null) {
result.addMatchedIndicator(ti);
result.setReputationScore(ti.getSeverity());
result.setThreatCategories(Collections.singletonList(ti.getCategory()));
result.setConfidence(ti.getSeverity());
threatsDetected.incrementAndGet();
iocsIdentified.incrementAndGet();
} else {
result.setReputationScore(calculateDomainReputation(domain));
result.setThreatCategories(new ArrayList<>());
result.setConfidence(30);
}
lookupCache.put("DOMAIN:" + domain.toLowerCase(), new CachedLookup(result.copy()));
return result;
}
public ThreatLookupResult lookupHash(String hash) {
CachedLookup cached = lookupCache.get("HASH:" + hash.toLowerCase());
if (cached != null && !cached.isExpired(config.getSecurity().getThreatFeeds().getCacheTtlMinutes())) {
return cached.result.copy();
}
ThreatLookupResult result = new ThreatLookupResult();
result.setIndicator(hash);
result.setType("FILE_HASH");
result.setTimestamp(LocalDateTime.now());
totalLookups.incrementAndGet();
ThreatIndicator ti = threatDatabase.get(hash.toLowerCase());
if (ti != null) {
result.addMatchedIndicator(ti);
result.setReputationScore(ti.getSeverity());
result.setThreatCategories(Collections.singletonList(ti.getCategory()));
result.setConfidence(ti.getSeverity());
threatsDetected.incrementAndGet();
iocsIdentified.incrementAndGet();
} else {
result.setReputationScore(0);
result.setThreatCategories(new ArrayList<>());
result.setConfidence(0);
}
lookupCache.put("HASH:" + hash.toLowerCase(), new CachedLookup(result.copy()));
return result;
}
private boolean isIPInRange(String ip, String cidr) {
if (!cidr.contains("/")) {
return ip.equals(cidr);
}
try {
String[] parts = cidr.split("/");
byte[] address = InetAddress.getByName(parts[0]).getAddress();
byte[] target = InetAddress.getByName(ip).getAddress();
int prefix = Integer.parseInt(parts[1]);
int fullBytes = prefix / 8;
int remainingBits = prefix % 8;
for (int i = 0; i < fullBytes; i++) {
if (address[i] != target[i]) {
return false;
}
}
if (remainingBits == 0) {
return true;
}
int mask = (-1) << (8 - remainingBits);
return (address[fullBytes] & mask) == (target[fullBytes] & mask);
} catch (UnknownHostException | NumberFormatException e) {
return false;
}
}
private int calculateDefaultReputation(String ip) {
if (ip.startsWith("127.") || ip.startsWith("192.168.") || ip.startsWith("10.")) {
return 100;
}
if (ip.startsWith("172.")) {
String[] parts = ip.split("\\.");
if (parts.length >= 1) {
int second = Integer.parseInt(parts[1]);
if (second >= 16 && second <= 31) {
return 100;
}
}
}
return 50;
}
private int calculateDomainReputation(String domain) {
String[] parts = domain.split("\\.");
if (parts.length < 2) return 50;
String tld = parts[parts.length - 1];
if (tld.equals("tk") || tld.equals("ml") || tld.equals("ga") || tld.equals("cf") || tld.equals("gq")) {
return 30;
}
if (domain.contains("free") || domain.contains("download") || domain.contains("crack")) {
return 20;
}
return 50;
}
private void updateIPReputation(String ip, ThreatLookupResult result) {
IPReputation rep = ipReputations.computeIfAbsent(ip, k -> new IPReputation(ip));
if (!result.getMatchedIndicators().isEmpty()) {
rep.addThreatCategory(result.getMatchedIndicators().get(0).getCategory());
rep.adjustScore(-10);
} else {
rep.adjustScore(5);
}
rep.setLastSeen(LocalDateTime.now());
}
public void updateIPReputationFromExternal(String ip, int score, List<String> categories) {
IPReputation rep = ipReputations.computeIfAbsent(ip, k -> new IPReputation(ip));
rep.setScore(score);
for (String category : categories) {
rep.addThreatCategory(category);
}
rep.setLastSeen(LocalDateTime.now());
logger.info("Updated reputation for IP: {} score: {}", ip, score);
}
public Map<String, IPReputation> getMaliciousIPs(int limit) {
Map<String, IPReputation> malicious = new HashMap<>();
for (Map.Entry<String, IPReputation> entry : ipReputations.entrySet()) {
if (entry.getValue().getScore() < 30) {
malicious.put(entry.getKey(), entry.getValue());
}
}
return malicious;
}
public void addThreatFeed(String feedName, List<String> indicators) {
threatFeeds.put(feedName, indicators);
logger.info("Added threat feed: {} with {} indicators", feedName, indicators.size());
}
public Map<String, Object> refreshFeeds() {
Map<String, Object> result = new LinkedHashMap<>();
int loaded = 0;
int failed = 0;
if (!config.getSecurity().getThreatFeeds().isEnabled()) {
result.put("enabled", false);
result.put("loadedFeeds", loaded);
result.put("failedFeeds", failed);
return result;
}
for (ServerGuardConfig.FeedSourceConfig source : config.getSecurity().getThreatFeeds().getSources()) {
if (!source.isEnabled() || source.getUrl() == null || source.getUrl().isBlank()) {
continue;
}
try {
List<String> indicators = downloadIndicators(source);
if (!indicators.isEmpty()) {
addThreatFeed(source.getName(), indicators);
for (String indicator : indicators) {
addThreatIndicator(indicator, source.getType(), "EXTERNAL_FEED",
"Loaded from feed " + source.getName(), Math.min(100, Math.max(10, source.getWeight())));
}
feedStates.put(source.getName(), new FeedState(source.getName(), true, indicators.size(), LocalDateTime.now(), null));
loaded++;
}
} catch (IOException e) {
feedStates.put(source.getName(), new FeedState(source.getName(), false, 0, LocalDateTime.now(), e.getMessage()));
failed++;
logger.warn("Threat feed refresh failed for {}: {}", source.getName(), e.getMessage());
}
}
result.put("enabled", true);
result.put("loadedFeeds", loaded);
result.put("failedFeeds", failed);
result.put("feedStates", getFeedStatus());
return result;
}
public Map<String, Object> getFeedStatus() {
Map<String, Object> status = new LinkedHashMap<>();
status.put("configuredSources", config.getSecurity().getThreatFeeds().getSources().size());
status.put("activeFeeds", threatFeeds.size());
status.put("states", new ArrayList<>(feedStates.values()));
return status;
}
private List<String> downloadIndicators(ServerGuardConfig.FeedSourceConfig source) throws IOException {
HttpURLConnection connection = (HttpURLConnection) new URL(source.getUrl()).openConnection();
connection.setConnectTimeout(config.getSecurity().getThreatFeeds().getConnectTimeoutMs());
connection.setReadTimeout(config.getSecurity().getThreatFeeds().getReadTimeoutMs());
connection.setRequestMethod("GET");
List<String> indicators = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
String trimmed = line.trim();
if (!trimmed.isEmpty() && !trimmed.startsWith("#")) {
indicators.add(trimmed);
}
}
}
return indicators;
}
public Map<String, Object> getStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("totalLookups", totalLookups.get());
stats.put("threatsDetected", threatsDetected.get());
stats.put("iocsIdentified", iocsIdentified.get());
stats.put("indicatorsInDatabase", threatDatabase.size());
stats.put("uniqueIPsAnalyzed", ipReputations.size());
stats.put("threatFeeds", threatFeeds.size());
stats.put("feedCacheEntries", lookupCache.size());
long maliciousCount = ipReputations.values().stream()
.filter(r -> r.getScore() < 30)
.count();
stats.put("maliciousIPs", maliciousCount);
return stats;
}
public List<ThreatEvent> getRecentEvents(int limit) {
List<ThreatEvent> events = new ArrayList<>();
int count = 0;
for (ThreatEvent event : eventLog) {
if (count++ >= limit) break;
events.add(event);
}
return events;
}
public void logThreatEvent(String indicator, String type, String details) {
ThreatEvent event = new ThreatEvent(indicator, type, details, LocalDateTime.now());
eventLog.offer(event);
if (eventLog.size() > 5000) {
eventLog.poll();
}
}
public static class ThreatIndicator {
private final String indicator;
private final String type;
private final String category;
private final String description;
private final int severity;
public ThreatIndicator(String indicator, String type, String category, String description, int severity) {
this.indicator = indicator;
this.type = type;
this.category = category;
this.description = description;
this.severity = severity;
}
public String getIndicator() { return indicator; }
public String getType() { return type; }
public String getCategory() { return category; }
public String getDescription() { return description; }
public int getSeverity() { return severity; }
}
public static class ThreatLookupResult {
private String indicator;
private String type;
private int reputationScore;
private List<String> threatCategories;
private List<ThreatIndicator> matchedIndicators;
private LocalDateTime lastSeen;
private int confidence;
private LocalDateTime timestamp;
public ThreatLookupResult() {
this.threatCategories = new ArrayList<>();
this.matchedIndicators = new ArrayList<>();
}
public String getIndicator() { return indicator; }
public void setIndicator(String indicator) { this.indicator = indicator; }
public String getType() { return type; }
public void setType(String type) { this.type = type; }
public int getReputationScore() { return reputationScore; }
public void setReputationScore(int reputationScore) { this.reputationScore = reputationScore; }
public List<String> getThreatCategories() { return threatCategories; }
public void setThreatCategories(List<String> threatCategories) { this.threatCategories = threatCategories; }
public List<ThreatIndicator> getMatchedIndicators() { return matchedIndicators; }
public void addMatchedIndicator(ThreatIndicator indicator) { this.matchedIndicators.add(indicator); }
public LocalDateTime getLastSeen() { return lastSeen; }
public void setLastSeen(LocalDateTime lastSeen) { this.lastSeen = lastSeen; }
public int getConfidence() { return confidence; }
public void setConfidence(int confidence) { this.confidence = confidence; }
public LocalDateTime getTimestamp() { return timestamp; }
public void setTimestamp(LocalDateTime timestamp) { this.timestamp = timestamp; }
public ThreatLookupResult copy() {
ThreatLookupResult copy = new ThreatLookupResult();
copy.setIndicator(indicator);
copy.setType(type);
copy.setReputationScore(reputationScore);
copy.setThreatCategories(new ArrayList<>(threatCategories));
for (ThreatIndicator matchedIndicator : matchedIndicators) {
copy.addMatchedIndicator(matchedIndicator);
}
copy.setLastSeen(lastSeen);
copy.setConfidence(confidence);
copy.setTimestamp(timestamp);
return copy;
}
}
public static class IPReputation {
private final String ip;
private volatile int score;
private final Set<String> threatCategories;
private volatile LocalDateTime firstSeen;
private volatile LocalDateTime lastSeen;
public IPReputation(String ip) {
this.ip = ip;
this.score = 50;
this.threatCategories = new HashSet<>();
this.firstSeen = LocalDateTime.now();
this.lastSeen = LocalDateTime.now();
}
public void adjustScore(int delta) {
this.score = Math.max(-100, Math.min(100, this.score + delta));
}
public void addThreatCategory(String category) {
this.threatCategories.add(category);
}
public int getConfidence() {
return Math.min(100, 50 + threatCategories.size() * 10);
}
public String getIp() { return ip; }
public int getScore() { return score; }
public void setScore(int score) { this.score = score; }
public Set<String> getThreatCategories() { return threatCategories; }
public LocalDateTime getFirstSeen() { return firstSeen; }
public LocalDateTime getLastSeen() { return lastSeen; }
public void setLastSeen(LocalDateTime lastSeen) { this.lastSeen = lastSeen; }
}
public static class ThreatEvent {
private final String indicator;
private final String type;
private final String details;
private final LocalDateTime timestamp;
public ThreatEvent(String indicator, String type, String details, LocalDateTime timestamp) {
this.indicator = indicator;
this.type = type;
this.details = details;
this.timestamp = timestamp;
}
public String getIndicator() { return indicator; }
public String getType() { return type; }
public String getDetails() { return details; }
public LocalDateTime getTimestamp() { return timestamp; }
}
public static class FeedState {
private final String name;
private final boolean success;
private final int indicatorsLoaded;
private final LocalDateTime lastRefresh;
private final String error;
public FeedState(String name, boolean success, int indicatorsLoaded, LocalDateTime lastRefresh, String error) {
this.name = name;
this.success = success;
this.indicatorsLoaded = indicatorsLoaded;
this.lastRefresh = lastRefresh;
this.error = error;
}
public String getName() { return name; }
public boolean isSuccess() { return success; }
public int getIndicatorsLoaded() { return indicatorsLoaded; }
public LocalDateTime getLastRefresh() { return lastRefresh; }
public String getError() { return error; }
}
private static class CachedLookup {
private final ThreatLookupResult result;
private final long createdAt;
private CachedLookup(ThreatLookupResult result) {
this.result = result;
this.createdAt = System.currentTimeMillis();
}
private boolean isExpired(long ttlMinutes) {
return System.currentTimeMillis() - createdAt > ttlMinutes * 60_000L;
}
}
}
@@ -0,0 +1,293 @@
package com.aluer.security;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.regex.*;
@Service
public class TrafficAnalysisService {
private final Map<String, TrafficSession> sessions = new ConcurrentHashMap<>();
private final Map<String, List<TrafficSample>> trafficHistory = new ConcurrentHashMap<>();
private final Map<String, AnomalyScore> anomalyScores = new ConcurrentHashMap<>();
private final Queue<TrafficAlert> alerts = new ConcurrentLinkedQueue<>();
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
private static final int MAX_SESSIONS = 10000;
private static final long SESSION_TIMEOUT = 300000;
private static final int HISTORY_SIZE = 1000;
private static final double ANOMALY_THRESHOLD = 0.75;
private final AtomicLong totalPacketsAnalyzed = new AtomicLong(0);
private final AtomicLong totalAnomaliesDetected = new AtomicLong(0);
public TrafficAnalysisService() {
startAnalysisTask();
}
public boolean analyzePacket(String sourceIP, String destIP, int port, int packetSize, String protocol) {
totalPacketsAnalyzed.incrementAndGet();
TrafficSession session = sessions.computeIfAbsent(sourceIP, k -> new TrafficSession(sourceIP));
session.recordPacket(destIP, port, packetSize, protocol);
boolean isAnomaly = checkForAnomalies(session);
if (isAnomaly) {
AnomalyScore score = anomalyScores.computeIfAbsent(sourceIP, k -> new AnomalyScore(sourceIP));
score.increment();
if (score.getScore() > ANOMALY_THRESHOLD) {
triggerAlert(sourceIP, "TRAFFIC_ANOMALY", "Anomaly score: " + score.getScore());
totalAnomaliesDetected.incrementAndGet();
return false;
}
}
recordTrafficSample(sourceIP, packetSize, protocol);
return true;
}
private boolean checkForAnomalies(TrafficSession session) {
if (session.packetCount > 1000) {
return true;
}
if (session.totalBytes > 100_000_000) {
return true;
}
if (session.uniquePorts.size() > 100) {
return true;
}
if (session.uniqueDestinations.size() > 50) {
return true;
}
return false;
}
private void recordTrafficSample(String ip, int packetSize, String protocol) {
List<TrafficSample> history = trafficHistory.computeIfAbsent(ip, k -> new CopyOnWriteArrayList<>());
TrafficSample sample = new TrafficSample(packetSize, protocol, System.currentTimeMillis());
history.add(sample);
while (history.size() > HISTORY_SIZE) {
history.remove(0);
}
}
public void triggerAlert(String sourceIP, String type, String details) {
TrafficAlert alert = new TrafficAlert(sourceIP, type, details, System.currentTimeMillis());
alerts.offer(alert);
while (alerts.size() > 500) {
alerts.poll();
}
}
public TrafficSession getSession(String ip) {
return sessions.get(ip);
}
public Collection<TrafficSession> getAllSessions() {
return sessions.values();
}
public AnomalyScore getAnomalyScore(String ip) {
return anomalyScores.get(ip);
}
public Map<String, AnomalyScore> getAllAnomalyScores() {
return new HashMap<>(anomalyScores);
}
public List<TrafficAlert> getAlerts(int limit) {
List<TrafficAlert> result = new ArrayList<>();
int count = 0;
for (TrafficAlert alert : alerts) {
if (count++ >= limit) break;
result.add(alert);
}
return result;
}
public Map<String, Object> getTrafficStats(String ip) {
TrafficSession session = sessions.get(ip);
if (session == null) {
return Collections.emptyMap();
}
Map<String, Object> stats = new HashMap<>();
stats.put("packetCount", session.packetCount);
stats.put("totalBytes", session.totalBytes);
stats.put("uniquePorts", session.uniquePorts.size());
stats.put("uniqueDestinations", session.uniqueDestinations.size());
stats.put("protocols", new HashSet<>(session.protocols));
return stats;
}
public Map<String, Object> getGlobalStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("activeSessions", sessions.size());
stats.put("totalPacketsAnalyzed", totalPacketsAnalyzed.get());
stats.put("totalAnomaliesDetected", totalAnomaliesDetected.get());
stats.put("uniqueIPsTracked", trafficHistory.size());
long totalBytes = sessions.values().stream()
.mapToLong(s -> s.totalBytes)
.sum();
stats.put("totalBytesProcessed", totalBytes);
return stats;
}
private void startAnalysisTask() {
scheduler.scheduleAtFixedRate(() -> {
long now = System.currentTimeMillis();
sessions.entrySet().removeIf(entry ->
now - entry.getValue().lastActivity > SESSION_TIMEOUT);
anomalyScores.entrySet().removeIf(entry ->
entry.getValue().getScore() < 0.1);
for (TrafficSession session : sessions.values()) {
session.resetCountersIfNeeded();
}
}, 60, 60, TimeUnit.SECONDS);
}
public static class TrafficSession {
private final String ip;
private final Map<String, Integer> destinationPorts = new ConcurrentHashMap<>();
private final Set<Integer> uniquePorts = ConcurrentHashMap.newKeySet();
private final Set<String> uniqueDestinations = ConcurrentHashMap.newKeySet();
private final Set<String> protocols = ConcurrentHashMap.newKeySet();
private volatile long packetCount = 0;
private volatile long totalBytes = 0;
private volatile long lastActivity;
private volatile long windowStart = System.currentTimeMillis();
public TrafficSession(String ip) {
this.ip = ip;
this.lastActivity = System.currentTimeMillis();
}
public void recordPacket(String destIP, int port, int packetSize, String protocol) {
packetCount++;
totalBytes += packetSize;
lastActivity = System.currentTimeMillis();
uniquePorts.add(port);
uniqueDestinations.add(destIP);
protocols.add(protocol);
String key = destIP + ":" + port;
destinationPorts.merge(key, 1, Integer::sum);
}
public void resetCountersIfNeeded() {
long now = System.currentTimeMillis();
if (now - windowStart > 60000) {
packetCount = 0;
totalBytes = 0;
windowStart = now;
}
}
public String getIp() {
return ip;
}
}
public static class TrafficSample {
private final int size;
private final String protocol;
private final long timestamp;
public TrafficSample(int size, String protocol, long timestamp) {
this.size = size;
this.protocol = protocol;
this.timestamp = timestamp;
}
public int getSize() {
return size;
}
public String getProtocol() {
return protocol;
}
public long getTimestamp() {
return timestamp;
}
}
public static class AnomalyScore {
private final String ip;
private final AtomicInteger score = new AtomicInteger(0);
private volatile long lastUpdate;
public AnomalyScore(String ip) {
this.ip = ip;
this.lastUpdate = System.currentTimeMillis();
}
public void increment() {
score.updateAndGet(s -> Math.min(100, s + 10));
lastUpdate = System.currentTimeMillis();
}
public void decrement() {
score.updateAndGet(s -> Math.max(0, s - 5));
lastUpdate = System.currentTimeMillis();
}
public double getScore() {
if (System.currentTimeMillis() - lastUpdate > 300000) {
score.set(0);
}
return score.get() / 100.0;
}
}
public static class TrafficAlert {
private final String sourceIP;
private final String type;
private final String details;
private final long timestamp;
public TrafficAlert(String sourceIP, String type, String details, long timestamp) {
this.sourceIP = sourceIP;
this.type = type;
this.details = details;
this.timestamp = timestamp;
}
public String getSourceIP() {
return sourceIP;
}
public String getType() {
return type;
}
public String getDetails() {
return details;
}
public long getTimestamp() {
return timestamp;
}
}
}
@@ -0,0 +1,319 @@
package com.aluer.security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicLong;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Component
public class TrafficShapingService {
private static final Logger logger = LoggerFactory.getLogger(TrafficShapingService.class);
private final Map<String, TrafficClass> trafficClasses = new ConcurrentHashMap<>();
private final Map<String, Queue<PacketRecord>> packetQueues = new ConcurrentHashMap<>();
private final Map<String, TokenBucket> tokenBuckets = new ConcurrentHashMap<>();
private final Map<String, TrafficStats> trafficStats = new ConcurrentHashMap<>();
private final Queue<TrafficEvent> eventLog = new ConcurrentLinkedQueue<>();
private final AtomicLong totalPacketsShaped = new AtomicLong(0);
private final AtomicLong totalPacketsDropped = new AtomicLong(0);
private final AtomicLong totalPacketsDelayed = new AtomicLong(0);
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public TrafficShapingService() {
initializeDefaultClasses();
}
private void initializeDefaultClasses() {
addTrafficClass("high-priority", 1000, 100, 50);
addTrafficClass("medium-priority", 500, 200, 100);
addTrafficClass("low-priority", 100, 500, 200);
addTrafficClass("bulk", 50, 1000, 500);
for (String className : trafficClasses.keySet()) {
packetQueues.put(className, new ConcurrentLinkedQueue<>());
tokenBuckets.put(className, new TokenBucket(
trafficClasses.get(className).getBucketSize(),
trafficClasses.get(className).getRefillRate()
));
trafficStats.put(className, new TrafficStats(className));
}
}
public void addTrafficClass(String name, int bucketSize, int refillRate, int maxDelay) {
TrafficClass tc = new TrafficClass(name, bucketSize, refillRate, maxDelay);
trafficClasses.put(name, tc);
logger.info("Added traffic class: {}", name);
}
public boolean processPacket(String sourceIP, String destIP, int port, int packetSize, String protocol) {
String trafficClass = classifyPacket(sourceIP, destIP, port, protocol);
TokenBucket bucket = tokenBuckets.get(trafficClass);
TrafficStats stats = trafficStats.get(trafficClass);
if (bucket == null || stats == null) {
return false;
}
if (!bucket.consume(packetSize)) {
totalPacketsDropped.incrementAndGet();
stats.recordDropped(packetSize);
logEvent(sourceIP, destIP, packetSize, "DROPPED", trafficClass);
return false;
}
Queue<PacketRecord> queue = packetQueues.get(trafficClass);
if (queue != null && queue.size() > 100) {
totalPacketsDropped.incrementAndGet();
stats.recordDropped(packetSize);
logEvent(sourceIP, destIP, packetSize, "QUEUE_FULL", trafficClass);
return false;
}
PacketRecord record = new PacketRecord(sourceIP, destIP, packetSize, LocalDateTime.now());
if (queue != null) {
queue.offer(record);
}
totalPacketsShaped.incrementAndGet();
stats.recordProcessed(packetSize);
logEvent(sourceIP, destIP, packetSize, "SHAPED", trafficClass);
return true;
}
private String classifyPacket(String sourceIP, String destIP, int port, String protocol) {
if (isPriorityIP(sourceIP)) {
return "high-priority";
}
if (port == 25565 || port == 25575) {
return "high-priority";
}
if ("UDP".equalsIgnoreCase(protocol)) {
return "medium-priority";
}
if (isKnownServer(port)) {
return "medium-priority";
}
return "low-priority";
}
private boolean isPriorityIP(String ip) {
return ip.startsWith("127.") || ip.startsWith("192.168.") || ip.startsWith("10.");
}
private boolean isKnownServer(int port) {
return port > 0 && port < 1024;
}
public Map<String, Object> getStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("totalPacketsShaped", totalPacketsShaped.get());
stats.put("totalPacketsDropped", totalPacketsDropped.get());
stats.put("totalPacketsDelayed", totalPacketsDelayed.get());
Map<String, TrafficStats> classStats = new HashMap<>();
for (Map.Entry<String, TrafficStats> entry : trafficStats.entrySet()) {
classStats.put(entry.getKey(), entry.getValue());
}
stats.put("classStats", classStats);
return stats;
}
public void adjustClassRate(String className, int newRefillRate) {
TrafficClass tc = trafficClasses.get(className);
if (tc != null) {
tc.setRefillRate(newRefillRate);
TokenBucket bucket = tokenBuckets.get(className);
if (bucket != null) {
bucket.setRate(newRefillRate);
}
logger.info("Adjusted rate for class {} to {}", className, newRefillRate);
}
}
public void clearQueue(String className) {
Queue<PacketRecord> queue = packetQueues.get(className);
if (queue != null) {
queue.clear();
logger.info("Cleared queue for class: {}", className);
}
}
private void logEvent(String sourceIP, String destIP, int size, String action, String trafficClass) {
TrafficEvent event = new TrafficEvent(
sourceIP, destIP, size, action, trafficClass, LocalDateTime.now()
);
eventLog.offer(event);
if (eventLog.size() > 10000) {
eventLog.poll();
}
}
public List<TrafficEvent> getRecentEvents(int limit) {
List<TrafficEvent> events = new ArrayList<>();
int count = 0;
for (TrafficEvent event : eventLog) {
if (count++ >= limit) break;
events.add(event);
}
return events;
}
public Map<String, Object> getDetailedStats(String className) {
Map<String, Object> stats = new HashMap<>();
TrafficClass tc = trafficClasses.get(className);
TrafficStats ts = trafficStats.get(className);
TokenBucket tb = tokenBuckets.get(className);
if (tc != null) {
stats.put("bucketSize", tc.getBucketSize());
stats.put("refillRate", tc.getRefillRate());
stats.put("maxDelay", tc.getMaxDelay());
}
if (ts != null) {
stats.put("packetsProcessed", ts.getPacketsProcessed());
stats.put("packetsDropped", ts.getPacketsDropped());
stats.put("bytesProcessed", ts.getBytesProcessed());
}
if (tb != null) {
stats.put("availableTokens", tb.getAvailableTokens());
}
return stats;
}
public static class TrafficClass {
private final String name;
private final int bucketSize;
private int refillRate;
private final int maxDelay;
public TrafficClass(String name, int bucketSize, int refillRate, int maxDelay) {
this.name = name;
this.bucketSize = bucketSize;
this.refillRate = refillRate;
this.maxDelay = maxDelay;
}
public String getName() { return name; }
public int getBucketSize() { return bucketSize; }
public int getRefillRate() { return refillRate; }
public int getMaxDelay() { return maxDelay; }
public void setRefillRate(int refillRate) { this.refillRate = refillRate; }
}
public static class TokenBucket {
private final int maxTokens;
private volatile int availableTokens;
private volatile int refillRate;
private long lastRefillTime;
public TokenBucket(int maxTokens, int refillRate) {
this.maxTokens = maxTokens;
this.availableTokens = maxTokens;
this.refillRate = refillRate;
this.lastRefillTime = System.currentTimeMillis();
}
public synchronized boolean consume(int tokens) {
refill();
if (availableTokens >= tokens) {
availableTokens -= tokens;
return true;
}
return false;
}
private void refill() {
long now = System.currentTimeMillis();
long elapsed = now - lastRefillTime;
if (elapsed > 100) {
int tokensToAdd = (int) (elapsed * refillRate / 1000);
availableTokens = Math.min(maxTokens, availableTokens + tokensToAdd);
lastRefillTime = now;
}
}
public int getAvailableTokens() { return availableTokens; }
public void setRate(int refillRate) { this.refillRate = refillRate; }
}
public static class PacketRecord {
private final String sourceIP;
private final String destIP;
private final int size;
private final LocalDateTime timestamp;
public PacketRecord(String sourceIP, String destIP, int size, LocalDateTime timestamp) {
this.sourceIP = sourceIP;
this.destIP = destIP;
this.size = size;
this.timestamp = timestamp;
}
public String getSourceIP() { return sourceIP; }
public String getDestIP() { return destIP; }
public int getSize() { return size; }
public LocalDateTime getTimestamp() { return timestamp; }
}
public static class TrafficStats {
private final String className;
private final AtomicLong packetsProcessed = new AtomicLong(0);
private final AtomicLong packetsDropped = new AtomicLong(0);
private final AtomicLong bytesProcessed = new AtomicLong(0);
public TrafficStats(String className) {
this.className = className;
}
public void recordProcessed(int size) {
packetsProcessed.incrementAndGet();
bytesProcessed.addAndGet(size);
}
public void recordDropped(int size) {
packetsDropped.incrementAndGet();
}
public String getClassName() { return className; }
public long getPacketsProcessed() { return packetsProcessed.get(); }
public long getPacketsDropped() { return packetsDropped.get(); }
public long getBytesProcessed() { return bytesProcessed.get(); }
}
public static class TrafficEvent {
private final String sourceIP;
private final String destIP;
private final int size;
private final String action;
private final String trafficClass;
private final LocalDateTime timestamp;
public TrafficEvent(String sourceIP, String destIP, int size, String action,
String trafficClass, LocalDateTime timestamp) {
this.sourceIP = sourceIP;
this.destIP = destIP;
this.size = size;
this.action = action;
this.trafficClass = trafficClass;
this.timestamp = timestamp;
}
public String getSourceIP() { return sourceIP; }
public String getDestIP() { return destIP; }
public int getSize() { return size; }
public String getAction() { return action; }
public String getTrafficClass() { return trafficClass; }
public LocalDateTime getTimestamp() { return timestamp; }
}
}
@@ -0,0 +1,100 @@
package com.aluer.security;
import com.aluer.console.AluerMirageShieldService;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.Map;
@Component
public class WafRequestFilter extends OncePerRequestFilter {
private final WebApplicationFirewall webApplicationFirewall;
private final AluerMirageShieldService aluerMirageShieldService;
public WafRequestFilter(WebApplicationFirewall webApplicationFirewall,
AluerMirageShieldService aluerMirageShieldService) {
this.webApplicationFirewall = webApplicationFirewall;
this.aluerMirageShieldService = aluerMirageShieldService;
}
@Override
protected boolean shouldNotFilter(HttpServletRequest request) {
String uri = request.getRequestURI();
return uri.startsWith("/favicon")
|| uri.startsWith("/assets/")
|| uri.endsWith(".css")
|| uri.endsWith(".js")
|| uri.endsWith(".png")
|| uri.endsWith(".ico");
}
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
Map<String, String> headers = extractHeaders(request);
String clientIp = resolveClientIp(request);
WebApplicationFirewall.WAFResult result = webApplicationFirewall.checkRequest(
clientIp,
request.getMethod(),
request.getRequestURI(),
request.getQueryString(),
headers,
null
);
if (result.isBlocked()) {
String notice = aluerMirageShieldService.composeDeterrenceNotice(clientIp, result.getReason());
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json");
response.setHeader("X-Aluer-Deterrence", "identified-and-isolated");
response.getWriter().write(
"{\"status\":\"blocked\",\"reason\":\"" + escapeJson(result.getReason()) +
"\",\"source\":\"" + escapeJson(clientIp) +
"\",\"notice\":\"" + escapeJson(notice) + "\"}"
);
return;
}
request.setAttribute("aluer.waf.suspicious", result.isSuspicious());
request.setAttribute("aluer.waf.rules", result.getMatchedRules());
filterChain.doFilter(request, response);
}
private Map<String, String> extractHeaders(HttpServletRequest request) {
Map<String, String> headers = new LinkedHashMap<>();
Enumeration<String> names = request.getHeaderNames();
if (names == null) {
return Collections.emptyMap();
}
while (names.hasMoreElements()) {
String name = names.nextElement();
headers.put(name, request.getHeader(name));
}
return headers;
}
private String resolveClientIp(HttpServletRequest request) {
String forwarded = request.getHeader("X-Forwarded-For");
if (forwarded != null && !forwarded.isBlank()) {
return forwarded.split(",")[0].trim();
}
return request.getRemoteAddr();
}
private String escapeJson(String value) {
if (value == null) {
return "";
}
return value.replace("\\", "\\\\").replace("\"", "\\\"");
}
}
@@ -0,0 +1,448 @@
package com.aluer.security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicLong;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
@Component
public class WebApplicationFirewall {
private static final Logger logger = LoggerFactory.getLogger(WebApplicationFirewall.class);
private final Map<String, WAFRule> rules = new ConcurrentHashMap<>();
private final Queue<WAFEvent> eventLog = new ConcurrentLinkedQueue<>();
private final Map<String, RequestStats> requestStats = new ConcurrentHashMap<>();
private final Map<String, ClientReputation> clientReputations = new ConcurrentHashMap<>();
private final AtomicLong totalRequests = new AtomicLong(0);
private final AtomicLong blockedRequests = new AtomicLong(0);
private final AtomicLong suspiciousRequests = new AtomicLong(0);
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public WebApplicationFirewall() {
initializeDefaultRules();
}
private void initializeDefaultRules() {
addRule("SQL_INJECTION", "HIGH", Pattern.compile(
".*(union|select|insert|update|delete|drop|create|alter|exec|execute|script|<script).*",
Pattern.CASE_INSENSITIVE
), "SQL注入攻击");
addRule("XSS_ATTACK", "HIGH", Pattern.compile(
".*(<script|javascript:|onerror=|onload=|alert\\(|eval\\(|document\\.|window\\.).*",
Pattern.CASE_INSENSITIVE
), "跨站脚本攻击(XSS)");
addRule("PATH_TRAVERSAL", "MEDIUM", Pattern.compile(
".*(\\.\\./|\\.\\.\\\\|%2e%2e/|%2e%2e\\\\).*",
Pattern.CASE_INSENSITIVE
), "路径遍历攻击");
addRule("COMMAND_INJECTION", "HIGH", Pattern.compile(
".*(;|\\||`|$|&&|\\|\\||>|<).*(ls|cat|rm|mv|cp|chmod|chown|wget|curl|nc|bash|sh).*",
Pattern.CASE_INSENSITIVE
), "命令注入攻击");
addRule("LDAP_INJECTION", "MEDIUM", Pattern.compile(
".*(\\(|\\)|\\*|\\?|\\?|\\?|\\\\n|\\\\r).*",
Pattern.CASE_INSENSITIVE
), "LDAP注入攻击");
addRule("XML_INJECTION", "MEDIUM", Pattern.compile(
".*(<!DOCTYPE|<!ENTITY|<!ELEMENT|CDATA|\\?xml).*",
Pattern.CASE_INSENSITIVE
), "XML注入攻击");
addRule("FILE_INCLUDE", "MEDIUM", Pattern.compile(
".*(include|require|include_once|require_once|php://|file://).*",
Pattern.CASE_INSENSITIVE
), "文件包含攻击");
addRule("SSRF_ATTACK", "HIGH", Pattern.compile(
".*(https?://(127\\.0\\.0\\.1|localhost|0\\.0\\.0\\.0|169\\.254\\.169\\.254|::1)|gopher://|dict://|ftp://).*",
Pattern.CASE_INSENSITIVE
), "服务端请求伪造(SSRF)");
addRule("SSTI_ATTACK", "HIGH", Pattern.compile(
".*(\\{\\{.*\\}\\}|\\$\\{.*\\}|<%=.*%>|#\\{.*\\}).*",
Pattern.CASE_INSENSITIVE
), "服务端模板注入(SSTI)");
addRule("JNDI_INJECTION", "HIGH", Pattern.compile(
".*\\$\\{jndi:(ldap|ldaps|rmi|dns|iiop):.*",
Pattern.CASE_INSENSITIVE
), "JNDI注入");
addRule("JAVA_DESERIALIZATION", "HIGH", Pattern.compile(
".*(rO0AB|ac ed 00 05|java\\.util\\.PriorityQueue|ysoserial).*",
Pattern.CASE_INSENSITIVE
), "Java反序列化利用");
addRule("CRLF_INJECTION", "MEDIUM", Pattern.compile(
".*(%0d|%0a|\\\\r|\\\\n|\\r|\\n).*",
Pattern.CASE_INSENSITIVE
), "CRLF注入");
addRule("OPEN_REDIRECT", "MEDIUM", Pattern.compile(
".*(redirect=|url=|next=|return=)https?://.*",
Pattern.CASE_INSENSITIVE
), "开放重定向");
addRule("VALIDATE_EMAIL", "LOW", Pattern.compile(
"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
), "邮箱格式验证");
addRule("VALIDATE_IP", "LOW", Pattern.compile(
"^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"
), "IP地址格式验证");
addRule("BLOCK_SENSITIVE", "HIGH", Pattern.compile(
".*(password|passwd|pwd|secret|token|auth|api_key|apikey|private_key).*",
Pattern.CASE_INSENSITIVE
), "敏感信息访问");
logger.info("Initialized {} WAF rules", rules.size());
}
public void addRule(String name, String severity, Pattern pattern, String description) {
WAFRule rule = new WAFRule(name, severity, pattern, description);
rules.put(name, rule);
logger.info("Added WAF rule: {} [{}]", name, severity);
}
public WAFResult checkRequest(String clientIP, String method, String uri, String queryString, Map<String, String> headers, String body) {
WAFResult result = new WAFResult();
result.setClientIP(clientIP);
result.setMethod(method);
result.setUri(uri);
result.setTimestamp(LocalDateTime.now());
totalRequests.incrementAndGet();
updateClientStats(clientIP);
if (isClientBlocked(clientIP)) {
result.setBlocked(true);
result.setReason("Client is blocked");
blockedRequests.incrementAndGet();
logEvent(clientIP, method, uri, "BLOCKED", "Client blocked");
return result;
}
if (isRateLimited(clientIP)) {
result.setBlocked(true);
result.setReason("Rate limit exceeded");
blockedRequests.incrementAndGet();
updateClientReputation(clientIP, -20);
logEvent(clientIP, method, uri, "BLOCKED", "Rate limit exceeded");
return result;
}
StringBuilder fullRequestBuilder = new StringBuilder();
fullRequestBuilder.append(method).append(" ").append(uri);
if (queryString != null) {
fullRequestBuilder.append("?").append(queryString);
}
for (Map.Entry<String, String> header : headers.entrySet()) {
if (header.getValue() != null) {
fullRequestBuilder.append("\n").append(header.getKey()).append(": ").append(header.getValue());
}
}
if (body != null) {
fullRequestBuilder.append("\n").append(body);
}
String fullRequest = fullRequestBuilder.toString();
for (WAFRule rule : rules.values()) {
if (!rule.isEnabled()) continue;
Matcher matcher = rule.getPattern().matcher(fullRequest);
if (matcher.find()) {
result.addMatchedRule(rule.getName());
if ("HIGH".equals(rule.getSeverity())) {
result.setBlocked(true);
result.setReason("High severity rule matched: " + rule.getDescription());
blockedRequests.incrementAndGet();
updateClientReputation(clientIP, -15);
logEvent(clientIP, method, uri, "BLOCKED", rule.getName() + " - " + rule.getDescription());
} else if ("MEDIUM".equals(rule.getSeverity())) {
result.setSuspicious(true);
result.addWarning("Medium severity rule matched: " + rule.getDescription());
suspiciousRequests.incrementAndGet();
updateClientReputation(clientIP, -5);
logEvent(clientIP, method, uri, "SUSPICIOUS", rule.getName());
} else {
result.addWarning("Low severity rule matched: " + rule.getDescription());
logEvent(clientIP, method, uri, "WARNING", rule.getName());
}
}
}
for (Map.Entry<String, String> header : headers.entrySet()) {
String headerValue = header.getValue();
if (headerValue != null && headerValue.length() > 1000) {
result.addWarning("Unusually long header: " + header.getKey());
suspiciousRequests.incrementAndGet();
}
if (headerValue != null && looksLikeHeaderSmuggling(header.getKey(), headerValue)) {
result.setSuspicious(true);
result.addWarning("Possible header smuggling: " + header.getKey());
suspiciousRequests.incrementAndGet();
}
}
if (!result.isBlocked()) {
logEvent(clientIP, method, uri, "ALLOWED", "Request passed all rules");
}
return result;
}
private boolean looksLikeHeaderSmuggling(String headerName, String headerValue) {
String normalizedName = headerName == null ? "" : headerName.toLowerCase(Locale.ROOT);
String normalizedValue = headerValue == null ? "" : headerValue.toLowerCase(Locale.ROOT);
if (normalizedValue.contains("\r") || normalizedValue.contains("\n")) {
return true;
}
return normalizedName.equals("host")
&& (normalizedValue.contains("127.0.0.1") || normalizedValue.contains("localhost"));
}
private void updateClientStats(String clientIP) {
RequestStats stats = requestStats.computeIfAbsent(clientIP, k -> new RequestStats(clientIP));
stats.incrementRequestCount();
long oneMinuteAgo = System.currentTimeMillis() - 60000;
if (stats.getWindowStart() < oneMinuteAgo) {
stats.setRequestCountInLastMinute(stats.getRequestCount() - stats.getRequestCountInLastMinute());
stats.setWindowStart(System.currentTimeMillis());
}
stats.incrementRequestCountInLastMinute();
}
private boolean isClientBlocked(String clientIP) {
ClientReputation rep = clientReputations.get(clientIP);
return rep != null && rep.getScore() < -100;
}
private boolean isRateLimited(String clientIP) {
RequestStats stats = requestStats.get(clientIP);
if (stats == null) return false;
return stats.getRequestCountInLastMinute() > 120;
}
private void updateClientReputation(String clientIP, int scoreChange) {
ClientReputation rep = clientReputations.computeIfAbsent(clientIP, k -> new ClientReputation(clientIP));
rep.adjustScore(scoreChange);
}
public void blockClient(String clientIP, String reason) {
ClientReputation rep = clientReputations.computeIfAbsent(clientIP, k -> new ClientReputation(clientIP));
rep.setScore(-200);
rep.setBlockReason(reason);
logger.info("Blocked client: {} - {}", clientIP, reason);
}
public void unblockClient(String clientIP) {
ClientReputation rep = clientReputations.get(clientIP);
if (rep != null) {
rep.setScore(0);
rep.setBlockReason(null);
logger.info("Unblocked client: {}", clientIP);
}
}
public Map<String, Object> getStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("totalRequests", totalRequests.get());
stats.put("blockedRequests", blockedRequests.get());
stats.put("suspiciousRequests", suspiciousRequests.get());
stats.put("activeClients", requestStats.size());
stats.put("blockedClients", clientReputations.values().stream()
.filter(r -> r.getScore() < -100).count());
stats.put("rulesLoaded", rules.size());
return stats;
}
public List<WAFEvent> getRecentEvents(int limit) {
List<WAFEvent> events = new ArrayList<>();
int count = 0;
for (WAFEvent event : eventLog) {
if (count++ >= limit) break;
events.add(event);
}
return events;
}
public Map<String, ClientReputation> getBlockedClients() {
Map<String, ClientReputation> blocked = new HashMap<>();
for (Map.Entry<String, ClientReputation> entry : clientReputations.entrySet()) {
if (entry.getValue().getScore() < -100) {
blocked.put(entry.getKey(), entry.getValue());
}
}
return blocked;
}
private void logEvent(String clientIP, String method, String uri, String action, String details) {
WAFEvent event = new WAFEvent(clientIP, method, uri, action, details, LocalDateTime.now());
eventLog.offer(event);
if (eventLog.size() > 10000) {
eventLog.poll();
}
}
public void enableRule(String ruleName) {
WAFRule rule = rules.get(ruleName);
if (rule != null) {
rule.setEnabled(true);
logger.info("Enabled WAF rule: {}", ruleName);
}
}
public void disableRule(String ruleName) {
WAFRule rule = rules.get(ruleName);
if (rule != null) {
rule.setEnabled(false);
logger.info("Disabled WAF rule: {}", ruleName);
}
}
public static class WAFRule {
private final String name;
private final String severity;
private final Pattern pattern;
private final String description;
private volatile boolean enabled = true;
public WAFRule(String name, String severity, Pattern pattern, String description) {
this.name = name;
this.severity = severity;
this.pattern = pattern;
this.description = description;
}
public String getName() { return name; }
public String getSeverity() { return severity; }
public Pattern getPattern() { return pattern; }
public String getDescription() { return description; }
public boolean isEnabled() { return enabled; }
public void setEnabled(boolean enabled) { this.enabled = enabled; }
}
public static class WAFResult {
private String clientIP;
private String method;
private String uri;
private boolean blocked;
private boolean suspicious;
private String reason;
private List<String> matchedRules = new ArrayList<>();
private List<String> warnings = new ArrayList<>();
private LocalDateTime timestamp;
public String getClientIP() { return clientIP; }
public void setClientIP(String clientIP) { this.clientIP = clientIP; }
public String getMethod() { return method; }
public void setMethod(String method) { this.method = method; }
public String getUri() { return uri; }
public void setUri(String uri) { this.uri = uri; }
public boolean isBlocked() { return blocked; }
public void setBlocked(boolean blocked) { this.blocked = blocked; }
public boolean isSuspicious() { return suspicious; }
public void setSuspicious(boolean suspicious) { this.suspicious = suspicious; }
public String getReason() { return reason; }
public void setReason(String reason) { this.reason = reason; }
public List<String> getMatchedRules() { return matchedRules; }
public void addMatchedRule(String rule) { this.matchedRules.add(rule); }
public List<String> getWarnings() { return warnings; }
public void addWarning(String warning) { this.warnings.add(warning); }
public LocalDateTime getTimestamp() { return timestamp; }
public void setTimestamp(LocalDateTime timestamp) { this.timestamp = timestamp; }
}
public static class RequestStats {
private final String clientIP;
private volatile long requestCount;
private volatile long requestCountInLastMinute;
private volatile long windowStart;
public RequestStats(String clientIP) {
this.clientIP = clientIP;
this.windowStart = System.currentTimeMillis();
}
public void incrementRequestCount() { requestCount++; }
public void incrementRequestCountInLastMinute() { requestCountInLastMinute++; }
public String getClientIP() { return clientIP; }
public long getRequestCount() { return requestCount; }
public long getRequestCountInLastMinute() { return requestCountInLastMinute; }
public long getWindowStart() { return windowStart; }
public void setRequestCountInLastMinute(long count) { this.requestCountInLastMinute = count; }
public void setWindowStart(long windowStart) { this.windowStart = windowStart; }
}
public static class ClientReputation {
private final String clientIP;
private volatile int score;
private volatile String blockReason;
private volatile long lastUpdated;
public ClientReputation(String clientIP) {
this.clientIP = clientIP;
this.score = 0;
this.lastUpdated = System.currentTimeMillis();
}
public void adjustScore(int delta) {
this.score = Math.max(-200, Math.min(100, this.score + delta));
this.lastUpdated = System.currentTimeMillis();
}
public String getClientIP() { return clientIP; }
public int getScore() { return score; }
public void setScore(int score) { this.score = score; }
public String getBlockReason() { return blockReason; }
public void setBlockReason(String blockReason) { this.blockReason = blockReason; }
public long getLastUpdated() { return lastUpdated; }
}
public static class WAFEvent {
private final String clientIP;
private final String method;
private final String uri;
private final String action;
private final String details;
private final LocalDateTime timestamp;
public WAFEvent(String clientIP, String method, String uri, String action, String details, LocalDateTime timestamp) {
this.clientIP = clientIP;
this.method = method;
this.uri = uri;
this.action = action;
this.details = details;
this.timestamp = timestamp;
}
public String getClientIP() { return clientIP; }
public String getMethod() { return method; }
public String getUri() { return uri; }
public String getAction() { return action; }
public String getDetails() { return details; }
public LocalDateTime getTimestamp() { return timestamp; }
}
}
@@ -0,0 +1,508 @@
package com.aluer.security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicLong;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@Component
public class ZeroTrustArchitectureService {
private static final Logger logger = LoggerFactory.getLogger(ZeroTrustArchitectureService.class);
private final Map<String, TrustPolicy> policies = new ConcurrentHashMap<>();
private final Map<String, DeviceProfile> devices = new ConcurrentHashMap<>();
private final Map<String, UserContext> userContexts = new ConcurrentHashMap<>();
private final Map<String, AccessDecision> accessDecisions = new ConcurrentHashMap<>();
private final Queue<ZeroTrustEvent> eventLog = new ConcurrentLinkedQueue<>();
private final Map<String, List<VerificationResult>> verificationHistory = new ConcurrentHashMap<>();
private final AtomicLong totalAccessRequests = new AtomicLong(0);
private final AtomicLong grantedAccess = new AtomicLong(0);
private final AtomicLong deniedAccess = new AtomicLong(0);
private volatile boolean enabled = true;
private volatile String defaultPolicy = "DENY_ALL";
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private static final int MAX_HISTORY = 10000;
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public ZeroTrustArchitectureService() {
initializeDefaultPolicies();
startContinuousVerification();
logger.info("Zero Trust Architecture Service initialized");
}
private void initializeDefaultPolicies() {
addPolicy("DENY_ALL", "DENY", "Default deny all", 0, new ArrayList<>());
addPolicy("ALLOW_INTERNAL", "ALLOW", "Allow internal network", 100, Arrays.asList("10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"));
addPolicy("ALLOW_KNOWN_DEVICES", "CONDITIONAL", "Allow known devices with valid certs", 80, new ArrayList<>());
addPolicy("MFA_REQUIRED", "CONDITIONAL", "Require MFA for sensitive resources", 90, new ArrayList<>());
addPolicy("TIME_BASED_ACCESS", "CONDITIONAL", "Allow during business hours", 70, new ArrayList<>());
addPolicy("IP_REPUTATION_BASED", "CONDITIONAL", "Allow based on IP reputation", 85, new ArrayList<>());
addPolicy("DEVICE_HEALTH_CHECK", "CONDITIONAL", "Require healthy device", 75, new ArrayList<>());
addPolicy("LEAST_PRIVILEGE", "CONDITIONAL", "Grant minimum required access", 95, new ArrayList<>());
logger.info("Initialized {} trust policies", policies.size());
}
public void addPolicy(String name, String type, String description, int priority, List<String> conditions) {
TrustPolicy policy = new TrustPolicy(name, type, description, priority, conditions);
policies.put(name, policy);
}
public void addDevice(String deviceId, String type, String os, String macAddress, String owner) {
DeviceProfile device = new DeviceProfile(deviceId, type, os, macAddress, owner);
devices.put(deviceId, device);
logger.info("Added device to Zero Trust: {}", deviceId);
}
public AccessDecision evaluateAccess(String userId, String deviceId, String resource, String action, Map<String, Object> context) {
totalAccessRequests.incrementAndGet();
AccessDecision decision = new AccessDecision();
decision.setUserId(userId);
decision.setDeviceId(deviceId);
decision.setResource(resource);
decision.setAction(action);
decision.setTimestamp(LocalDateTime.now());
TrustPolicy policy = selectPolicy(userId, deviceId, resource);
if (policy == null) {
decision.setGranted(false);
decision.setReason("No matching policy found");
deniedAccess.incrementAndGet();
logEvent(userId, resource, "DENIED", "No matching policy");
return decision;
}
boolean deviceTrusted = verifyDevice(deviceId);
boolean userVerified = verifyUser(userId, context);
boolean contextSafe = verifyContext(context);
boolean resourceAccessible = checkResourceAccess(resource, action);
decision.setPolicyName(policy.getName());
decision.setDeviceTrusted(deviceTrusted);
decision.setUserVerified(userVerified);
decision.setContextSafe(contextSafe);
boolean shouldGrant = evaluatePolicyConditions(policy, deviceTrusted, userVerified, contextSafe, resourceAccessible);
decision.setGranted(shouldGrant);
if (shouldGrant) {
decision.setReason("Access granted by policy: " + policy.getName());
grantedAccess.incrementAndGet();
logEvent(userId, resource, "GRANTED", "Policy: " + policy.getName());
} else {
decision.setReason("Access denied - policy conditions not met");
deniedAccess.incrementAndGet();
logEvent(userId, resource, "DENIED", "Policy conditions not met");
}
accessDecisions.put(userId + ":" + resource + ":" + System.currentTimeMillis(), decision);
return decision;
}
private TrustPolicy selectPolicy(String userId, String deviceId, String resource) {
TrustPolicy matchedPolicy = null;
int highestPriority = -1;
for (TrustPolicy policy : policies.values()) {
if (matchesResource(resource, policy) && policy.getPriority() > highestPriority) {
matchedPolicy = policy;
highestPriority = policy.getPriority();
}
}
return matchedPolicy;
}
private boolean matchesResource(String resource, TrustPolicy policy) {
return true;
}
private boolean verifyDevice(String deviceId) {
DeviceProfile device = devices.get(deviceId);
if (device == null) {
return false;
}
boolean healthy = device.isHealthy();
boolean encrypted = device.isEncrypted();
boolean compliant = device.isCompliant();
return healthy && encrypted && compliant;
}
private boolean verifyUser(String userId, Map<String, Object> context) {
UserContext userContext = userContexts.get(userId);
if (userContext == null) {
return false;
}
boolean mfaVerified = userContext.isMfaVerified();
boolean sessionValid = userContext.isSessionValid();
return mfaVerified && sessionValid;
}
private boolean verifyContext(Map<String, Object> context) {
if (context == null) {
return false;
}
String location = (String) context.get("location");
String device = (String) context.get("device");
String network = (String) context.get("network");
if (location != null && location.equals("UNKNOWN")) {
return false;
}
if (network != null && network.equals("UNSECURED")) {
return false;
}
return true;
}
private boolean checkResourceAccess(String resource, String action) {
return true;
}
private boolean evaluatePolicyConditions(TrustPolicy policy, boolean deviceTrusted, boolean userVerified, boolean contextSafe, boolean resourceAccessible) {
switch (policy.getType()) {
case "ALLOW":
return resourceAccessible;
case "DENY":
return false;
case "CONDITIONAL":
if (policy.getName().equals("ALLOW_KNOWN_DEVICES")) {
return deviceTrusted && resourceAccessible;
}
if (policy.getName().equals("MFA_REQUIRED")) {
return userVerified && deviceTrusted && resourceAccessible;
}
if (policy.getName().equals("TIME_BASED_ACCESS")) {
return isBusinessHours() && resourceAccessible;
}
if (policy.getName().equals("DEVICE_HEALTH_CHECK")) {
return deviceTrusted && resourceAccessible;
}
return deviceTrusted && userVerified && contextSafe && resourceAccessible;
default:
return false;
}
}
private boolean isBusinessHours() {
int hour = LocalDateTime.now().getHour();
return hour >= 9 && hour <= 18;
}
public void updateUserContext(String userId, boolean mfaVerified, boolean sessionValid) {
UserContext context = userContexts.computeIfAbsent(userId, k -> new UserContext(userId));
context.setMfaVerified(mfaVerified);
context.setSessionValid(sessionValid);
}
public void updateDeviceStatus(String deviceId, boolean healthy, boolean encrypted, boolean compliant) {
DeviceProfile device = devices.get(deviceId);
if (device != null) {
device.setHealthy(healthy);
device.setEncrypted(encrypted);
device.setCompliant(compliant);
}
}
public void revokeAccess(String userId, String resource) {
logger.info("Revoking access for user {} to resource {}", userId, resource);
logEvent(userId, resource, "REVOKED", "Access revoked manually");
}
public void grantTemporaryAccess(String userId, String resource, int durationMinutes) {
logger.info("Granting temporary access for user {} to resource {} for {} minutes", userId, resource, durationMinutes);
logEvent(userId, resource, "TEMP_GRANTED", "Temporary access for " + durationMinutes + " minutes");
}
private void startContinuousVerification() {
scheduler.scheduleAtFixedRate(() -> {
verifyAllActiveSessions();
checkDeviceCompliance();
analyzeAccessPatterns();
}, 30, 30, TimeUnit.SECONDS);
}
private void verifyAllActiveSessions() {
for (UserContext context : userContexts.values()) {
if (context.isSessionValid()) {
boolean stillValid = verifySession(context.getUserId());
context.setSessionValid(stillValid);
}
}
}
private boolean verifySession(String userId) {
return true;
}
private void checkDeviceCompliance() {
for (DeviceProfile device : devices.values()) {
if (!device.isHealthy()) {
logger.warn("Device {} is not healthy", device.getDeviceId());
}
}
}
private void analyzeAccessPatterns() {
Map<String, Long> resourceAccessCount = new HashMap<>();
for (AccessDecision decision : accessDecisions.values()) {
if (decision.isGranted()) {
resourceAccessCount.merge(decision.getResource(), 1L, Long::sum);
}
}
for (Map.Entry<String, Long> entry : resourceAccessCount.entrySet()) {
if (entry.getValue() > 10000) {
logger.warn("High access volume for resource: {} ({} accesses)", entry.getKey(), entry.getValue());
}
}
}
public Map<String, Object> getStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("enabled", enabled);
stats.put("defaultPolicy", defaultPolicy);
stats.put("totalAccessRequests", totalAccessRequests.get());
stats.put("grantedAccess", grantedAccess.get());
stats.put("deniedAccess", deniedAccess.get());
stats.put("policiesConfigured", policies.size());
stats.put("registeredDevices", devices.size());
stats.put("activeUsers", userContexts.size());
double grantRate = totalAccessRequests.get() > 0 ?
grantedAccess.get() * 100.0 / totalAccessRequests.get() : 0;
stats.put("grantRate", String.format("%.2f%%", grantRate));
return stats;
}
public Map<String, TrustPolicy> getPolicies() {
return new HashMap<>(policies);
}
public Map<String, DeviceProfile> getDevices() {
return new HashMap<>(devices);
}
public List<AccessDecision> getRecentDecisions(int limit) {
List<AccessDecision> decisions = new ArrayList<>();
int count = 0;
for (AccessDecision decision : accessDecisions.values()) {
if (count++ >= limit) break;
decisions.add(decision);
}
return decisions;
}
public List<ZeroTrustEvent> getRecentEvents(int limit) {
List<ZeroTrustEvent> events = new ArrayList<>();
int count = 0;
for (ZeroTrustEvent event : eventLog) {
if (count++ >= limit) break;
events.add(event);
}
return events;
}
private void logEvent(String userId, String resource, String action, String details) {
ZeroTrustEvent event = new ZeroTrustEvent(userId, resource, action, details, LocalDateTime.now());
eventLog.offer(event);
if (eventLog.size() > 5000) {
eventLog.poll();
}
}
public void enable() {
enabled = true;
logger.info("Zero Trust Architecture enabled");
}
public void disable() {
enabled = false;
logger.info("Zero Trust Architecture disabled");
}
public static class TrustPolicy {
private final String name;
private final String type;
private final String description;
private final int priority;
private final List<String> conditions;
public TrustPolicy(String name, String type, String description, int priority, List<String> conditions) {
this.name = name;
this.type = type;
this.description = description;
this.priority = priority;
this.conditions = conditions;
}
public String getName() { return name; }
public String getType() { return type; }
public String getDescription() { return description; }
public int getPriority() { return priority; }
public List<String> getConditions() { return conditions; }
}
public static class DeviceProfile {
private final String deviceId;
private final String type;
private final String os;
private final String macAddress;
private final String owner;
private volatile boolean healthy = true;
private volatile boolean encrypted = true;
private volatile boolean compliant = true;
private volatile long lastChecked;
public DeviceProfile(String deviceId, String type, String os, String macAddress, String owner) {
this.deviceId = deviceId;
this.type = type;
this.os = os;
this.macAddress = macAddress;
this.owner = owner;
this.lastChecked = System.currentTimeMillis();
}
public String getDeviceId() { return deviceId; }
public String getType() { return type; }
public String getOs() { return os; }
public String getMacAddress() { return macAddress; }
public String getOwner() { return owner; }
public boolean isHealthy() { return healthy; }
public void setHealthy(boolean healthy) { this.healthy = healthy; }
public boolean isEncrypted() { return encrypted; }
public void setEncrypted(boolean encrypted) { this.encrypted = encrypted; }
public boolean isCompliant() { return compliant; }
public void setCompliant(boolean compliant) { this.compliant = compliant; }
public long getLastChecked() { return lastChecked; }
public void setLastChecked(long lastChecked) { this.lastChecked = lastChecked; }
}
public static class UserContext {
private final String userId;
private volatile boolean mfaVerified = false;
private volatile boolean sessionValid = false;
private volatile long lastActivity;
public UserContext(String userId) {
this.userId = userId;
this.lastActivity = System.currentTimeMillis();
}
public String getUserId() { return userId; }
public boolean isMfaVerified() { return mfaVerified; }
public void setMfaVerified(boolean mfaVerified) { this.mfaVerified = mfaVerified; }
public boolean isSessionValid() { return sessionValid; }
public void setSessionValid(boolean sessionValid) { this.sessionValid = sessionValid; }
public long getLastActivity() { return lastActivity; }
public void setLastActivity(long lastActivity) { this.lastActivity = lastActivity; }
}
public static class AccessDecision {
private String userId;
private String deviceId;
private String resource;
private String action;
private String policyName;
private boolean granted;
private String reason;
private boolean deviceTrusted;
private boolean userVerified;
private boolean contextSafe;
private LocalDateTime timestamp;
public String getUserId() { return userId; }
public void setUserId(String userId) { this.userId = userId; }
public String getDeviceId() { return deviceId; }
public void setDeviceId(String deviceId) { this.deviceId = deviceId; }
public String getResource() { return resource; }
public void setResource(String resource) { this.resource = resource; }
public String getAction() { return action; }
public void setAction(String action) { this.action = action; }
public String getPolicyName() { return policyName; }
public void setPolicyName(String policyName) { this.policyName = policyName; }
public boolean isGranted() { return granted; }
public void setGranted(boolean granted) { this.granted = granted; }
public String getReason() { return reason; }
public void setReason(String reason) { this.reason = reason; }
public boolean isDeviceTrusted() { return deviceTrusted; }
public void setDeviceTrusted(boolean deviceTrusted) { this.deviceTrusted = deviceTrusted; }
public boolean isUserVerified() { return userVerified; }
public void setUserVerified(boolean userVerified) { this.userVerified = userVerified; }
public boolean isContextSafe() { return contextSafe; }
public void setContextSafe(boolean contextSafe) { this.contextSafe = contextSafe; }
public LocalDateTime getTimestamp() { return timestamp; }
public void setTimestamp(LocalDateTime timestamp) { this.timestamp = timestamp; }
}
public static class VerificationResult {
private final String entityId;
private final String entityType;
private final boolean verified;
private final String details;
private final LocalDateTime timestamp;
public VerificationResult(String entityId, String entityType, boolean verified, String details) {
this.entityId = entityId;
this.entityType = entityType;
this.verified = verified;
this.details = details;
this.timestamp = LocalDateTime.now();
}
public String getEntityId() { return entityId; }
public String getEntityType() { return entityType; }
public boolean isVerified() { return verified; }
public String getDetails() { return details; }
public LocalDateTime getTimestamp() { return timestamp; }
}
public static class ZeroTrustEvent {
private final String userId;
private final String resource;
private final String action;
private final String details;
private final LocalDateTime timestamp;
public ZeroTrustEvent(String userId, String resource, String action, String details, LocalDateTime timestamp) {
this.userId = userId;
this.resource = resource;
this.action = action;
this.details = details;
this.timestamp = timestamp;
}
public String getUserId() { return userId; }
public String getResource() { return resource; }
public String getAction() { return action; }
public String getDetails() { return details; }
public LocalDateTime getTimestamp() { return timestamp; }
}
}