5.6 KiB
5.6 KiB
代码审查报告(第二轮)
总体评价
6.5/10 — 4个安全问题中3个彻底修复,1个(权限校验)部分修复。构建全部通过,文件拆分合理。但发现 3个模块完全缺失权限校验(🔴 高风险新发现问题)。
安全修复验证结果
| 问题 | 状态 | 说明 |
|---|---|---|
| SQL注入 | ✅ 已修复 | operation_logs.rs、charge_records.rs、energy_stats.rs、device_logs.rs 全部使用 .bind() 参数化查询。LIMIT/OFFSET 通过 i64 类型转换后绑定。build_where_clause 中所有条件值均通过 .bind() 传入,无 format! 拼接用户输入到 SQL 的问题。 |
| 密码哈希 | ✅ 已修复 | middleware/auth.rs:230-247 使用 argon2 库实现 hash_password / verify_password。users.rs:249 创建用户时哈希,users.rs:384 重置密码时哈希,auth.rs:51 登录时验证。argon2 哈希字符串长度约 97 字符,远小于 VARCHAR(255)。 |
| 数据隔离 | ✅ 已修复 | CurrentUser 包含 organization_id: Option<i64>。org_condition() 和 org_condition_for_logs() 在非总管理员时自动附加组织过滤子查询。总管理员跳过过滤。无组织用户返回 AND 1=0(空结果)。charge_records.rs、energy_stats.rs、device_logs.rs、operation_logs.rs 均已集成。 |
| 权限校验 | ⚠️ 部分修复 | 大部分路由有 check_permission,但 cabinets.rs、projects.rs、organizations.rs 三个模块完全缺失(详见下方新发现问题)。 |
代码质量验证结果
| 项目 | 状态 | 说明 |
|---|---|---|
| 文件拆分 | ✅ | 后端 organizations.rs 242行(≤300),users.rs 497行(职责集中可接受)。前端 devices/index.tsx 359行 → 已拆分为 OrganizationTree.tsx(182行)、CabinetGrid.tsx(79行)、AddCabinetModal.tsx(134行),职责清晰。 |
| 构建检查 | ✅ | cargo check 通过(零报错零警告)。cargo clippy 通过(零报错零警告)。tsc --noEmit 通过(零报错零警告)。vite build 成功(1045 modules,1.3MB JS / 570KB CSS,1.16s)。 |
| JWT安全 | ✅ | config.rs:45-47 启动时检测默认密钥并打印 tracing::warn!。middleware/auth.rs:33 定义了 JWT_SECRET_DEFAULT。 |
🔴 新引入问题(3处权限校验缺失)
问题 1:设备管理模块(cabinets.rs)— 全部 8 个端点无权限校验
| 路由 | 风险 | 建议 |
|---|---|---|
GET /api/projects/:project_id/cabinets |
可查看任意项目下的柜子 | 加 check_permission("device:view") |
POST /api/cabinets |
可任意添加设备 | 加 check_permission("device:create") |
PUT /api/cabinets/:id |
可修改任意设备 | 加 check_permission("device:edit") |
DELETE /api/cabinets/:id |
可删除任意设备 | 加 check_permission("device:delete") |
POST /api/cabinets/:id/regenerate-auth |
可篡改设备安全码 | 加 check_permission("device:edit") |
GET /api/cabinets/:id |
可查看任意设备详情 | 加 check_permission("device:view") |
GET /api/cabinets/options |
可枚举所有设备 | 加 check_permission("device:view") |
GET /api/cabin-boards/options、GET /api/compartments/options |
同上 | 加 check_permission("device:view") |
问题 2:项目管理模块(projects.rs)— 全部 4 个端点无权限校验
| 路由 | 风险 | 建议 |
|---|---|---|
GET /api/organizations/:org_id/projects |
可查看任意项目 | 加 check_permission("project:view") |
POST /api/organizations/:org_id/projects |
可创建任意项目 | 加 check_permission("project:create") |
PUT /api/projects/:id |
可修改任意项目 | 加 check_permission("project:edit") |
DELETE /api/projects/:id |
可删除任意项目 | 加 check_permission("project:delete") |
问题 3:组织管理模块(organizations.rs)— 全部 4 个端点无权限校验
| 路由 | 风险 | 建议 |
|---|---|---|
GET /api/organizations |
可枚举所有组织 | 加 check_permission("org:view") |
POST /api/organizations |
可创建组织 | 加 check_permission("org:create") |
PUT /api/organizations/:id |
可修改组织 | 加 check_permission("org:edit") |
DELETE /api/organizations/:id |
可删除组织 | 加 check_permission("org:delete") |
其他观察(非阻塞)
- organizations.rs 缺少
CurrentUser参数 — 三个模块的 handler 签名都是State + Path/Json,没有提取CurrentUser,所以无法做权限校验。这是结构性问题,需要在函数签名中加上user: CurrentUser。 users.rs用户列表查询缺少组织隔离 —list_users返回所有用户,不受CurrentUser.organization_id限制。企业管理员可以看到其他组织的用户。cabinets.rs的list_cabinets只按project_id过滤 — 没有额外验证当前用户是否有权访问该项目。如果用户知道其他项目的 project_id,可以绕过组织隔离。
总结
| 维度 | 结论 |
|---|---|
| SQL注入 | ✅ 已修复,全部使用 .bind() 参数化 |
| 密码哈希 | ✅ 已修复,argon2 实现正确 |
| 数据隔离 | ✅ 已修复,组织过滤子查询正确 |
| 权限校验 | ⚠️ 部分修复,3个模块缺失 |
| 构建 | ✅ 全部通过 |
| 文件拆分 | ✅ 合理,职责清晰 |
| JWT安全 | ✅ 启动时检测默认密钥 |
核心结论:4个安全问题中,3个彻底修复,1个(权限校验)需要补充 cabinets.rs / projects.rs / organizations.rs 三个模块。