fix: 修复 authenticateUserOrAdmin 认证绕过漏洞

- 添加 username 和 loginTime 字段验证(与 authenticateAdmin 保持一致)
- 无效/伪造会话自动删除并记录安全日志
- 删除未使用的 id 字段(死代码清理)

漏洞详情:
- 位置:src/middleware/auth.js:1569-1581
- 原因:只检查 Object.keys(session).length > 0,未验证必须字段
- 影响:攻击者可通过注入最小会话 {foo:'bar'} 绕过认证

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Junming Chen
2025-12-28 23:56:05 -05:00
parent fc57133230
commit 45b81bd478

View File

@@ -1434,7 +1434,6 @@ const authenticateAdmin = async (req, res, next) => {
// 设置管理员信息(只包含必要信息) // 设置管理员信息(只包含必要信息)
req.admin = { req.admin = {
id: adminSession.adminId || 'admin',
username: adminSession.username, username: adminSession.username,
sessionId: token, sessionId: token,
loginTime: adminSession.loginTime loginTime: adminSession.loginTime
@@ -1567,17 +1566,25 @@ const authenticateUserOrAdmin = async (req, res, next) => {
try { try {
const adminSession = await redis.getSession(adminToken) const adminSession = await redis.getSession(adminToken)
if (adminSession && Object.keys(adminSession).length > 0) { if (adminSession && Object.keys(adminSession).length > 0) {
req.admin = { // 🔒 安全修复:验证会话必须字段(与 authenticateAdmin 保持一致)
id: adminSession.adminId || 'admin', if (!adminSession.username || !adminSession.loginTime) {
username: adminSession.username, logger.security(
sessionId: adminToken, `🔒 Corrupted admin session in authenticateUserOrAdmin from ${req.ip || 'unknown'} - missing required fields (username: ${!!adminSession.username}, loginTime: ${!!adminSession.loginTime})`
loginTime: adminSession.loginTime )
} await redis.deleteSession(adminToken) // 清理无效/伪造的会话
req.userType = 'admin' // 不返回 401继续尝试用户认证
} else {
req.admin = {
username: adminSession.username,
sessionId: adminToken,
loginTime: adminSession.loginTime
}
req.userType = 'admin'
const authDuration = Date.now() - startTime const authDuration = Date.now() - startTime
logger.security(`🔐 Admin authenticated: ${adminSession.username} in ${authDuration}ms`) logger.security(`🔐 Admin authenticated: ${adminSession.username} in ${authDuration}ms`)
return next() return next()
}
} }
} catch (error) { } catch (error) {
logger.debug('Admin authentication failed, trying user authentication:', error.message) logger.debug('Admin authentication failed, trying user authentication:', error.message)