P2迭代: 危险命令检测 + DB会话合并 + API密钥修复 + 安全审计 (6项)

P2-14: agent.py _verify_api_key() 重写文档并明确两步验证逻辑,
       全局密钥匹配直接通过,非匹配密钥放行至handler做per-server验证
P2-15: websocket.py 删除已废弃的 connected_clients=[] 别名,
       health.py 已使用 manager.client_count
P2-16: webssh.py 合并4个AsyncSessionLocal()为1个共享session(预接受操作),
       命令日志保留独立session(长连接WebSocket不能持有单session)
P2-18: 新增危险命令检测 (check_dangerous_command),识别 rm -rf /、
       fork bomb、dd写裸设备、mkfs等模式,scripts.py + webssh.py集成
P2-19: install.py 状态文件不再存储db_pass明文(步骤5已删除文件),
       审计确认所有logger调用无敏感数据泄露
P2-17: httpOnly cookie迁移标记为延期(需前后端+WebSocket全面重构,
       当前JWT+updated_at+CORS限制方案已足够安全)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Your Name
2026-05-22 23:18:08 +08:00
parent d744d7df8e
commit 341d16fd6d
6 changed files with 108 additions and 73 deletions
+12 -13
View File
@@ -34,24 +34,23 @@ REDIS_ALERT_KEY_PREFIX = "alerts:"
def _verify_api_key(x_api_key: str = Header(...)):
"""Verify Agent API key from request header (global key check only)
"""Verify Agent API key — accepts either global or per-server key.
Per-server key verification is done in the endpoint handler after
we know the server_id from the payload.
For heartbeat endpoints, the global key is checked first; if it doesn't
match, the request is still allowed through so the handler can verify
the per-server key (which requires server_id from the payload).
NOTE: This function only checks the GLOBAL API key. Endpoints that
need per-server verification must also call _verify_server_api_key().
Any request with a key that doesn't match the global key is rejected
immediately — per-server keys are only valid for heartbeat endpoints
where the server_id is in the payload.
For strict global-only verification, use _verify_global_api_key instead.
"""
if not x_api_key:
raise HTTPException(status_code=401, detail="Missing API key")
if x_api_key != settings.API_KEY:
# For heartbeat endpoints, per-server keys are verified later
# in the handler after we know the server_id.
# For /exec endpoint, only the global API key is accepted.
pass # Allow through — per-server check happens in handler
# If the global key matches, allow immediately
if x_api_key == settings.API_KEY:
return x_api_key
# Non-matching key — allow through for per-server verification in handler.
# The handler MUST call _verify_server_api_key() before processing.
# This two-step approach is needed because server_id is in the payload,
# not the header, so per-server verification can't happen in a Depends().
return x_api_key