Files
Nexus/docs/archive/audits/2026-06-04-phase2-merged.md
T
2026-07-08 22:31:31 +08:00

238 lines
11 KiB
Markdown
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.
# Phase2 P2 合并卷
> 生成日期: 2026-06-04 · 源文件 9 篇 · 原文 `docs/archive/audits/2026-06-04-phase2/`
## 批次索引
### `audit-phase2-2026-06-04-waveP2-1.md`
# Phase 2 深审 — Wave P2-1Files / SSH 基础设施)
## 登记
## 入口表
## Closure 表
**len(H)=17, Closure=17**
## FINDING
无 P0/P1 新 FINDING。
## L3 门控(同日记录)
## DoD
- [x] len(H) == Closure
## 验证
### `audit-phase2-2026-06-04-waveP2-2.md`
# Phase 2 深审 — Wave P2-2sync_v2 全文 + 路径/Shell 依赖)
## 登记
## 入口表(sync_v2 全 22 路由)
## Closure 表
**len(H)=20, Closure=20**
## FINDING
无 P0/P1 新 FINDING。
## DoD
- [x] len(H) == Closure
## 验证
### `audit-phase2-2026-06-04-waveP2-3.md`
# Phase 2 深审 — Wave P2-3WebSocket / Dashboard 告警链)
## 登记
## 入口表
## Closure 表
**len(H)=16, Closure=16**
## FINDING
无 P0/P1 新 FINDING。
## DoD
- [x] len(H) == Closure
## 验证
### `audit-phase2-2026-06-04-waveP2-4.md`
# Phase 2 深审 — Wave P2-4servers.py 全文)
## 登记
## 入口表(servers.py 26 路由)
## Closure 表
**len(H)=20, Closure=20**
## FINDING
无 P0/P1 新 FINDING。
## DoD
- [x] len(H) == Closure
## 验证
### `audit-phase2-2026-06-04-waveP2-5.md`
# Phase 2 深审 — Wave P2-5webssh.py 全文)
## 登记
## 入口表
## Closure 表
**len(H)=17, Closure=17**
## FINDING
无 P0/P1 新 FINDING。
## DoD
- [x] len(H) == Closure
## 验证
### `audit-phase2-2026-06-04-waveP2-6.md`
# Phase 2 深审 — Wave P2-6sync_engine_v2.py 全文)
## 登记
## 入口表(服务层,经 sync_v2 API 调用)
## Closure 表
**len(H)=17, Closure=17**
## FINDING
无 P0/P1 新 FINDING。
## DoD
- [x] len(H) == Closure
## 验证
### `audit-phase2-2026-06-04-waveP2-7.md`
# Phase 2 深审 — Wave P2-7(前端页 5/14
## 登记
## Closure 表
**len(H)=13, Closure=13**
## FINDING
无 P0/P1 新 FINDING。
## DoD
### `audit-phase2-2026-06-04-waveP2-8.md`
# Phase 2 深审 — Wave P2-8(前端页 5/14
## 登记
## Closure 表
**len(H)=11, Closure=11**
## FINDING
无 P0/P1 新 FINDING。
### `audit-phase2-2026-06-04-waveP2-9.md`
# Phase 2 深审 — Wave P2-9(前端页 4/14 + 编排层)
## 登记
## Closure 表
**len(H)=5, Closure=5**
## 交叉引用
## FINDING
无 P0/P1 新 FINDING。
## Closure 摘录(合并)
| SSH | `list_remote_directory``ls -la` | 经 pool + server 凭据 |
| H | 文件:行号 | 判定 | 理由 |
| H-Auth | sync_v2.py:741614 | SAFE | 22 路由均 `Depends(get_current_admin)` |
| H-Shell | sync_v2.py:156-168 | RISK | `rm -rf` 删目录;JWT+审计+前端 confirm |
| H-Shell | sync_v2.py:156,165,168,223-227 | SAFE | path shlex.quote |
| H-Path | sync_v2.py:149-165 | SAFE | normalize_remote_abs_path |
| H-Clipboard | sync_v2.py:207-208 | SAFE | assert_clipboard_transfer_safe |
| H-Sandbox | sync_v2.py:302,341,413,721 | SAFE | ensure_under_nexus_upload |
| H-Source | sync_v2.py:548,1096 | SAFE | FORBIDDEN prefixes + resolve |
| H-Audit | sync_v2.py:461-475 | SAFE | 失败 log warning+exc_info,非静默 pass |
| H-Upload | sync_v2.py:876-877,977-978 | SAFE | 100MB / 500MB 上限 |
| H-ZipSlip | sync_v2.py:1000-1005 | SAFE | assert_zip + is_path_under_prefix |
| H-Download | sync_v2.py:1244-1272 | SAFE | 100MB + filename sanitize |
| H-Read | sync_v2.py:1322-1326 | SAFE | max_size 来自 payload |
| H-Write | sync_v2.py:1394-1414 | SAFE | 5MB + etag 409 冲突 |
| H-Chmod | sync_v2.py:1507-1514 | SAFE | recursive policy + test -d |
| H-Verify | sync_v2.py:1145-1146 | SAFE | sha256sum 路径 shlex.quote |
| H-Path | posix_paths.py:46-59 | SAFE | 禁 `..` 与反斜杠 |
| H-Path | posix_paths.py:117-136 | SAFE | upload 前缀 + zip-slip |
| H-Sudo | remote_shell.py:35-53 | SAFE | bash -c + shlex.quote(command) |
| H-Clipboard | remote_path_validation.py:24-33 | SAFE | dest 非源子树 |
| H-Parse | unix_ls.py:70-71 | SAFE | 跳过 `.` `..` |
| H-WS-Auth | websocket.py:304-311,340-347 | SAFE | 无 token → 4001;无效 → 4401 |
| H-WS-Token | websocket.py:366-410 | SAFE | tv/updated_at 与 HTTP JWT 一致 |
| H-WS-ADR011 | websocket.py:9,296 | RISK | query JWT;单人运维已接受 |
| H-WS-Limit | websocket.py:49-52 | SAFE | MAX_CONNECTIONS=500 |
| H-WS-Heartbeat | websocket.py:139-165 | SAFE | 30s ping / 60s zombie |
| H-WS-Channel | websocket.py:246-249,531-551 | SAFE | alerts 与 sync 分 channel/manager |
| H-WS-Dedup | websocket.py:416-437 | SAFE | Telegram 5min 冷却;WS 仍实时 |
| H-WS-Recovery | websocket.py:512-513 | SAFE | recovery 清 cooldown |
| H-Frontend-Token | useWebSocket.ts:61 | RISK | URL query token;同 ADR-011 |
| H-Frontend-Auth | useWebSocket.ts:114-116 | SAFE | 4001/4401 → forceLogout |
| H-Frontend-XSS | useWebSocket.ts:99-102 | SAFE | snackbar 文本插值,无 v-html |
| H-Frontend-Singleton | useWebSocket.ts:17-18 | SAFE | 模块级单例;App 统一 connect |
| H-Dashboard-Refresh | DashboardPage.vue:393-397 | SAFE | WS alert → reload stats/alerts |
| H-Dashboard-API | DashboardPage.vue:302-337 | SAFE | http JWT 拉 stats/alert-history |
| H-App-Lifecycle | App.vue:257-259 | SAFE | login connect / logout disconnect |
| H-Alert-API | settings.py:768-828 | SAFE | alert-history JWT + 参数化 filter |
| H-Auth | servers.py:26×路由 | SAFE | 26 端点均 `get_current_admin` |
| H-Mask | servers.py:1692-1698 | SAFE | password_set / agent key 前缀截断 |
| H-Encrypt | servers.py:1096-1099,559-562 | SAFE | Fernet encrypt 入库 |
| H-Allowlist | servers.py:1163-1187 | SAFE | UPDATE 字段白名单;agent_api_key 排除 |
| H-Reauth | servers.py:1256-1260,1479-1483 | SAFE | agent-key/install-cmd 需当前密码 |
| H-Reveal | servers.py:1492-1502 | SAFE | install-cmd 不用全局 API_KEY |
| H-AgentKey | servers.py:1282-1288 | SAFE | 生成后 display_once 响应 |
| H-Fallback | servers.py:626,1321 | RISK | batch/single install 可回退 settings.API_KEY |
| H-Shell | servers.py:631-633,1330-1332 | SAFE | install shlex.quote url/key/port |
| H-Sudo | servers.py:36-60 | RISK | 临时 sudoers 白名单;运维必要 |
| H-SudoPwd | servers.py:1025-1027 | SAFE | sudo -S 密码走 stdin 非 argv |
| H-CSV | servers.py:376-388,445-446 | SAFE | formula injection 防御 + 1MB 上限 |
| H-CSV | servers.py:499-501 | SAFE | MAX_IMPORT_ROWS=500 |
| H-Batch | servers.py:615,686,772,850 | SAFE | Semaphore(5) 并发上限 |
| H-Redis | servers.py:179-201,873-877 | SAFE | 心跳 overlay;失败 log warning |
| H-Audit | servers.py: CUD/batch | SAFE | 写操作 AuditLog |
| H-Crypto | crypto.py:20-26 | SAFE | 无 ENCRYPTION_KEY 则 RuntimeError |
| H-Crypto | crypto.py:52-54 | SAFE | decrypt 失败 raise,非静默 |
| H-Capability | files_capability.py:31-39 | SAFE | 只读 probe,无密码回传 |
| H-Elevation | files_elevation.py:48-55 | SAFE | apply_files_elevation_payload |
| H-Purpose | webssh.py:48-49 | SAFE | 拒绝非 webssh purpose |
| H-Bind | webssh.py:106-109 | SAFE | token server_id 须匹配路径 |
| H-TV | webssh.py:66-76 | SAFE | tv 校验;legacy updated_at +5s grace |
| H-Close | webssh.py:97-104 | SAFE | 缺 token→4001;无效→4401 |
| H-Issue | auth.py:334-346 | SAFE | 签发前 JWT + server/domain 校验 |
| H-Scope | auth_service.py:455-470 | SAFE | JWT 含 server_id + purpose + tv |
| H-Expire | auth_service.py:467 | SAFE | 15 分钟短期令牌 |
| H-WSQuery | webssh.py:88, useTerminalSessions:293 | RISK | ADR-011 query token(已接受) |
| H-Cred | webssh.py:126-135 | SAFE | key/password 配置检查 |
| H-Audit | webssh.py:137-146,353-366 | SAFE | connect/disconnect 审计 |
| H-Session | webssh.py:148-157,369-376 | SAFE | SshSession 创建/关闭 |
| H-DB | webssh.py:111-158 | SAFE | 长连接前关闭 DB session |
| H-Pool | webssh.py:167,337 | SAFE | acquire/release + stale retry |
| H-CmdLog | webssh.py:277-290,379-398 | SAFE | Enter 触发;2000 字符截断 |
| H-Danger | dependencies.py:167-180 | RISK | 危险命令仅 WARN 不阻断(设计) |
| H-Resize | webssh.py:293-296 | SAFE | cols/rows 边界默认 80×24 |
| H-Error | webssh.py:171,204 | SAFE | SSH 失败不向客户端泄露栈 |
| H-Source | sync_engine_v2.py:72-76,327-330 | SAFE | `_nexus_source_path` 拒绝系统路径 |
| H-Conc | sync_engine_v2.py:38,79-80 | SAFE | MAX_CONCURRENT=10 + min 入参 |
| H-DBLock | sync_engine_v2.py:89,149,190 | SAFE | `_db_lock` 串行写 sync_log/retry |
| H-Cancel | sync_engine_v2.py:96-136 | SAFE | Redis cancel flag;失败则继续 push |
| H-Retry | sync_engine_v2.py:193-224 | SAFE | 失败自动 pending retry;去重 |
| H-Subproc | sync_engine_v2.py:468-473 | SAFE | create_subprocess_exec 参数化 |
| H-Shlex | sync_engine_v2.py:456-458 | SAFE | key path shlex.quote |
| H-KeyTmp | sync_engine_v2.py:449-455,491-495 | SAFE | 0600 临时 key + finally unlink |
| H-Pass | sync_engine_v2.py:440-446 | RISK | sshpass -e/proc 可见(内网运维可接受) |
| H-Remote | sync_engine_v2.py:414 | SAFE | normalize_remote_abs_path |
| H-Timeout | sync_engine_v2.py:476-482 | SAFE | RSYNC_TIMEOUT+30 kill |
| H-Output | sync_engine_v2.py:486-487 | SAFE | stdout/stderr 截断 10KB |
| H-Staging | sync_engine_v2.py:498-516 | SAFE | 仅 manual 全成功才 rmtree staging |
| H-Preview | sync_engine_v2.py:364-365 | SAFE | verbose 文件列表上限 200 |
| H-Audit | sync_engine_v2.py:267-271,380-391 | SAFE | sync_files 审计;失败 log error |
| H-TG | sync_engine_v2.py:274-291 | SAFE | Telegram 失败不阻断 |
| H-Gather | sync_engine_v2.py:254-265 | SAFE | gather 异常计入 failed |
| H-JWT | 各页 http.* | SAFE | 经 `@/api` JWT 客户端 |
| H-WS | DashboardPage:393-397 | RISK | useWebSocket query token(已接受) |
| H-Nav | DashboardPage:383-387 | SAFE | server_id 数字 query 路由 |
| H-Err | DashboardPage:268-345 | SAFE | load 失败 snackbar |
| H-CSV | ServersPage:391-435 | SAFE | import FormDataexport 无密码列 |
| H-Batch | ServersPage:325-388 | SAFE | batch 端点 JWTconfirm 删除 |
| H-Form | ServersPage:162-176 | SAFE | 凭据经 ServerFormDialog composable |
| H-Filter | AlertsPage:150-162 | SAFE | 只读分页 API |
| H-Audit | AuditPage:126-141 | SAFE | 只读;normalizeAuditList |
| H-TG | SettingsPage:272-275 | SAFE | GET 不返 token 明文;value_set |
| H-Reveal | SettingsPage:434-460 | SAFE | API Key/TG reveal 需 current_password |
| H-Pw | SettingsPage:339-359 | SAFE | 改密 POST;表单 type=password |
| H-TOTP | SettingsPage:362-404 | SAFE | setup/enable/disable 走 auth API |
| H-CredList | CredentialsPage:253-255 | SAFE | GET 列表无密码明文 |
| H-CredPost | CredentialsPage:323-327 | SAFE | encrypted_pw 仅 POST/PUT |
| H-CredEdit | CredentialsPage:306,340,357 | SAFE | 编辑留空不修改 |
| H-SSH | CredentialsPage:346-347 | SAFE | 私钥仅提交时传输 |
| H-Cron | SchedulesPage:177 | SAFE | cron 正则校验 |
| H-Sched | SchedulesPage:173-180 | SAFE | 路径/服务器必填 |
| H-Retry | RetriesPage:146 | SAFE | retry POST JWT |
| H-CmdView | CommandsPage:139-153 | SAFE | 只读 command-logs/sessions |
| H-ScriptExec | ScriptsPage:415-419,463-467 | SAFE | exec 走后端 JWT |
| H-Quick | ScriptsPage:459-467 | RISK | 临时命令;后端 check_dangerous |
| H-Poll | ScriptsPage:527-528 | SAFE | onUnmounted stopPolling |
| H-FilesShell | FilesPage.vue:33-37 | SAFE | 逻辑在 useFilesPageD5 |
| H-PushShell | PushPage.vue:105 | SAFE | usePushPageD4 |
| H-TermShell | TerminalPage.vue | SAFE | useTerminalSessionsD5 |
| H-Login | LoginPage.vue | SAFE | auth.login 内存 tokenD6 |
| H-NoStore | 四页 | SAFE | 无 localStorage 存密码 |