深度优化: 修复跨服务器登录、密码哈希、仪表盘UI、流量趋势等12项问题

### 严重修复
1. 跨服务器无法登录 - 新增SESSION_COOKIE_DOMAIN/SECURE/NAME配置
2. SOCKS5用户密码明文存储→bcrypt哈希(兼容自动迁移)
3. 仪表盘审计日志不显示→替换为空循环为真实API加载
4. 管理员登录防爆破未生效→auth.py集成check_fail2ban

### 中等问题修复
5. 流量趋势图表无数据→新增record_traffic_snapshot后台线程
6. 网络流量累计值跳变→新增基线差值机制
7. asyncio连接计数非线程安全→加锁保护

### 优化改进
8. API密钥页面截断文本修复
9. 新增gunicorn/bcrypt依赖
10. 更新README环境变量文档和生产建议
11. 登录密码常量时间对比防时序攻击
12. 仪表盘图表添加animation:false防卡顿
This commit is contained in:
Your Name
2026-07-16 22:13:14 +08:00
parent 00d9750662
commit 06470512f6
12 changed files with 186 additions and 27 deletions
+56 -3
View File
@@ -1,4 +1,5 @@
"""监控与统计服务。"""
import copy
import logging
import os
import psutil
@@ -14,13 +15,34 @@ log = logging.getLogger("socks.stats")
_metrics_buffer = deque(maxlen=600) # 10分钟 @ 10秒间隔
_metrics_lock = __import__("threading").Lock()
# 网络流量基线(用于计算会话增量)
_net_baseline = None
_net_baseline_lock = __import__("threading").Lock()
def _get_net_delta():
global _net_baseline
try:
net = psutil.net_io_counters()
current = {"bytes_sent": net.bytes_sent, "bytes_recv": net.bytes_recv}
with _net_baseline_lock:
if _net_baseline is None:
_net_baseline = copy.deepcopy(current)
return {"bytes_sent": 0, "bytes_recv": 0}
return {
"bytes_sent": current["bytes_sent"] - _net_baseline["bytes_sent"],
"bytes_recv": current["bytes_recv"] - _net_baseline["bytes_recv"],
}
except Exception:
return {"bytes_sent": 0, "bytes_recv": 0}
def _record_metrics():
"""记录系统级指标。"""
try:
cpu = psutil.cpu_percent(interval=0.5)
mem = psutil.virtual_memory()
net = psutil.net_io_counters()
net_delta = _get_net_delta()
# 计算活跃连接
with db.app.app_context():
active = db.session.query(Connection).filter_by(
@@ -32,8 +54,8 @@ def _record_metrics():
"mem_percent": mem.percent,
"mem_used_mb": mem.used // 1024 // 1024,
"mem_total_mb": mem.total // 1024 // 1024,
"net_bytes_sent": net.bytes_sent,
"net_bytes_recv": net.bytes_recv,
"net_bytes_sent": net_delta["bytes_sent"],
"net_bytes_recv": net_delta["bytes_recv"],
"active_connections": active,
}
with _metrics_lock:
@@ -195,3 +217,34 @@ def prune_old_data():
)
db.session.commit()
log.info("数据清理完成")
def record_traffic_snapshot():
"""记录每日流量快照(用于流量趋势图表)。"""
from datetime import date
today = date.today()
with db.app.app_context():
from sqlalchemy import func
today_start = datetime.now(timezone.utc).replace(hour=0, minute=0, second=0, microsecond=0)
result = db.session.query(
func.coalesce(func.sum(Connection.bytes_in), 0),
func.coalesce(func.sum(Connection.bytes_out), 0),
func.count(Connection.id),
).filter(Connection.started_at >= today_start).first()
total_in = result[0] if result else 0
total_out = result[1] if result else 0
total_conns = result[2] if result else 0
snap = db.session.query(TrafficSnapshot).filter_by(date=today).first()
if snap:
snap.bytes_in = total_in
snap.bytes_out = total_out
snap.connections = total_conns
else:
snap = TrafficSnapshot(
date=today, bytes_in=total_in, bytes_out=total_out,
connections=total_conns,
)
db.session.add(snap)
db.session.commit()
log.info("流量快照已记录: %s", today)