🔒 安全加固:修复多个中高危漏洞
修复内容: 1. Host Header 注入 - 添加 PUBLIC_BASE_URL 和 ALLOWED_HOSTS 白名单 2. API密钥暴力破解 - 添加速率限制(5次/小时,封锁24小时) 3. 路径遍历漏洞 - 增强路径验证,防止空字节注入和目录遍历 4. 令牌安全 - 密码重置和邮箱验证令牌使用SHA256哈希存储 5. 文件上传安全 - 阻止PHP/JSP/ASP等可执行脚本上传 6. IDOR防护 - 增强权限验证和安全日志 7. XSS防护 - 增强输入过滤,阻止javascript:等危险协议 8. 日志脱敏 - 移除验证码等敏感信息的日志输出 9. CSRF增强 - HTTPS环境使用strict模式Cookie 10. 邮箱枚举防护 - 密码重置统一返回消息 11. 速率限制 - 文件列表(60次/分)和上传(100次/小时) 配置说明: - PUBLIC_BASE_URL: 必须配置,用于生成安全的邮件链接 - ALLOWED_HOSTS: 可选,Host头白名单 - COOKIE_SECURE=true: 生产环境必须开启 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -492,16 +492,20 @@ const SettingsDB = {
|
||||
}
|
||||
};
|
||||
|
||||
// 邮箱验证管理
|
||||
// 邮箱验证管理(增强安全:哈希存储)
|
||||
const VerificationDB = {
|
||||
setVerification(userId, token, expiresAtMs) {
|
||||
// 对令牌进行哈希后存储
|
||||
const hashedToken = crypto.createHash('sha256').update(token).digest('hex');
|
||||
db.prepare(`
|
||||
UPDATE users
|
||||
SET verification_token = ?, verification_expires_at = ?, is_verified = 0, updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = ?
|
||||
`).run(token, expiresAtMs, userId);
|
||||
`).run(hashedToken, expiresAtMs, userId);
|
||||
},
|
||||
consumeVerificationToken(token) {
|
||||
// 对用户提供的令牌进行哈希
|
||||
const hashedToken = crypto.createHash('sha256').update(token).digest('hex');
|
||||
const row = db.prepare(`
|
||||
SELECT * FROM users
|
||||
WHERE verification_token = ?
|
||||
@@ -512,7 +516,7 @@ const VerificationDB = {
|
||||
OR verification_expires_at > CURRENT_TIMESTAMP -- 兼容旧的字符串时间
|
||||
)
|
||||
AND is_verified = 0
|
||||
`).get(token);
|
||||
`).get(hashedToken);
|
||||
if (!row) return null;
|
||||
|
||||
db.prepare(`
|
||||
@@ -524,23 +528,30 @@ const VerificationDB = {
|
||||
}
|
||||
};
|
||||
|
||||
// 密码重置 Token 管理
|
||||
// 密码重置 Token 管理(增强安全:哈希存储)
|
||||
const PasswordResetTokenDB = {
|
||||
// 创建令牌时存储哈希值
|
||||
create(userId, token, expiresAtMs) {
|
||||
// 对令牌进行哈希后存储(防止数据库泄露时令牌被直接使用)
|
||||
const hashedToken = crypto.createHash('sha256').update(token).digest('hex');
|
||||
db.prepare(`
|
||||
INSERT INTO password_reset_tokens (user_id, token, expires_at, used)
|
||||
VALUES (?, ?, ?, 0)
|
||||
`).run(userId, token, expiresAtMs);
|
||||
`).run(userId, hashedToken, expiresAtMs);
|
||||
},
|
||||
// 验证令牌时先哈希再比较
|
||||
use(token) {
|
||||
// 对用户提供的令牌进行哈希
|
||||
const hashedToken = crypto.createHash('sha256').update(token).digest('hex');
|
||||
const row = db.prepare(`
|
||||
SELECT * FROM password_reset_tokens
|
||||
WHERE token = ? AND used = 0 AND (
|
||||
expires_at > strftime('%s','now')*1000 -- 数值时间戳
|
||||
OR expires_at > CURRENT_TIMESTAMP -- 兼容旧的字符串时间
|
||||
)
|
||||
`).get(token);
|
||||
`).get(hashedToken);
|
||||
if (!row) return null;
|
||||
// 立即标记为已使用(防止重复使用)
|
||||
db.prepare(`UPDATE password_reset_tokens SET used = 1 WHERE id = ?`).run(row.id);
|
||||
return row;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user