EG/plugins/user/server_architecture/security/security_manager.py
2025-12-12 16:16:15 +08:00

892 lines
30 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
安全管理系统模块
负责处理认证、授权和防止攻击
"""
import time
import hashlib
import secrets
import hmac
from typing import Dict, Any, List, Optional
class SecurityManager:
"""
安全管理器
负责处理认证、授权和防止攻击
"""
def __init__(self, plugin):
"""
初始化安全管理器
Args:
plugin: 服务器架构插件实例
"""
self.plugin = plugin
self.enabled = False
self.initialized = False
# 安全配置
self.security_config = {
"enable_authentication": True,
"enable_encryption": False,
"enable_message_authentication": True,
"enable_rate_limiting": True,
"enable_ddos_protection": True,
"enable_session_management": True,
"session_timeout": 3600, # 1小时
"max_login_attempts": 5,
"login_lockout_duration": 900, # 15分钟
"enable_ip_filtering": True,
"enable_captcha": False,
"captcha_threshold": 10,
"password_min_length": 8,
"password_require_complexity": True,
"enable_two_factor_auth": False,
"token_lifetime": 86400, # 24小时
"enable_audit_logging": True
}
# 安全状态
self.security_state = {
"active_sessions": {},
"blocked_ips": {},
"login_attempts": {},
"security_events": [],
"last_security_check": 0.0
}
# 安全统计
self.security_stats = {
"successful_authentications": 0,
"failed_authentications": 0,
"blocked_connections": 0,
"security_events": 0,
"active_sessions": 0,
"errors": 0
}
# 密钥管理
self.secret_key = self._generate_secret_key()
self.session_keys = {}
# 回调函数
self.security_callbacks = {
"authentication_success": [],
"authentication_failed": [],
"session_created": [],
"session_expired": [],
"security_violation": [],
"ip_blocked": []
}
# 时间戳记录
self.last_security_event = 0.0
self.last_session_cleanup = 0.0
print("✓ 安全管理器已创建")
def initialize(self) -> bool:
"""
初始化安全管理器
Returns:
是否初始化成功
"""
try:
print("正在初始化安全管理器...")
# 生成密钥
self.secret_key = self._generate_secret_key()
self.initialized = True
print("✓ 安全管理器初始化完成")
return True
except Exception as e:
print(f"✗ 安全管理器初始化失败: {e}")
self.security_stats["errors"] += 1
import traceback
traceback.print_exc()
return False
def _generate_secret_key(self) -> str:
"""
生成密钥
Returns:
生成的密钥
"""
try:
return secrets.token_hex(32)
except Exception as e:
print(f"✗ 密钥生成失败: {e}")
# 使用默认密钥(仅用于开发环境)
return "default_secret_key_for_development_purposes_only"
def enable(self) -> bool:
"""
启用安全管理器
Returns:
是否启用成功
"""
try:
if not self.initialized:
print("✗ 安全管理器未初始化")
return False
self.enabled = True
print("✓ 安全管理器已启用")
return True
except Exception as e:
print(f"✗ 安全管理器启用失败: {e}")
self.security_stats["errors"] += 1
import traceback
traceback.print_exc()
return False
def disable(self):
"""禁用安全管理器"""
try:
self.enabled = False
# 清理会话
self.security_state["active_sessions"].clear()
self.session_keys.clear()
print("✓ 安全管理器已禁用")
except Exception as e:
print(f"✗ 安全管理器禁用失败: {e}")
self.security_stats["errors"] += 1
import traceback
traceback.print_exc()
def finalize(self):
"""清理安全管理器资源"""
try:
# 禁用安全管理器
if self.enabled:
self.disable()
# 清理回调
self.security_callbacks.clear()
self.initialized = False
print("✓ 安全管理器资源已清理")
except Exception as e:
print(f"✗ 安全管理器资源清理失败: {e}")
import traceback
traceback.print_exc()
def update(self, dt: float):
"""
更新安全管理器状态
Args:
dt: 时间增量(秒)
"""
try:
if not self.enabled:
return
current_time = time.time()
# 定期清理过期会话
if current_time - self.last_session_cleanup > 300: # 每5分钟清理一次
self._cleanup_expired_sessions(current_time)
self.last_session_cleanup = current_time
# 定期清理登录尝试记录
self._cleanup_login_attempts(current_time)
self.security_state["last_security_check"] = current_time
except Exception as e:
print(f"✗ 安全管理器更新失败: {e}")
self.security_stats["errors"] += 1
import traceback
traceback.print_exc()
def _cleanup_expired_sessions(self, current_time: float):
"""清理过期会话"""
try:
expired_sessions = []
for session_id, session_data in self.security_state["active_sessions"].items():
if current_time - session_data["login_time"] > self.security_config["session_timeout"]:
expired_sessions.append(session_id)
for session_id in expired_sessions:
del self.security_state["active_sessions"][session_id]
if session_id in self.session_keys:
del self.session_keys[session_id]
self.security_stats["active_sessions"] -= 1
# 触发会话过期回调
self._trigger_security_callback("session_expired", {
"session_id": session_id,
"timestamp": current_time
})
except Exception as e:
print(f"✗ 过期会话清理失败: {e}")
self.security_stats["errors"] += 1
def _cleanup_login_attempts(self, current_time: float):
"""清理登录尝试记录"""
try:
expired_attempts = []
for ip_address, attempt_data in self.security_state["login_attempts"].items():
if current_time - attempt_data["last_attempt"] > self.security_config["login_lockout_duration"]:
expired_attempts.append(ip_address)
for ip_address in expired_attempts:
del self.security_state["login_attempts"][ip_address]
except Exception as e:
print(f"✗ 登录尝试记录清理失败: {e}")
self.security_stats["errors"] += 1
def authenticate_client(self, client_id: str, auth_data: Dict[str, Any], client_address: tuple) -> bool:
"""
认证客户端
Args:
client_id: 客户端ID
auth_data: 认证数据
client_address: 客户端地址
Returns:
是否认证成功
"""
try:
if not self.enabled or not self.security_config["enable_authentication"]:
# 如果未启用认证,直接通过
return True
client_ip = client_address[0] if isinstance(client_address, tuple) else str(client_address)
# 检查IP是否被阻止
if self._is_ip_blocked(client_ip):
self.security_stats["blocked_connections"] += 1
return False
# 检查登录尝试次数
if self._is_login_blocked(client_ip):
self.security_stats["blocked_connections"] += 1
return False
# 执行认证
auth_result = self._perform_authentication(client_id, auth_data, client_address)
if auth_result:
self.security_stats["successful_authentications"] += 1
# 触发认证成功回调
self._trigger_security_callback("authentication_success", {
"client_id": client_id,
"client_address": client_address,
"timestamp": time.time()
})
# 记录安全事件
self._log_security_event("authentication_success", client_id, client_address)
else:
self.security_stats["failed_authentications"] += 1
# 记录失败的登录尝试
self._record_failed_login(client_ip)
# 触发认证失败回调
self._trigger_security_callback("authentication_failed", {
"client_id": client_id,
"client_address": client_address,
"timestamp": time.time()
})
# 记录安全事件
self._log_security_event("authentication_failed", client_id, client_address)
return auth_result
except Exception as e:
print(f"✗ 客户端认证失败: {e}")
self.security_stats["errors"] += 1
return False
def _is_ip_blocked(self, client_ip: str) -> bool:
"""
检查IP是否被阻止
Args:
client_ip: 客户端IP
Returns:
IP是否被阻止
"""
try:
if not self.security_config["enable_ip_filtering"]:
return False
if client_ip in self.security_state["blocked_ips"]:
block_data = self.security_state["blocked_ips"][client_ip]
if time.time() - block_data["block_time"] < block_data["duration"]:
return True
else:
# 阻止时间已过期,移除
del self.security_state["blocked_ips"][client_ip]
return False
except Exception as e:
print(f"✗ IP阻止检查失败: {e}")
self.security_stats["errors"] += 1
return False
def _is_login_blocked(self, client_ip: str) -> bool:
"""
检查登录是否被阻止
Args:
client_ip: 客户端IP
Returns:
登录是否被阻止
"""
try:
if client_ip in self.security_state["login_attempts"]:
attempts = self.security_state["login_attempts"][client_ip]
if (attempts["count"] >= self.security_config["max_login_attempts"] and
time.time() - attempts["last_attempt"] < self.security_config["login_lockout_duration"]):
return True
return False
except Exception as e:
print(f"✗ 登录阻止检查失败: {e}")
self.security_stats["errors"] += 1
return False
def _record_failed_login(self, client_ip: str):
"""
记录失败的登录尝试
Args:
client_ip: 客户端IP
"""
try:
current_time = time.time()
if client_ip not in self.security_state["login_attempts"]:
self.security_state["login_attempts"][client_ip] = {
"count": 1,
"last_attempt": current_time
}
else:
self.security_state["login_attempts"][client_ip]["count"] += 1
self.security_state["login_attempts"][client_ip]["last_attempt"] = current_time
# 如果超过最大尝试次数阻止IP
if (self.security_state["login_attempts"][client_ip]["count"] >=
self.security_config["max_login_attempts"]):
self._block_ip(client_ip, self.security_config["login_lockout_duration"])
except Exception as e:
print(f"✗ 失败登录记录失败: {e}")
self.security_stats["errors"] += 1
def _perform_authentication(self, client_id: str, auth_data: Dict[str, Any], client_address: tuple) -> bool:
"""
执行认证
Args:
client_id: 客户端ID
auth_data: 认证数据
client_address: 客户端地址
Returns:
是否认证成功
"""
try:
# 检查认证类型
auth_type = auth_data.get("auth_type", "token")
if auth_type == "token":
return self._authenticate_with_token(client_id, auth_data, client_address)
elif auth_type == "password":
return self._authenticate_with_password(client_id, auth_data, client_address)
elif auth_type == "session":
return self._authenticate_with_session(client_id, auth_data, client_address)
else:
# 默认认证方式
return self._authenticate_with_token(client_id, auth_data, client_address)
except Exception as e:
print(f"✗ 认证执行失败: {e}")
self.security_stats["errors"] += 1
return False
def _authenticate_with_token(self, client_id: str, auth_data: Dict[str, Any], client_address: tuple) -> bool:
"""
使用令牌认证
Args:
client_id: 客户端ID
auth_data: 认证数据
client_address: 客户端地址
Returns:
是否认证成功
"""
try:
token = auth_data.get("token")
if not token:
return False
# 验证令牌(简化实现)
# 在实际应用中,这里应该连接到用户数据库验证令牌
if token == "valid_test_token":
# 创建会话
self._create_session(client_id, auth_data, client_address)
return True
else:
return False
except Exception as e:
print(f"✗ 令牌认证失败: {e}")
self.security_stats["errors"] += 1
return False
def _authenticate_with_password(self, client_id: str, auth_data: Dict[str, Any], client_address: tuple) -> bool:
"""
使用密码认证
Args:
client_id: 客户端ID
auth_data: 认证数据
client_address: 客户端地址
Returns:
是否认证成功
"""
try:
username = auth_data.get("username")
password = auth_data.get("password")
if not username or not password:
return False
# 验证密码(简化实现)
# 在实际应用中,这里应该连接到用户数据库验证用户名和密码
if username == "test_user" and password == "test_password":
# 创建会话
self._create_session(client_id, auth_data, client_address)
return True
else:
return False
except Exception as e:
print(f"✗ 密码认证失败: {e}")
self.security_stats["errors"] += 1
return False
def _authenticate_with_session(self, client_id: str, auth_data: Dict[str, Any], client_address: tuple) -> bool:
"""
使用会话认证
Args:
client_id: 客户端ID
auth_data: 认证数据
client_address: 客户端地址
Returns:
是否认证成功
"""
try:
session_id = auth_data.get("session_id")
if not session_id:
return False
# 检查会话是否存在且有效
if session_id in self.security_state["active_sessions"]:
session_data = self.security_state["active_sessions"][session_id]
if time.time() - session_data["login_time"] < self.security_config["session_timeout"]:
# 更新会话最后活动时间
session_data["last_activity"] = time.time()
return True
return False
except Exception as e:
print(f"✗ 会话认证失败: {e}")
self.security_stats["errors"] += 1
return False
def _create_session(self, client_id: str, auth_data: Dict[str, Any], client_address: tuple):
"""
创建会话
Args:
client_id: 客户端ID
auth_data: 认证数据
client_address: 客户端地址
"""
try:
session_id = self._generate_session_id()
session_data = {
"client_id": client_id,
"client_address": client_address,
"login_time": time.time(),
"last_activity": time.time(),
"user_id": auth_data.get("user_id", ""),
"username": auth_data.get("username", ""),
"permissions": auth_data.get("permissions", [])
}
self.security_state["active_sessions"][session_id] = session_data
self.security_stats["active_sessions"] += 1
# 生成会话密钥
if self.security_config["enable_encryption"]:
self.session_keys[session_id] = self._generate_session_key()
# 触发会话创建回调
self._trigger_security_callback("session_created", {
"session_id": session_id,
"client_id": client_id,
"client_address": client_address,
"timestamp": time.time()
})
except Exception as e:
print(f"✗ 会话创建失败: {e}")
self.security_stats["errors"] += 1
def _generate_session_id(self) -> str:
"""
生成会话ID
Returns:
生成的会话ID
"""
try:
return secrets.token_urlsafe(32)
except Exception as e:
print(f"✗ 会话ID生成失败: {e}")
self.security_stats["errors"] += 1
return f"session_{int(time.time() * 1000000)}"
def _generate_session_key(self) -> str:
"""
生成会话密钥
Returns:
生成的会话密钥
"""
try:
return secrets.token_hex(16)
except Exception as e:
print(f"✗ 会话密钥生成失败: {e}")
self.security_stats["errors"] += 1
return f"key_{int(time.time() * 1000000)}"
def validate_token(self, token: str) -> bool:
"""
验证令牌
Args:
token: 令牌
Returns:
令牌是否有效
"""
try:
if not token:
return False
# 简化实现:检查令牌格式
# 在实际应用中,这里应该连接到令牌数据库验证令牌
return len(token) > 10 and token.isalnum()
except Exception as e:
print(f"✗ 令牌验证失败: {e}")
self.security_stats["errors"] += 1
return False
def hash_password(self, password: str, salt: str = None) -> Dict[str, str]:
"""
哈希密码
Args:
password: 密码
salt: 盐值(可选)
Returns:
包含哈希值和盐值的字典
"""
try:
if salt is None:
salt = secrets.token_hex(16)
# 使用PBKDF2哈希密码
password_hash = hashlib.pbkdf2_hmac('sha256', password.encode('utf-8'), salt.encode('utf-8'), 100000)
return {
"hash": password_hash.hex(),
"salt": salt
}
except Exception as e:
print(f"✗ 密码哈希失败: {e}")
self.security_stats["errors"] += 1
return {}
def verify_password(self, password: str, password_hash: str, salt: str) -> bool:
"""
验证密码
Args:
password: 密码
password_hash: 密码哈希值
salt: 盐值
Returns:
密码是否正确
"""
try:
# 重新哈希密码
new_hash = hashlib.pbkdf2_hmac('sha256', password.encode('utf-8'), salt.encode('utf-8'), 100000)
return hmac.compare_digest(new_hash.hex(), password_hash)
except Exception as e:
print(f"✗ 密码验证失败: {e}")
self.security_stats["errors"] += 1
return False
def _block_ip(self, client_ip: str, duration: float):
"""
阻止IP地址
Args:
client_ip: 客户端IP
duration: 阻止持续时间(秒)
"""
try:
self.security_state["blocked_ips"][client_ip] = {
"block_time": time.time(),
"duration": duration
}
# 触发IP阻止回调
self._trigger_security_callback("ip_blocked", {
"ip_address": client_ip,
"duration": duration,
"timestamp": time.time()
})
# 记录安全事件
self._log_security_event("ip_blocked", None, client_ip)
print(f"✓ IP地址已被阻止: {client_ip} (持续 {duration} 秒)")
except Exception as e:
print(f"✗ IP阻止失败: {e}")
self.security_stats["errors"] += 1
def unblock_ip(self, client_ip: str) -> bool:
"""
解除IP阻止
Args:
client_ip: 客户端IP
Returns:
是否解除成功
"""
try:
if client_ip in self.security_state["blocked_ips"]:
del self.security_state["blocked_ips"][client_ip]
print(f"✓ IP地址阻止已解除: {client_ip}")
return True
else:
print(f"✗ IP地址未被阻止: {client_ip}")
return False
except Exception as e:
print(f"✗ IP阻止解除失败: {e}")
self.security_stats["errors"] += 1
return False
def _log_security_event(self, event_type: str, client_id: str = None, client_address=None):
"""
记录安全事件
Args:
event_type: 事件类型
client_id: 客户端ID可选
client_address: 客户端地址(可选)
"""
try:
if not self.security_config["enable_audit_logging"]:
return
event = {
"event_type": event_type,
"client_id": client_id,
"client_address": client_address,
"timestamp": time.time()
}
self.security_state["security_events"].append(event)
self.security_stats["security_events"] += 1
# 保持事件列表大小
if len(self.security_state["security_events"]) > 1000:
self.security_state["security_events"] = self.security_state["security_events"][-1000:]
self.last_security_event = time.time()
except Exception as e:
print(f"✗ 安全事件记录失败: {e}")
self.security_stats["errors"] += 1
def get_active_sessions(self) -> Dict[str, Any]:
"""
获取活跃会话
Returns:
活跃会话字典
"""
try:
return self.security_state["active_sessions"].copy()
except Exception as e:
print(f"✗ 获取活跃会话失败: {e}")
self.security_stats["errors"] += 1
return {}
def get_blocked_ips(self) -> Dict[str, Any]:
"""
获取被阻止的IP地址
Returns:
被阻止的IP地址字典
"""
try:
return self.security_state["blocked_ips"].copy()
except Exception as e:
print(f"✗ 获取被阻止的IP地址失败: {e}")
self.security_stats["errors"] += 1
return {}
def get_security_stats(self) -> Dict[str, Any]:
"""
获取安全统计信息
Returns:
安全统计字典
"""
return {
"state": self.security_state.copy(),
"stats": self.security_stats.copy(),
"config": self.security_config.copy()
}
def reset_stats(self):
"""重置安全统计信息"""
try:
self.security_stats = {
"successful_authentications": 0,
"failed_authentications": 0,
"blocked_connections": 0,
"security_events": 0,
"active_sessions": 0,
"errors": 0
}
print("✓ 安全统计信息已重置")
except Exception as e:
print(f"✗ 安全统计信息重置失败: {e}")
def set_security_config(self, config: Dict[str, Any]) -> bool:
"""
设置安全配置
Args:
config: 安全配置字典
Returns:
是否设置成功
"""
try:
self.security_config.update(config)
print(f"✓ 安全配置已更新: {self.security_config}")
return True
except Exception as e:
print(f"✗ 安全配置设置失败: {e}")
return False
def get_security_config(self) -> Dict[str, Any]:
"""
获取安全配置
Returns:
安全配置字典
"""
return self.security_config.copy()
def _trigger_security_callback(self, callback_type: str, data: Dict[str, Any]):
"""
触发安全回调
Args:
callback_type: 回调类型
data: 回调数据
"""
try:
if callback_type in self.security_callbacks:
for callback in self.security_callbacks[callback_type]:
try:
callback(data)
except Exception as e:
print(f"✗ 安全回调执行失败: {callback_type} - {e}")
except Exception as e:
print(f"✗ 安全回调触发失败: {e}")
def register_security_callback(self, callback_type: str, callback: callable):
"""
注册安全回调
Args:
callback_type: 回调类型
callback: 回调函数
"""
try:
if callback_type in self.security_callbacks:
self.security_callbacks[callback_type].append(callback)
print(f"✓ 安全回调已注册: {callback_type}")
else:
print(f"✗ 无效的回调类型: {callback_type}")
except Exception as e:
print(f"✗ 安全回调注册失败: {e}")
def unregister_security_callback(self, callback_type: str, callback: callable):
"""
注销安全回调
Args:
callback_type: 回调类型
callback: 回调函数
"""
try:
if callback_type in self.security_callbacks:
if callback in self.security_callbacks[callback_type]:
self.security_callbacks[callback_type].remove(callback)
print(f"✓ 安全回调已注销: {callback_type}")
else:
print(f"✗ 无效的回调类型: {callback_type}")
except Exception as e:
print(f"✗ 安全回调注销失败: {e}")