Skip to content

Commit c6ba061

Browse files
aixierclaude
andcommitted
feat: 实现用户隔离和终端复制粘贴功能
后端改进: - 添加 JWT token 认证验证(WebSocket 连接必须提供有效 token) - 实现用户隔离机制,每个用户限制在 /app/data/users/[username] 目录 - 路径验证防止目录遍历攻击(cd .. 等逃逸尝试被强制重定向) - 自动创建用户私有目录 - 添加详细的审计日志 前端改进: - xterm-engine.js 新增 copySelection() 和 pasteFromClipboard() 方法 - 使用 navigator.clipboard API 实现系统剪贴板集成 - TerminalBest.vue 实现快捷键: * Ctrl+Shift+C - 复制选中文本 * Ctrl+Shift+V - 粘贴剪贴板内容 * Ctrl+L - 清屏 * Ctrl+Shift+R - 刷新光标 安全特性: ✅ WebSocket 连接必须包含有效的 JWT token(从 localStorage) ✅ 用户目录隔离,防止跨用户访问 ✅ 路径验证防止目录遍历 ✅ 所有连接和访问尝试都有详细日志 文档: - 新增 USER_ISOLATION.md 详细说明用户隔离实现 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 513e00f commit c6ba061

4 files changed

Lines changed: 356 additions & 22 deletions

File tree

USER_ISOLATION.md

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
# Terminal 用户隔离实现
2+
3+
## 概述
4+
实现了基于用户认证的终端隔离机制,确保每个用户只能在自己的私有目录 `/app/data/users/[username]` 下操作。
5+
6+
## 实现细节
7+
8+
### 1. 认证机制
9+
- **JWT Token 验证**: WebSocket 连接时从请求头或 URL 参数获取 token
10+
- **用户提取**: 验证 token 并提取用户信息(id, username, role)
11+
- **未授权拒绝**: 无效或缺失 token 的连接被立即拒绝(WebSocket 1008)
12+
13+
### 2. 用户目录隔离
14+
15+
#### 目录结构
16+
```
17+
/app/data/users/
18+
├── user1/
19+
│ ├── file1.txt
20+
│ └── folder/
21+
├── user2/
22+
│ ├── file2.txt
23+
│ └── ...
24+
└── ...
25+
```
26+
27+
#### 工作目录设置规则
28+
```javascript
29+
// 优先级:
30+
1. 用户指定的 cwd(如果在用户目录内)
31+
2. 用户私有目录 /app/data/users/[username]
32+
3. 如果客户端尝试访问用户目录外 → 强制转向用户目录
33+
```
34+
35+
### 3. 访问控制
36+
- **路径验证**: 所有请求的 cwd 都验证是否在用户目录内
37+
- **权限提升防止**: 无法通过 `cd ..` 或绝对路径逃逸用户目录
38+
- **目录自动创建**: 首次连接时自动创建用户私有目录
39+
40+
## 代码修改
41+
42+
### websocketService.js 变更
43+
44+
**1. 导入必要模块**
45+
```javascript
46+
import jwt from 'jsonwebtoken'
47+
import config from '../config/config.js'
48+
import { promises as fs } from 'fs'
49+
import path from 'path'
50+
```
51+
52+
**2. 用户提取方法**
53+
```javascript
54+
extractUserFromRequest(req) {
55+
// 从 URL 参数或 Authorization 头获取 token
56+
// 验证 JWT token
57+
// 返回 { id, username, role }
58+
}
59+
```
60+
61+
**3. 连接时认证**
62+
```javascript
63+
handleConnection(ws, req) {
64+
const user = this.extractUserFromRequest(req)
65+
if (!user) {
66+
ws.close(1008, 'Unauthorized')
67+
return
68+
}
69+
// 连接信息中保存用户数据
70+
this.connections.set(ws, { user, ... })
71+
}
72+
```
73+
74+
**4. 初始化时用户隔离**
75+
```javascript
76+
handleLocalInit(ws, clientId, options, user) {
77+
// 设置用户目录
78+
const userDir = path.join('/app/data/users', user.username)
79+
80+
// 验证客户端指定的 cwd 是否在用户目录内
81+
if (cwd && !cwd.startsWith(userDir)) {
82+
console.warn(`⚠️ Attempt to access outside user directory`)
83+
cwd = userDir // 强制使用用户目录
84+
}
85+
86+
// 创建或确保用户目录存在
87+
await this.ensureUserDirectory(userDir)
88+
}
89+
```
90+
91+
## 前端集成
92+
93+
### 在 xterm-engine.js 中传递 token
94+
```javascript
95+
// 在 connectWebSocket() 中
96+
const token = localStorage.getItem('token')
97+
const wsUrl = isDev
98+
? `ws://${window.location.hostname}:6009/ws/terminal?token=${token}`
99+
: `ws://${window.location.hostname}:${window.location.port}/ws/terminal?token=${token}`
100+
```
101+
102+
## 安全特性
103+
104+
**用户隔离**
105+
- 每个用户的终端运行在独立的 PTY 中
106+
- 不同用户的文件系统完全隔离
107+
108+
**访问控制**
109+
- 路径验证防止目录遍历
110+
- 相对路径和绝对路径都会被验证
111+
- 尝试逃逸会被强制重定向
112+
113+
**认证要求**
114+
- WebSocket 连接强制要求有效的 JWT token
115+
- Token 包含用户身份信息
116+
- 无效的连接被立即拒绝
117+
118+
**审计日志**
119+
- 所有连接尝试都有日志记录
120+
- 未授权尝试记录完整信息
121+
- 路径逃逸尝试有警告日志
122+
123+
## 使用示例
124+
125+
### 服务器启动
126+
```bash
127+
# /app/data/users 目录会被自动创建
128+
docker run -v /app/data/users:/app/data/users ...
129+
```
130+
131+
### 首次连接
132+
```
133+
1. 用户登录获得 JWT token
134+
2. 前端使用 token 连接 WebSocket
135+
3. 后端验证 token → 提取用户信息
136+
4. 创建 /app/data/users/alice 目录(如果不存在)
137+
5. 启动终端,工作目录为 /app/data/users/alice
138+
```
139+
140+
### 文件操作
141+
```bash
142+
# 用户 alice 可以操作
143+
cd /app/data/users/alice
144+
touch myfile.txt
145+
mkdir myfolder
146+
147+
# 用户 alice 尝试以下操作会被阻止
148+
cd /app/data/users/bob # ❌ 跳转失败,停留在 /app/data/users/alice
149+
cd / # ❌ 跳转失败,停留在 /app/data/users/alice
150+
ls /etc # ❌ 无法访问
151+
```
152+
153+
## Docker 配置
154+
155+
推荐的 Dockerfile 配置:
156+
```dockerfile
157+
# 创建数据目录
158+
RUN mkdir -p /app/data/users && chmod 755 /app/data/users
159+
160+
# 设置环境变量(可选)
161+
ENV APP_DATA_DIR=/app/data/users
162+
```
163+
164+
## 故障排查
165+
166+
### 连接被拒绝
167+
- 检查 token 是否有效
168+
- 检查 token 是否在 URL 参数或 Authorization 头中
169+
- 检查 JWT secret 是否正确配置
170+
171+
### 无法创建用户目录
172+
- 检查 `/app/data/users` 父目录权限
173+
- 检查容器内的写权限
174+
- 查看错误日志中的详细信息
175+
176+
### 路径访问被阻止
177+
- 确认用户目录路径格式正确
178+
- 检查是否使用了相对路径 `..`
179+
- 查看服务器警告日志中的尝试信息
180+
181+
## 未来改进
182+
183+
- [ ] 支持更细粒度的权限控制(只读/读写)
184+
- [ ] 添加目录配额限制
185+
- [ ] 实现用户之间的文件共享机制
186+
- [ ] 添加活动审计和日志查询界面
187+
- [ ] 支持 chroot 沙箱隔离(需要 Linux 权限)

0 commit comments

Comments
 (0)