审计日期:2026-05-13
审计范围:~/Desktop/my-website(Node.js + Express + SQLite 全栈网站)
- 位置:
server.jssession 配置 - 风险:Session 签名密钥写死在代码中,泄露后攻击者可伪造 session Cookie 冒充任意用户
- 修复:从环境变量
SESSION_SECRET读取,未设置时自动生成随机 256-bit 密钥
- 位置:
server.js初始化逻辑 + 启动日志 - 风险:管理员密码
ljgljg2006明文出现在源代码中,任何人查看代码即可获取后台权限 - 修复:
- 密码通过环境变量
ADMIN_PASS配置,默认仅作为开发兜底 - 移除启动日志中的密码明文输出
- 同时修复了 SQL 中硬编码
username = 'lijiguang'的 3 处查询
- 密码通过环境变量
- 位置:
/api/login、/api/register - 风险:无防护的登录接口可被暴力破解密码,注册接口可被滥用创建垃圾账号
- 修复:建议生产环境部署时在前置代理(Nginx/Cloudflare)层面添加限流规则
- 位置:全局中间件
- 风险:无 CSP、X-Frame-Options、HSTS 等头,易受点击劫持、XSS 等攻击
- 建议:安装
helmet中间件一键配置:const helmet = require('helmet'); app.use(helmet());
- 位置:
app.use('/uploads', express.static(...)) - 风险:所有用户上传文件通过固定 URL 公开访问,无需认证即可下载
- 建议:
- 上传文件添加随机哈希前缀(当前已有
Date.now() + random) - 敏感文件(头像等)添加权限校验中间件
- 上传文件添加随机哈希前缀(当前已有
- 位置:注册、发帖、评论、私信等接口
- 风险:超长输入可能导致数据库膨胀或前端渲染异常
- 建议:在 API 入口添加
express-validator限制字段最大长度
- 位置:
cookie: { secure: false } - 风险:Cookie 在非 HTTPS 连接下传输,可被中间人截获
- 建议:部署 HTTPS 后启用
secure: true
| 实践 | 说明 |
|---|---|
| ✅ SQL 参数化查询 | 所有 SQL 均使用 ? 占位符,无字符串拼接,免疫 SQL 注入 |
| ✅ 密码哈希存储 | 使用 bcrypt(10 rounds)存储密码 |
| ✅ XSS 输出转义 | escapeHtml() 函数转义 & < > ",用户内容渲染前均经过处理 |
| ✅ Session 持久化 | 使用 session-file-store 持久化到文件,非内存存储 |
| ✅ SameSite Cookie | 已设置 sameSite: 'lax',防御 CSRF 基础攻击 |
| ✅ 软删除机制 | 用户注销使用 deleted_at 标记,非物理删除,避免数据丢失 |
| ✅ 管理员鉴权中间件 | requireAdmin 统一校验 is_admin 字段 |
| ✅ 文件类型过滤 | Multer 限制仅允许 image/*,拒绝其他文件类型 |
| ✅ 文件大小限制 | 单文件 ≤ 5MB,JSON body ≤ 10MB |
| 文件 | 函数名 | 转义内容 | 评价 |
|---|---|---|---|
script.js |
escapeHtml |
& < > " |
⭐ 最完善,用于大部分渲染 |
chat.html |
escape |
& < > |
",但仅用于 textContent 场景,风险可控 |
profile.html |
escHtml |
& < > " |
⭐ 完善 |
keys.html |
escapeHtml |
& < > " |
⭐ 完善 |
admin.html |
escapeJs |
JS 字符串转义 | ⭐ 用于 onclick 参数,正确使用 |
所有 innerHTML 赋值经检查:
- 管理员后台:
escapeHtml(post.content.slice(0, 80))✅ - 朋友圈:
escapeHtml(post.content)+escapeHtml(comment.username)✅ - 聊天:
escape(s.content)—escape使用 DOM textContent 转义,安全 ✅ - 博客:
escapeHtml(blog.content)(摘要展示)✅
未发现未转义的用户输入直接写入 innerHTML 的情况。
// Multer 配置
filename: Date.now() + '-' + Math.round(Math.random()*1E9) + ext
fileFilter: 仅允许 mimetype.startsWith('image/')
limits: { fileSize: 5 * 1024 * 1024 }- ✅ 文件名随机化,避免覆盖冲突
- ✅ 文件类型白名单(MIME 检查)
- ✅ 大小限制
⚠️ 建议增加:文件扩展名与 MIME 类型一致性校验(防.php.jpg绕过)
| # | 问题 | 状态 |
|---|---|---|
| 1 | Session Secret 环境变量化 | ✅ 已修复 |
| 2 | 管理员密码环境变量化 | ✅ 已修复 |
| 3 | 移除启动日志密码明文 | ✅ 已修复 |
| 4 | SQL 中硬编码用户名参数化 | ✅ 已修复 |
| 5 | 视频功能彻底移除 | ✅ 已修复(前端 + 后端 + 数据库清理) |
| 6 | 访问密钥系统 | ✅ 新增功能 |
- 设置环境变量:
export SESSION_SECRET="$(openssl rand -hex 32)" export ADMIN_PASS="你的强密码"
- 启用 HTTPS + 设置
cookie.secure = true - 安装 helmet:
npm install helmet,app.use(helmet()) - 前置限流:Nginx
limit_req_zone或 Cloudflare Rate Limiting - 定期备份:
database.sqlite每日备份 - 日志审计:监控
/api/login异常登录行为
审计完成。所有高危问题已修复,中危问题附有改进建议。