该文档记录的是修复前的审查结果,当前仓库代码已在此基础上继续整改,请结合最新实现一起判断。
审查时间:2026-03-13
审查对象:F:\设计\快速项目\AutoLableServer
当前版本不建议直接部署到生产环境。
主要原因不是单点缺陷,而是同时存在:
- 认证绕过
- 私有数据泄露
- 实际路由与文档/测试脚本不一致
- 生产配置项与代码读取逻辑不一致
- 社区公开数据模型与分类浏览逻辑割裂
综合判断:服务可以本地调试,但尚未达到“可直接部署”的标准。
已完成:
- 读取入口、配置、路由、服务层和数据持久化逻辑
- 本地启动服务
node index.js - 运行最小接口复现
运行态已确认:
- 未登录仅携带
x-user-id: u-1即可访问GET /api/auth/session GET /api/auth/session会返回完整用户对象,其中包含salt和passwordHash- 未登录可直接通过
GET /api/collections?userId=...枚举私有收藏夹 - 未登录可直接通过
GET /api/collections/:id?userId=...读取私有收藏夹详情 - 文档和测试脚本中的
GET /api/cards/public实际返回404
getUserFromRequest() 在没有有效 Bearer token 时,会直接信任请求头中的 x-user-id,然后把对应用户视为已登录用户。
证据:
services/auth.service.js:44-53services/auth.service.js:59-65
影响:
- 所有依赖
ensureUser()的受保护接口都可能被伪造身份访问 - 这不仅是读取问题,也意味着写操作接口同样可被冒用
部署判断:
- 这是直接阻断上线的问题
/api/auth/session 直接返回 authService.checkSession(req) 的结果,而该结果是完整用户对象,没有做字段裁剪。
证据:
routes/auth.routes.js:11-13services/auth.service.js:71-73
运行态复现:
- 未登录携带
x-user-id: u-1访问/api/auth/session - 服务返回了
salt与passwordHash
影响:
- 攻击者可同时完成身份伪造与密码哈希枚举
- 这会显著放大认证绕过造成的安全后果
部署判断:
- 这是直接阻断上线的问题
收藏夹读取接口没有真正基于登录态做鉴权,而是信任 URL 查询参数中的 userId。
证据:
routes/collection.routes.js:12-20routes/collection.routes.js:30-38services/collection.service.js:12-15services/collection.service.js:38-49
运行态复现:
- 注册新用户后系统自动创建默认私有收藏夹
- 未登录直接请求
GET /api/collections?userId=<该用户ID>,可枚举其私有收藏夹 - 未登录直接请求
GET /api/collections/<收藏夹ID>?userId=<该用户ID>,可读取私有收藏夹详情
影响:
- 私有收藏夹元数据和内容都可能外泄
- 只要知道或猜到用户 ID,即可绕过“私有”限制
部署判断:
- 这是直接阻断上线的问题
实际公开社区卡片入口是 /api/published,但文档和测试脚本仍把 /api/cards/public 作为公开查询接口。
证据:
- 实际注册:
routes/index.js:29-42 - 文档描述:
README.md:104-113 - 测试脚本:
test-api.js:134-137
运行态复现:
GET /api/cards/public返回404
影响:
- 现有客户端或联调脚本若按文档接入,会直接失败
- 说明接口契约尚未稳定,部署后前后端联调风险高
部署判断:
- 不一定阻断服务启动,但足以阻断稳定上线
社区公开卡片由 publish.service.js 写入 publishedCards,但分类接口 category.service.js 查询的却是普通 cards。
证据:
- 社区发布写入:
services/publish.service.js:23-78 - 社区公开列表读取:
services/publish.service.js:124-167 - 分类读取普通卡片:
services/category.service.js:35-43
影响:
- 通过
/api/published/publish发布的社区卡片,不一定能在/api/categories/:id/cards中出现 - 这会造成“社区首页有数据,但分类页为空或不一致”的行为缺陷
部署判断:
- 这是明显的业务逻辑不闭合问题
代码实际读取的是 COMMUNITY_PORT 和 COMMUNITY_SESSION_TTL_MS,但 .env.example、README 和 docker-compose.yml 配置的是 PORT 和 SESSION_TTL_MS。
证据:
- 代码读取:
config/constants.js:7-10 - 示例配置:
.env.example:4-11 - Docker 配置:
docker-compose.yml:10-14 - README 说明:
README.md:130-138
影响:
- 运维按文档设置环境变量,可能根本不会生效
- 端口和 Session TTL 实际上被硬编码默认值接管
部署判断:
- 这是明显的部署链路不健全问题
服务入口把 CORS 固定为 origin: '*',同时设置 credentials: true,并未读取 .env 中的 CORS_ORIGIN。
证据:
index.js:14-18.env.example:10-11docker-compose.yml:10-14README.md:230-233
影响:
- 文档中宣称可通过
CORS_ORIGIN限制来源,但实际代码并未接通 origin: '*'与credentials: true组合本身也不适合需要凭证的浏览器跨域场景
部署判断:
- 生产跨域行为不可控,不建议直接上线
种子数据中预置了 demo 用户,但没有预置 passwordHash 和 salt。登录逻辑会在用户没有密码哈希时,使用本次提交的密码为该用户即时补写密码。
证据:
- 种子用户:
config/constants.js:47-48 - 首次登录补写密码:
services/auth.service.js:23-29 - 登录逻辑:
services/auth.service.js:98-100
影响:
- 全新部署后,第一个用
demo登录的人会实际接管该账号 - 这对演示环境或首次上线环境尤其危险
部署判断:
- 即使不是阻断项,也不应带着该逻辑进入生产
当前使用 JSON 文件直接读写整个状态,没有事务、锁或并发控制。
证据:
data/storage.js:13-17data/storage.js:72-79data/index.js中多处写操作都会直接saveData(...)
影响:
- 单进程、小流量下可以工作
- 但并不适合高并发、故障恢复或多实例部署
说明:
- 这一点 README 也已经提示更适合换成数据库
- 单独看它不是“现在一定跑不起来”的问题,但会限制生产稳定性
仓库根目录存在 data.json、sessions.json,data/ 目录下也存在实际被代码使用的 data/data.json、data/sessions.json。
影响:
- 容易误以为根目录数据文件在生效
- 排障和备份路径容易混淆
结论:不可以。
原因:
- 认证边界已失效
- 私有数据可被未授权读取
- 公开路由契约与文档、测试脚本不一致
- 社区发布与分类浏览逻辑不一致
- 生产配置项与实际代码读取不一致
建议至少完成以下修复后再进入部署验证:
- 删除
x-user-id作为认证依据,只接受有效的 Bearer token /api/auth/session、/api/auth/login等接口只返回脱敏后的用户字段- 收藏夹读取接口改为基于认证用户做权限判断,禁止通过查询参数冒充身份
- 统一“公开社区卡片”的正式路由,并同步修正文档、测试脚本和客户端
- 统一社区公开数据源,避免
publishedCards与cards并行造成分类页错乱 - 统一环境变量命名,确保代码、
.env.example、README、compose 一致 - 让 CORS 真正读取配置,并按生产域名白名单生效
- 移除或重构
demo种子账号逻辑,避免首次登录认领 - 评估是否继续使用 JSON 文件存储;若用于生产,建议切换数据库
AutoLableServer 当前实现不具备直接部署条件。
如果只是内网自测或单人临时使用,可以运行;如果目标是公网部署或正式联调,当前版本风险过高,建议先完成上述修复再上线。