# 任务010:安全修复 ## 目标 修复代码审查发现的4个严重安全问题。 ## 修复清单 ### 1. SQL注入修复( 高优先级) **问题位置:** - `src/routes/operation_logs.rs:49-63` - `src/routes/charge_records.rs:130` - `src/routes/energy_stats.rs:341` **修复方案:** 将所有 `format!` 拼接的SQL改为参数化查询。 ```rust // 错误示例(operation_logs.rs) let sql = format!( "SELECT * FROM operation_logs WHERE action = '{}' AND created_at >= '{}'", action.replace("'", "''"), start_time ); // 正确示例 let sql = "SELECT * FROM operation_logs WHERE action = $1 AND created_at >= $2"; sqlx::query_as(sql) .bind(&action) .bind(&start_time) ``` **涉及文件:** - `src/routes/operation_logs.rs` - `src/routes/charge_records.rs` - `src/routes/energy_stats.rs` - `src/routes/downloads.rs` ### 2. 密码哈希(🔴 高优先级) **问题位置:** `src/routes/auth.rs:51` **修复方案:** 集成 `argon2` crate,密码存储和验证使用哈希。 ```rust // Cargo.toml 添加 argon2 = "0.5" // 密码哈希(创建/重置用户时) use argon2::{ password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, SaltString}, Argon2, }; fn hash_password(password: &str) -> Result { let salt = SaltString::generate(&mut OsRng); let argon2 = Argon2::default(); let hash = argon2.hash_password(password.as_bytes(), &salt)?; Ok(hash.to_string()) } // 密码验证(登录时) fn verify_password(password: &str, hash: &str) -> Result { let parsed_hash = PasswordHash::new(hash)?; let argon2 = Argon2::default(); Ok(argon2.verify_password(password.as_bytes(), &parsed_hash).is_ok()) } ``` **涉及文件:** - `src/routes/auth.rs` — 登录验证改用 `verify_password` - `src/routes/users.rs` — 创建/重置密码改用 `hash_password` - `src/db/migrate.rs` — users表password字段长度改为255(argon2哈希较长) ### 3. 组织级数据隔离(🔴 高优先级) **问题位置:** - `src/routes/organizations.rs` 全部路由 - `src/routes/charge_records.rs` - `src/routes/device_logs.rs` - `src/routes/energy_stats.rs` **修复方案:** 在 `CurrentUser` 中携带 `organization_id`,查询时自动过滤。 ```rust // middleware/auth.rs 修改 pub struct CurrentUser { pub user_id: i64, pub role_level: i32, // 0普通 1企业管理员 2总管理员 pub organization_id: Option, // 新增 pub permissions: HashSet, } // 查询时根据角色自动过滤 pub fn apply_org_filter(query: &str, user: &CurrentUser) -> String { if user.role_level >= 2 { // 总管理员看全部 query.to_string() } else if let Some(org_id) = user.organization_id { // 企业管理员只看本组织 format!("{} WHERE organization_id = {}", query, org_id) } else { format!("{} WHERE 1=0", query) // 无组织用户看不了 } } ``` **涉及文件:** - `src/middleware/auth.rs` — CurrentUser增加organization_id - `src/routes/organizations.rs` — 所有查询加组织过滤 - `src/routes/charge_records.rs` — 加组织过滤 - `src/routes/device_logs.rs` — 加组织过滤 - `src/routes/energy_stats.rs` — 加组织过滤 ### 4. 补充权限校验(🟡 中优先级) **问题位置:** - `src/routes/charge_records.rs:158` - `src/routes/device_logs.rs:62` - `src/routes/energy_stats.rs:81-283` - `src/routes/downloads.rs:87` **修复方案:** 为每个路由添加对应的 `check_permission` 调用。 ```rust // 示例 #[get("/api/charge-records")] async fn list_charge_records( user: CurrentUser, pool: State, query: Query, ) -> Result>> { auth::check_permission(&user, "charge_record:view")?; // 新增 // ... 原有逻辑 } ``` **权限码对应:** - 充电记录 → `charge_record:view` - 设备日志 → `device_log:view` - 能耗统计 → `energy:view` - 下载中心 → `charge_record:export` 或 `energy:export` ## 质量约束 1. 完成代码后执行 `cargo check` + `cargo clippy`,零报错零警告 2. 分层拆分,单函数≤80行,命名语义化,完整注释 3. 所有外部IO/网络请求异常捕获,禁止裸panic 4. 分支逻辑全覆盖,不遗漏兜底分支 5. 常量抽离,不使用废弃API 6. Rust内存安全,合理管理所有权,禁用unsafe无合理理由 7. 修复后重新运行审查清单中的安全项目,确保全部通过