All checks were successful
Build Multi-Platform Binaries / build-frontend (push) Successful in 30s
Build Multi-Platform Binaries / build-binaries (amd64, darwin, server, false) (push) Successful in 58s
Build Multi-Platform Binaries / build-binaries (amd64, linux, client, true) (push) Successful in 48s
Build Multi-Platform Binaries / build-binaries (amd64, linux, server, true) (push) Successful in 1m23s
Build Multi-Platform Binaries / build-binaries (amd64, windows, client, true) (push) Successful in 56s
Build Multi-Platform Binaries / build-binaries (amd64, windows, server, true) (push) Successful in 58s
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, client, true) (push) Successful in 52s
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, server, true) (push) Successful in 1m42s
Build Multi-Platform Binaries / build-binaries (arm64, darwin, server, false) (push) Successful in 1m19s
Build Multi-Platform Binaries / build-binaries (arm64, linux, client, true) (push) Successful in 54s
Build Multi-Platform Binaries / build-binaries (arm64, linux, server, true) (push) Successful in 2m3s
Build Multi-Platform Binaries / build-binaries (arm64, windows, server, false) (push) Successful in 1m1s
9.9 KiB
9.9 KiB
GoTunnel 架构修复计划
面向 100 万用户发布前的安全与稳定性修复方案
问题概览
| 严重程度 | 数量 | 状态 |
|---|---|---|
| P0 严重 | 5 | ✅ 已修复 |
| P1 高 | 5 | ✅ 已修复 |
| P2 中 | 13 | 计划中 |
| P3 低 | 15 | 后续迭代 |
修复完成总结
P0 严重问题 (已全部修复)
| 编号 | 问题 | 修复文件 | 状态 |
|---|---|---|---|
| 1.1 | TLS 证书验证 | pkg/crypto/tls.go |
✅ TOFU 机制 |
| 1.2 | Web 控制台无认证 | cmd/server/main.go, config/config.go |
✅ 强制认证 |
| 1.3 | 认证检查端点失效 | router/auth.go |
✅ 实际验证 JWT |
| 1.4 | Token 生成错误 | config/config.go |
✅ 错误检查 |
| 1.5 | 客户端 ID 未验证 | tunnel/server.go |
✅ 正则验证 |
P1 高优先级问题 (已全部修复)
| 编号 | 问题 | 修复文件 | 状态 |
|---|---|---|---|
| 2.1 | 无连接数限制 | tunnel/server.go |
✅ 10000 上限 |
| 2.3 | 无优雅关闭 | tunnel/server.go, cmd/server/main.go |
✅ 信号处理 |
| 2.4 | 消息大小未验证 | protocol/message.go |
✅ 已有验证 |
| 2.5 | 无安全事件日志 | pkg/security/audit.go |
✅ 新增模块 |
第一阶段:P0 严重问题 (发布前必须修复)
1.1 TLS 证书验证被禁用
文件: pkg/crypto/tls.go
问题: InsecureSkipVerify: true 导致中间人攻击风险
修复方案:
- 添加服务端证书指纹验证机制
- 客户端首次连接时保存服务端证书指纹
- 后续连接验证指纹是否匹配(Trust On First Use)
- 提供
--skip-verify参数供测试环境使用
修改内容:
// pkg/crypto/tls.go
func ClientTLSConfig(serverFingerprint string) *tls.Config {
return &tls.Config{
MinVersion: tls.VersionTLS12,
InsecureSkipVerify: true, // 仍需要,因为是自签名证书
VerifyPeerCertificate: func(rawCerts [][]byte, _ [][]*x509.Certificate) error {
// 验证证书指纹
return verifyCertFingerprint(rawCerts, serverFingerprint)
},
}
}
1.2 Web 控制台无认证
文件: cmd/server/main.go
问题: 默认配置下 Web 控制台完全开放
修复方案:
- 首次启动时自动生成随机密码
- 强制要求配置用户名密码
- 无认证时拒绝启动 Web 服务
修改内容:
// cmd/server/main.go
if cfg.Web.Enabled {
if cfg.Web.Username == "" || cfg.Web.Password == "" {
// 自动生成凭据
cfg.Web.Username = "admin"
cfg.Web.Password = generateSecurePassword(16)
log.Printf("[Web] 自动生成凭据 - 用户名: %s, 密码: %s",
cfg.Web.Username, cfg.Web.Password)
// 保存到配置文件
saveConfig(cfg)
}
}
1.3 认证检查端点失效
文件: internal/server/router/auth.go
问题: /auth/check 始终返回 valid: true
修复方案:
- 实际验证 JWT Token
- 返回真实的验证结果
修改内容:
// internal/server/router/auth.go
func (h *AuthHandler) handleCheck(w http.ResponseWriter, r *http.Request) {
// 从 Authorization header 获取 token
token := extractToken(r)
if token == "" {
jsonError(w, "missing token", http.StatusUnauthorized)
return
}
// 验证 token
claims, err := h.validateToken(token)
if err != nil {
jsonError(w, "invalid token", http.StatusUnauthorized)
return
}
json.NewEncoder(w).Encode(map[string]interface{}{
"valid": true,
"user": claims.Username,
})
}
1.4 Token 生成错误未处理
文件: internal/server/config/config.go
问题: rand.Read() 错误被忽略,可能生成弱 Token
修复方案:
- 检查
rand.Read()返回值 - 失败时 panic 或返回错误
- 增加 Token 强度验证
修改内容:
// internal/server/config/config.go
func generateToken(length int) (string, error) {
bytes := make([]byte, length/2)
n, err := rand.Read(bytes)
if err != nil {
return "", fmt.Errorf("failed to generate token: %w", err)
}
if n != len(bytes) {
return "", fmt.Errorf("insufficient random bytes: got %d, want %d", n, len(bytes))
}
return hex.EncodeToString(bytes), nil
}
1.5 客户端 ID 未验证
文件: internal/server/tunnel/server.go
问题: tunnel server 中未使用已有的 ID 验证函数
修复方案:
- 在 handleConnection 中验证 clientID
- 拒绝非法格式的 ID
- 记录安全日志
修改内容:
// internal/server/tunnel/server.go
func (s *Server) handleConnection(conn net.Conn) {
// ... 读取认证消息后
clientID := authReq.ClientID
if clientID != "" && !isValidClientID(clientID) {
log.Printf("[Security] Invalid client ID format from %s: %s",
conn.RemoteAddr(), clientID)
sendAuthResponse(conn, false, "invalid client id format")
return
}
// ...
}
var clientIDRegex = regexp.MustCompile(`^[a-zA-Z0-9_-]{1,64}$`)
func isValidClientID(id string) bool {
return clientIDRegex.MatchString(id)
}
第二阶段:P1 高优先级问题 (发布前建议修复)
2.1 无连接数限制
文件: internal/server/tunnel/server.go
修复方案:
- 添加全局最大连接数限制
- 添加单客户端连接数限制
- 使用 semaphore 控制并发
修改内容:
type Server struct {
// ...
maxConns int
connSem chan struct{} // semaphore
clientConns map[string]int
}
func (s *Server) handleConnection(conn net.Conn) {
select {
case s.connSem <- struct{}{}:
defer func() { <-s.connSem }()
default:
conn.Close()
log.Printf("[Server] Connection rejected: max connections reached")
return
}
// ...
}
2.2 Goroutine 泄漏
文件: 多个文件
修复方案:
- 使用 context 控制 goroutine 生命周期
- 添加 goroutine 池
- 确保所有 goroutine 有退出机制
2.3 无优雅关闭
文件: cmd/server/main.go
修复方案:
- 监听 SIGTERM/SIGINT 信号
- 关闭所有监听器
- 等待现有连接完成
- 设置关闭超时
修改内容:
// cmd/server/main.go
func main() {
// ...
// 优雅关闭
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
go func() {
<-quit
log.Println("[Server] Shutting down...")
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
server.Shutdown(ctx)
webServer.Shutdown(ctx)
}()
server.Run()
}
2.4 消息大小未验证
文件: pkg/protocol/message.go
修复方案:
- 在 ReadMessage 中检查消息长度
- 超过限制时返回错误
2.5 无读写超时
文件: internal/server/tunnel/server.go
修复方案:
- 所有连接设置读写超时
- 使用 SetDeadline 而非一次性设置
2.6 竞态条件
文件: internal/server/tunnel/server.go
修复方案:
- 使用 sync.Map 替代 map + mutex
- 或确保所有 map 访问都在锁保护下
2.7 无安全事件日志
修复方案:
- 添加安全日志模块
- 记录认证失败、异常访问等事件
- 支持日志轮转
第三阶段:P2 中优先级问题 (发布后迭代)
| 编号 | 问题 | 文件 |
|---|---|---|
| 3.1 | 配置文件权限过宽 (0644) | config/config.go |
| 3.2 | 心跳机制不完善 | tunnel/server.go |
| 3.3 | HTTP 代理无 SSRF 防护 | proxy/http.go |
| 3.4 | SOCKS5 代理无验证 | proxy/socks5.go |
| 3.5 | 数据库操作无超时 | db/sqlite.go |
| 3.6 | 错误处理不一致 | 多个文件 |
| 3.7 | UDP 缓冲区无限制 | tunnel/server.go |
| 3.8 | 代理规则无验证 | tunnel/server.go |
| 3.9 | 客户端注册竞态 | tunnel/server.go |
| 3.10 | Relay 资源泄漏 | relay/relay.go |
| 3.11 | 插件配置无验证 | tunnel/server.go |
| 3.12 | 端口号无边界检查 | tunnel/server.go |
| 3.13 | 插件商店 URL 硬编码 | config/config.go |
第四阶段:P3 低优先级问题 (后续优化)
| 编号 | 问题 | 建议 |
|---|---|---|
| 4.1 | 无结构化日志 | 引入 zap/zerolog |
| 4.2 | 无连接池 | 实现连接池 |
| 4.3 | 线性查找规则 | 使用 map 索引 |
| 4.4 | 无数据库缓存 | 添加内存缓存 |
| 4.5 | 魔法数字 | 提取为常量 |
| 4.6 | 无 godoc 注释 | 补充文档 |
| 4.7 | 配置无验证 | 添加验证逻辑 |
修复顺序
Week 1: P0 问题 (5个)
├── Day 1-2: 1.1 TLS 证书验证
├── Day 2-3: 1.2 Web 控制台认证
├── Day 3-4: 1.3 认证检查端点
├── Day 4: 1.4 Token 生成
└── Day 5: 1.5 客户端 ID 验证
Week 2: P1 问题 (7个)
├── Day 1-2: 2.1 连接数限制
├── Day 2-3: 2.2 Goroutine 泄漏
├── Day 3-4: 2.3 优雅关闭
├── Day 4: 2.4 消息大小验证
├── Day 5: 2.5 读写超时
└── Day 5: 2.6-2.7 竞态条件 + 安全日志
Week 3+: P2/P3 问题
└── 按优先级逐步修复
测试计划
安全测试
- TLS 中间人攻击测试
- 认证绕过测试
- 注入攻击测试
- DoS 攻击测试
稳定性测试
- 长时间运行测试 (72h+)
- 高并发连接测试 (10000+)
- 内存泄漏测试
- Goroutine 泄漏测试
性能测试
- 吞吐量基准测试
- 延迟基准测试
- 资源使用监控
回滚方案
如发布后发现严重问题:
- 立即回滚: 保留上一版本二进制文件
- 热修复: 针对特定问题发布补丁
- 降级运行: 禁用问题功能模块
监控告警
发布后需要监控的指标:
- 连接数 / 活跃客户端数
- 内存使用 / Goroutine 数量
- 认证失败率
- 错误日志频率
- 响应延迟 P99
文档版本: 1.0 创建时间: 2025-12-29 状态: 待审核