Repository navigation
Expand file tree
/
Copy pathmain.go
More file actions
114 lines (101 loc) · 3.85 KB
/
Copy pathmain.go
File metadata and controls
114 lines (101 loc) · 3.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// FasterEdge 开源项目 · https://github.com/FasterEdge · https://gitee.com/FasterEdge
package main
// https://github.com/FasterEdge/SimpleWebShell
import (
"crypto/tls"
"flag"
"fmt"
"github.com/FasterEdge/SimpleWebShell/route"
"log"
"os"
"github.com/gin-gonic/gin"
)
var (
password *string
shellPath *string
port *string
useTLS *bool
certFile *string
keyFile *string
)
func init() {
password = flag.String("key", "", "密码 (必需)")
shellPath = flag.String("shell", "/bin/bash", "Shell路径 (Windows默认: cmd, Linux默认: /bin/bash)")
port = flag.String("port", "8878", "监听端口 (默认: 8878)")
useTLS = flag.Bool("tls", false, "启用HTTPS (需通过 -cert/-keyfile 指定证书与私钥路径)")
certFile = flag.String("cert", "", "TLS证书文件路径 (PEM格式,-tls=true时必需)")
keyFile = flag.String("keyfile", "", "TLS私钥文件路径 (PEM格式,-tls=true时必需)")
}
func main() {
version := "1.0.20260922" // 当前系统的版本
flag.Parse()
// 检查必需参数
if *password == "" {
log.Fatal("错误: 必须指定密码参数 -key")
}
// 输出参数
fmt.Printf("SimpleWebShell %s By FasterEdge\n", version)
fmt.Printf("开源官网:https://github.com/FasterEdge\n")
fmt.Printf("SimpleWebShell仅用于边缘计算场景中远程操作和热更新,禁止用于非法用途!\n")
// 不打印密码明文: 容器场景下 stdout 会进入 Docker logs, 明文打印会导致凭据泄露
fmt.Printf("密码已设置(长度 %d,已隐藏)\n", len(*password))
fmt.Printf("Shell路径: %s\n", *shellPath)
fmt.Printf("监听端口: %s\n", *port)
// 校验TLS参数
if *useTLS {
if *certFile == "" || *keyFile == "" {
log.Fatal("错误: 启用HTTPS(-tls=true)时必须同时指定 -cert 证书路径与 -keyfile 私钥路径")
}
if err := validateCertFiles(*certFile, *keyFile); err != nil {
log.Fatalf("错误: TLS证书/私钥无效: %v", err)
}
fmt.Printf("已启用HTTPS: 证书=%s 私钥=%s\n", *certFile, *keyFile)
}
// 设置Gin为发布模式
gin.SetMode(gin.ReleaseMode)
// 创建Gin路由器。
// 注意:不使用 gin.Default(),因为其默认日志会打印完整 URL(含 ?key=密码),
// 导致密码泄露到服务日志。改用 gin.New() + 自定义日志(仅打印路径,不含查询串)。
r := gin.New()
r.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {
// 仅打印路径 path,不含 RawQuery,避免 key=密码 泄露到日志
// (gin v1.12 的 param.Path 会拼上查询串,故用 Request.URL.Path)
path := param.Request.URL.Path
return fmt.Sprintf("[GIN] %v | %3d | %13v | %15s | %-7s %s\n",
param.TimeStamp.Format("2006/01/02 - 15:04:05"),
param.StatusCode,
param.Latency,
param.ClientIP,
param.Method,
path,
)
}))
r.Use(gin.Recovery())
// 设置路由
route.SetupRoutes(r, *password, *shellPath, *port)
// 启动服务器
if *useTLS {
fmt.Printf("HTTPS服务器启动在端口 %s\n", *port)
log.Fatal(r.RunTLS(":"+*port, *certFile, *keyFile))
}
fmt.Printf("服务器启动在端口 %s\n", *port)
log.Fatal(r.Run(":" + *port))
}
// validateCertFiles 校验TLS证书/私钥路径存在且能够配对解析(PEM格式)。
// 使用 crypto/tls 实际加载证书对,可提前发现证书与私钥不匹配、文件损坏等暗病。
func validateCertFiles(certPath, keyPath string) error {
for _, path := range []string{certPath, keyPath} {
info, err := os.Stat(path)
if err != nil {
return fmt.Errorf("%s 不可访问: %v", path, err)
}
if info.IsDir() {
return fmt.Errorf("%s 是目录而非文件", path)
}
}
// 尝试完整解析证书+私钥对,确保两者匹配且为有效 PEM
if _, err := tls.LoadX509KeyPair(certPath, keyPath); err != nil {
return fmt.Errorf("证书与私钥解析失败(请确认为PEM格式且配对一致): %v", err)
}
return nil
}