86 lines
5.6 KiB
Markdown
86 lines
5.6 KiB
Markdown
|
|
# 代码审查报告(第二轮)
|
|||
|
|
|
|||
|
|
## 总体评价
|
|||
|
|
|
|||
|
|
**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")` |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 其他观察(非阻塞)
|
|||
|
|
|
|||
|
|
1. **organizations.rs 缺少 `CurrentUser` 参数** — 三个模块的 handler 签名都是 `State + Path/Json`,没有提取 `CurrentUser`,所以无法做权限校验。这是结构性问题,需要在函数签名中加上 `user: CurrentUser`。
|
|||
|
|
2. **`users.rs` 用户列表查询缺少组织隔离** — `list_users` 返回所有用户,不受 `CurrentUser.organization_id` 限制。企业管理员可以看到其他组织的用户。
|
|||
|
|
3. **`cabinets.rs` 的 `list_cabinets` 只按 `project_id` 过滤** — 没有额外验证当前用户是否有权访问该项目。如果用户知道其他项目的 project_id,可以绕过组织隔离。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 总结
|
|||
|
|
|
|||
|
|
| 维度 | 结论 |
|
|||
|
|
|------|------|
|
|||
|
|
| SQL注入 | ✅ 已修复,全部使用 `.bind()` 参数化 |
|
|||
|
|
| 密码哈希 | ✅ 已修复,argon2 实现正确 |
|
|||
|
|
| 数据隔离 | ✅ 已修复,组织过滤子查询正确 |
|
|||
|
|
| 权限校验 | ⚠️ 部分修复,3个模块缺失 |
|
|||
|
|
| 构建 | ✅ 全部通过 |
|
|||
|
|
| 文件拆分 | ✅ 合理,职责清晰 |
|
|||
|
|
| JWT安全 | ✅ 启动时检测默认密钥 |
|
|||
|
|
|
|||
|
|
**核心结论:4个安全问题中,3个彻底修复,1个(权限校验)需要补充 cabinets.rs / projects.rs / organizations.rs 三个模块。**
|