From 47fe1466a4bbd109d9f388c323b3653e07e74262 Mon Sep 17 00:00:00 2001 From: yuyx <237899745@qq.com> Date: Tue, 25 Nov 2025 01:37:02 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=92=20=E4=BF=AE=E5=A4=8D=E4=B8=AD?= =?UTF-8?q?=E9=AB=98=E5=8D=B1=E5=AE=89=E5=85=A8=E6=BC=8F=E6=B4=9E=E5=B9=B6?= =?UTF-8?q?=E5=A2=9E=E5=BC=BA=E6=96=87=E4=BB=B6=E5=AE=89=E5=85=A8=E9=AA=8C?= =?UTF-8?q?=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **关键安全修复:** 1. 修复弱随机数生成器(中危) - 分享码生成从Math.random()改为crypto.randomBytes() - 防止分享链接被预测或暴力猜测 2. 增强文件上传安全验证(中危) - 新增isSafePathSegment()函数验证文件名 - 禁止路径遍历字符(..、/、\、控制字符) - 添加上传路径规范化和安全检查 **功能改进:** - 管理员界面显示用户邮箱验证状态 - 优化用户状态展示(已封禁/未激活/正常) **安全影响:** - 消除分享链接可预测性风险 - 防止文件上传路径遍历攻击 - 提升文件系统访问控制安全性 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- backend/database.js | 4 +++- backend/server.js | 34 ++++++++++++++++++++++++++++++++-- frontend/app.html | 1 + 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/backend/database.js b/backend/database.js index e5f2424..578dcd6 100644 --- a/backend/database.js +++ b/backend/database.js @@ -1,6 +1,7 @@ const Database = require('better-sqlite3'); const bcrypt = require('bcryptjs'); const path = require('path'); +const crypto = require('crypto'); // 创建或连接数据库 const db = new Database(path.join(__dirname, 'ftp-manager.db')); @@ -297,9 +298,10 @@ const ShareDB = { // 生成随机分享码 generateShareCode(length = 8) { const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + const bytes = crypto.randomBytes(length); let code = ''; for (let i = 0; i < length; i++) { - code += chars.charAt(Math.floor(Math.random() * chars.length)); + code += chars[bytes[i] % chars.length]; } return code; }, diff --git a/backend/server.js b/backend/server.js index 098ce8d..bc75f91 100644 --- a/backend/server.js +++ b/backend/server.js @@ -197,6 +197,17 @@ function buildHttpDownloadUrl(rawBaseUrl, filePath) { } } +// 校验文件名/路径片段安全(禁止分隔符、控制字符、..) +function isSafePathSegment(name) { + return ( + typeof name === 'string' && + name.length > 0 && + !name.includes('..') && + !/[/\\]/.test(name) && + !/[\x00-\x1F]/.test(name) + ); +} + // 应用XSS过滤到所有POST/PUT请求的body app.use((req, res, next) => { if ((req.method === 'POST' || req.method === 'PUT') && req.body) { @@ -1986,9 +1997,27 @@ app.post('/api/upload', authMiddleware, upload.single('file'), async (req, res) const remotePath = req.body.path || '/'; // 修复中文文件名:multer将UTF-8转为了Latin1,需要转回来 const originalFilename = Buffer.from(req.file.originalname, 'latin1').toString('utf8'); - const remoteFilePath = remotePath === '/' + // 文件名安全校验 + if (!isSafePathSegment(originalFilename)) { + return res.status(400).json({ + success: false, + message: '文件名包含非法字符' + }); + } + + // 路径安全校验 + const normalizedPath = path.posix.normalize(remotePath || '/'); + if (normalizedPath.includes('..')) { + return res.status(400).json({ + success: false, + message: '上传路径非法' + }); + } + const safePath = normalizedPath === '.' ? '/' : normalizedPath; + + const remoteFilePath = safePath === '/' ? `/${originalFilename}` - : `${remotePath}/${originalFilename}`; + : `${safePath}/${originalFilename}`; let storage; @@ -3123,6 +3152,7 @@ app.get('/api/admin/users', authMiddleware, adminMiddleware, (req, res) => { email: u.email, is_admin: u.is_admin, is_active: u.is_active, + is_verified: u.is_verified, is_banned: u.is_banned, has_ftp_config: u.has_ftp_config, created_at: u.created_at, diff --git a/frontend/app.html b/frontend/app.html index 6d8c473..c071780 100644 --- a/frontend/app.html +++ b/frontend/app.html @@ -1733,6 +1733,7 @@ 已封禁 + 未激活 正常