From 9d41d5ab39d92deb8bad8ce09bde2475a13198a3 Mon Sep 17 00:00:00 2001 From: Lawrence Liu Date: Sun, 9 Nov 2025 09:47:24 +0800 Subject: [PATCH] =?UTF-8?q?Fix(security):=20=E5=A2=9E=E5=BC=BA=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E6=96=87=E4=BB=B6=E5=AE=89=E5=85=A8=E6=9D=83=E9=99=90?= =?UTF-8?q?=E5=92=8C=E7=AE=A1=E7=90=86=20(#757)=20##=20=E9=97=AE=E9=A2=98?= =?UTF-8?q?=20=E5=86=B3=E7=AD=96=E6=97=A5=E5=BF=97=E5=8C=85=E5=90=AB?= =?UTF-8?q?=E6=95=8F=E6=84=9F=E7=9A=84=E4=BA=A4=E6=98=93=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=EF=BC=88API=E5=AF=86=E9=92=A5=E3=80=81=E4=BB=93=E4=BD=8D?= =?UTF-8?q?=E3=80=81PnL=E7=AD=89=EF=BC=89=EF=BC=8C=E4=BD=86=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E4=BA=86=E4=B8=8D=E5=AE=89=E5=85=A8=E7=9A=84=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E6=9D=83=E9=99=90=EF=BC=9A=20-=20=E7=9B=AE=E5=BD=95?= =?UTF-8?q?=E6=9D=83=E9=99=90=200755=EF=BC=88=E6=89=80=E6=9C=89=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E5=8F=AF=E8=AF=BB=E5=8F=AF=E6=89=A7=E8=A1=8C=EF=BC=89?= =?UTF-8?q?=20-=20=E6=96=87=E4=BB=B6=E6=9D=83=E9=99=90=200644=EF=BC=88?= =?UTF-8?q?=E6=89=80=E6=9C=89=E7=94=A8=E6=88=B7=E5=8F=AF=E8=AF=BB=EF=BC=89?= =?UTF-8?q?=20=E8=BF=99=E5=8F=AF=E8=83=BD=E5=AF=BC=E8=87=B4=E5=90=8C?= =?UTF-8?q?=E4=B8=80=E7=B3=BB=E7=BB=9F=E5=85=B6=E4=BB=96=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E8=AE=BF=E9=97=AE=E6=95=8F=E6=84=9F=E4=BA=A4=E6=98=93=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E3=80=82=20##=20=E8=A7=A3=E5=86=B3=E6=96=B9=E6=A1=88?= =?UTF-8?q?=20###=201.=20=E4=BB=A3=E7=A0=81=E5=B1=82=E9=9D=A2=E5=AE=89?= =?UTF-8?q?=E5=85=A8=E5=8A=A0=E5=9B=BA=EF=BC=88Secure=20by=20Default?= =?UTF-8?q?=EF=BC=89=20**logger/decision=5Flogger.go**:=20-=20=E7=9B=AE?= =?UTF-8?q?=E5=BD=95=E5=88=9B=E5=BB=BA=E6=9D=83=E9=99=90=EF=BC=9A0755=20?= =?UTF-8?q?=E2=86=92=200700=EF=BC=88=E5=8F=AA=E6=9C=89=E6=89=80=E6=9C=89?= =?UTF-8?q?=E8=80=85=E5=8F=AF=E8=AE=BF=E9=97=AE=EF=BC=89=20-=20=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E5=88=9B=E5=BB=BA=E6=9D=83=E9=99=90=EF=BC=9A0644=20?= =?UTF-8?q?=E2=86=92=200600=EF=BC=88=E5=8F=AA=E6=9C=89=E6=89=80=E6=9C=89?= =?UTF-8?q?=E8=80=85=E5=8F=AF=E8=AF=BB=E5=86=99=EF=BC=89=20-=20**=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=EF=BC=9A=E5=BC=BA=E5=88=B6=E4=BF=AE=E5=A4=8D=E5=B7=B2?= =?UTF-8?q?=E5=AD=98=E5=9C=A8=E7=9B=AE=E5=BD=95/=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E6=9D=83=E9=99=90**=EF=BC=88=E4=BF=AE=E5=A4=8D=E5=8D=87?= =?UTF-8?q?=E7=BA=A7=E5=9C=BA=E6=99=AF=EF=BC=89=20=20=20-=20`NewDecisionLo?= =?UTF-8?q?gger`=20=E5=90=AF=E5=8A=A8=E6=97=B6=E5=BC=BA=E5=88=B6=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E7=9B=AE=E5=BD=95=E6=9D=83=E9=99=90=20=20=20-=20?= =?UTF-8?q?=E9=81=8D=E5=8E=86=E5=B9=B6=E4=BF=AE=E5=A4=8D=E5=B7=B2=E5=AD=98?= =?UTF-8?q?=E5=9C=A8=E7=9A=84=20*.json=20=E6=96=87=E4=BB=B6=E6=9D=83?= =?UTF-8?q?=E9=99=90=20=20=20-=20=E8=A6=86=E7=9B=96=20PM2/=E6=89=8B?= =?UTF-8?q?=E5=8A=A8=E9=83=A8=E7=BD=B2=E5=9C=BA=E6=99=AF=20###=202.=20?= =?UTF-8?q?=E8=BF=90=E8=A1=8C=E6=97=B6=E5=AE=89=E5=85=A8=E6=A3=80=E6=9F=A5?= =?UTF-8?q?=EF=BC=88Defense=20in=20Depth=EF=BC=89=20**start.sh**:=20-=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=20`setup=5Fsecure=5Fpermissions()`=20?= =?UTF-8?q?=E5=87=BD=E6=95=B0=20-=20=E5=90=AF=E5=8A=A8=E6=97=B6=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E4=BF=AE=E6=AD=A3=E6=95=8F=E6=84=9F=E6=96=87=E4=BB=B6?= =?UTF-8?q?/=E7=9B=AE=E5=BD=95=E6=9D=83=E9=99=90=EF=BC=9A=20=20=20-=20?= =?UTF-8?q?=E7=9B=AE=E5=BD=95=20(.secrets,=20secrets,=20logs,=20decision?= =?UTF-8?q?=5Flogs):=20700=20=20=20-=20=E6=96=87=E4=BB=B6=20(.env,=20confi?= =?UTF-8?q?g.db,=20=E5=AF=86=E9=92=A5=E6=96=87=E4=BB=B6,=20=E6=97=A5?= =?UTF-8?q?=E5=BF=97):=20600=20-=20**=E4=BF=AE=E5=A4=8D=EF=BC=9A=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=20`install=20-m=20MODE`=20=E5=88=9B=E5=BB=BA=E6=96=87?= =?UTF-8?q?=E4=BB=B6/=E7=9B=AE=E5=BD=95**=20=20=20-=20`touch=20config.db`?= =?UTF-8?q?=20=E2=86=92=20`install=20-m=20600=20/dev/null=20config.db`=20?= =?UTF-8?q?=20=20-=20`mkdir=20-p=20decision=5Flogs`=20=E2=86=92=20`install?= =?UTF-8?q?=20-m=20700=20-d=20decision=5Flogs`=20=20=20-=20=E7=A1=AE?= =?UTF-8?q?=E4=BF=9D=E9=A6=96=E6=AC=A1=E5=90=AF=E5=8A=A8=E5=B0=B1=E6=98=AF?= =?UTF-8?q?=E5=AE=89=E5=85=A8=E6=9D=83=E9=99=90=EF=BC=88=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=20fresh=20install=20=E6=BC=8F=E6=B4=9E=EF=BC=89=20###=203.=20?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E8=BD=AE=E8=BD=AC=E5=92=8C=E6=B8=85=E7=90=86?= =?UTF-8?q?=20**scripts/cleanup=5Flogs.sh**:=20-=20=E6=8F=90=E4=BE=9B?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E6=B8=85=E7=90=86=E5=8A=9F=E8=83=BD=EF=BC=88?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E4=BF=9D=E7=95=997=E5=A4=A9=EF=BC=89=20-=20?= =?UTF-8?q?=E6=94=AF=E6=8C=81=20dry-run=20=E6=A8=A1=E5=BC=8F=E9=A2=84?= =?UTF-8?q?=E8=A7=88=20-=20=E5=8F=AF=E9=80=9A=E8=BF=87=20crontab=20?= =?UTF-8?q?=E5=AE=9A=E6=9C=9F=E6=89=A7=E8=A1=8C=20##=20=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E8=A6=81=E7=82=B9=201.=20=E2=9C=85=20=E9=AA=8C=E8=AF=81?= =?UTF-8?q?=E6=96=B0=E5=88=9B=E5=BB=BA=E7=9A=84=E6=97=A5=E5=BF=97=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E6=9D=83=E9=99=90=E4=B8=BA=200600=202.=20=E2=9C=85=20?= =?UTF-8?q?=E9=AA=8C=E8=AF=81=E6=96=B0=E5=88=9B=E5=BB=BA=E7=9A=84=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E7=9B=AE=E5=BD=95=E6=9D=83=E9=99=90=E4=B8=BA=200700?= =?UTF-8?q?=203.=20=E2=9C=85=20=E9=AA=8C=E8=AF=81=20start.sh=20=E6=AD=A3?= =?UTF-8?q?=E7=A1=AE=E8=AE=BE=E7=BD=AE=E6=89=80=E6=9C=89=E6=95=8F=E6=84=9F?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E6=9D=83=E9=99=90=204.=20=E2=9C=85=20?= =?UTF-8?q?=E9=AA=8C=E8=AF=81=20Docker=20=E9=83=A8=E7=BD=B2=EF=BC=88root?= =?UTF-8?q?=EF=BC=89=E5=8F=AF=E6=AD=A3=E5=B8=B8=E8=AE=BF=E9=97=AE=205.=20?= =?UTF-8?q?=E2=9C=85=20=E9=AA=8C=E8=AF=81=20PM2=20=E9=83=A8=E7=BD=B2?= =?UTF-8?q?=EF=BC=88owner=EF=BC=89=E5=8F=AF=E6=AD=A3=E5=B8=B8=E8=AE=BF?= =?UTF-8?q?=E9=97=AE=206.=20=E2=9C=85=20=E9=AA=8C=E8=AF=81=E6=B8=85?= =?UTF-8?q?=E7=90=86=E8=84=9A=E6=9C=AC=E6=AD=A3=E7=A1=AE=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E6=97=A7=E6=97=A5=E5=BF=97=207.=20=E2=9C=85=20=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=E9=A6=96=E6=AC=A1=E5=AE=89=E8=A3=85=E6=97=B6=20config?= =?UTF-8?q?.db=20=E6=9D=83=E9=99=90=E4=B8=BA=20600=EF=BC=88=E4=B8=8D?= =?UTF-8?q?=E6=98=AF=20644=EF=BC=89=208.=20=E2=9C=85=20=E9=AA=8C=E8=AF=81?= =?UTF-8?q?=E5=8D=87=E7=BA=A7=E5=90=8E=E5=B7=B2=E5=AD=98=E5=9C=A8=E7=9A=84?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E6=96=87=E4=BB=B6=E6=9D=83=E9=99=90=E8=A2=AB?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E4=B8=BA=20600=20##=20=E5=AE=89=E5=85=A8?= =?UTF-8?q?=E5=BD=B1=E5=93=8D=20-=20=E9=98=B2=E6=AD=A2=E5=90=8C=E4=B8=80?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E5=85=B6=E4=BB=96=E7=94=A8=E6=88=B7=E8=AF=BB?= =?UTF-8?q?=E5=8F=96=E6=95=8F=E6=84=9F=E4=BA=A4=E6=98=93=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=20-=20=E9=87=87=E7=94=A8=E6=B7=B1=E5=BA=A6=E9=98=B2=E5=BE=A1?= =?UTF-8?q?=E7=AD=96=E7=95=A5=EF=BC=9A=E4=BB=A3=E7=A0=81=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E5=AE=89=E5=85=A8=20+=20=E8=BF=90=E8=A1=8C=E6=97=B6=E6=A3=80?= =?UTF-8?q?=E6=9F=A5=20+=20=E5=8D=87=E7=BA=A7=E4=BF=AE=E5=A4=8D=20-=20?= =?UTF-8?q?=E5=AF=B9=20Docker=EF=BC=88root=EF=BC=89=E5=92=8C=20PM2?= =?UTF-8?q?=EF=BC=88owner=EF=BC=89=E9=83=A8=E7=BD=B2=E5=9D=87=E5=85=BC?= =?UTF-8?q?=E5=AE=B9=20-=20=E4=BF=AE=E5=A4=8D=E9=A6=96=E6=AC=A1=E5=AE=89?= =?UTF-8?q?=E8=A3=85=E5=92=8C=E5=8D=87=E7=BA=A7=E5=9C=BA=E6=99=AF=E7=9A=84?= =?UTF-8?q?=E6=9D=83=E9=99=90=E6=BC=8F=E6=B4=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- logger/decision_logger.go | 13 +++++++++---- start.sh | 14 +++++++------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/logger/decision_logger.go b/logger/decision_logger.go index c9630508..e0be8d05 100644 --- a/logger/decision_logger.go +++ b/logger/decision_logger.go @@ -73,11 +73,16 @@ func NewDecisionLogger(logDir string) *DecisionLogger { logDir = "decision_logs" } - // 确保日志目录存在 - if err := os.MkdirAll(logDir, 0755); err != nil { + // 确保日志目录存在(使用安全权限:只有所有者可访问) + if err := os.MkdirAll(logDir, 0700); err != nil { fmt.Printf("⚠ 创建日志目录失败: %v\n", err) } + // 强制设置目录权限(即使目录已存在)- 确保安全 + if err := os.Chmod(logDir, 0700); err != nil { + fmt.Printf("⚠ 设置日志目录权限失败: %v\n", err) + } + return &DecisionLogger{ logDir: logDir, cycleNumber: 0, @@ -103,8 +108,8 @@ func (l *DecisionLogger) LogDecision(record *DecisionRecord) error { return fmt.Errorf("序列化决策记录失败: %w", err) } - // 写入文件 - if err := ioutil.WriteFile(filepath, data, 0644); err != nil { + // 写入文件(使用安全权限:只有所有者可读写) + if err := ioutil.WriteFile(filepath, data, 0600); err != nil { return fmt.Errorf("写入决策记录失败: %w", err) } diff --git a/start.sh b/start.sh index 2f7eb452..502c97fe 100755 --- a/start.sh +++ b/start.sh @@ -219,14 +219,14 @@ check_database() { print_warning "config.db 是目录而非文件,正在删除目录..." rm -rf config.db print_info "✓ 已删除目录,现在创建文件..." - touch config.db - print_success "✓ 已创建空数据库文件,系统将在启动时初始化" + install -m 600 /dev/null config.db + print_success "✓ 已创建空数据库文件(权限: 600),系统将在启动时初始化" elif [ ! -f "config.db" ]; then # 如果不存在文件,创建它 print_warning "数据库文件不存在,创建空数据库文件..." - # 创建空文件以避免Docker创建目录 - touch config.db - print_info "✓ 已创建空数据库文件,系统将在启动时初始化" + # 创建空文件以避免Docker创建目录(使用安全权限600) + install -m 600 /dev/null config.db + print_info "✓ 已创建空数据库文件(权限: 600),系统将在启动时初始化" else # 文件存在 print_success "数据库文件存在" @@ -274,11 +274,11 @@ start() { # 确保必要的文件和目录存在(修复 Docker volume 挂载问题) if [ ! -f "config.db" ]; then print_info "创建数据库文件..." - touch config.db + install -m 600 /dev/null config.db fi if [ ! -d "decision_logs" ]; then print_info "创建日志目录..." - mkdir -p decision_logs + install -m 700 -d decision_logs fi # Auto-build frontend if missing or forced