mirror of
https://github.com/laoxong/nofx.git
synced 2026-06-04 09:58:22 +08:00
Fix(security): 增强日志文件安全权限和管理 (#757)
## 问题 决策日志包含敏感的交易数据(API密钥、仓位、PnL等),但使用了不安全的默认权限: - 目录权限 0755(所有用户可读可执行) - 文件权限 0644(所有用户可读) 这可能导致同一系统其他用户访问敏感交易数据。 ## 解决方案 ### 1. 代码层面安全加固(Secure by Default) **logger/decision_logger.go**: - 目录创建权限:0755 → 0700(只有所有者可访问) - 文件创建权限:0644 → 0600(只有所有者可读写) - **新增:强制修复已存在目录/文件权限**(修复升级场景) - `NewDecisionLogger` 启动时强制设置目录权限 - 遍历并修复已存在的 *.json 文件权限 - 覆盖 PM2/手动部署场景 ### 2. 运行时安全检查(Defense in Depth) **start.sh**: - 新增 `setup_secure_permissions()` 函数 - 启动时自动修正敏感文件/目录权限: - 目录 (.secrets, secrets, logs, decision_logs): 700 - 文件 (.env, config.db, 密钥文件, 日志): 600 - **修复:使用 `install -m MODE` 创建文件/目录** - `touch config.db` → `install -m 600 /dev/null config.db` - `mkdir -p decision_logs` → `install -m 700 -d decision_logs` - 确保首次启动就是安全权限(修复 fresh install 漏洞) ### 3. 日志轮转和清理 **scripts/cleanup_logs.sh**: - 提供日志清理功能(默认保留7天) - 支持 dry-run 模式预览 - 可通过 crontab 定期执行 ## 测试要点 1. ✅ 验证新创建的日志文件权限为 0600 2. ✅ 验证新创建的日志目录权限为 0700 3. ✅ 验证 start.sh 正确设置所有敏感文件权限 4. ✅ 验证 Docker 部署(root)可正常访问 5. ✅ 验证 PM2 部署(owner)可正常访问 6. ✅ 验证清理脚本正确删除旧日志 7. ✅ 验证首次安装时 config.db 权限为 600(不是 644) 8. ✅ 验证升级后已存在的日志文件权限被修正为 600 ## 安全影响 - 防止同一系统其他用户读取敏感交易数据 - 采用深度防御策略:代码默认安全 + 运行时检查 + 升级修复 - 对 Docker(root)和 PM2(owner)部署均兼容 - 修复首次安装和升级场景的权限漏洞
This commit is contained in:
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user