fix(saas): 安全修复 — IDOR防护、SSRF防护、JWT密钥强制、错误信息脱敏、CORS配置化

- account: admin 权限守卫 (list_accounts/get_account/update_status/list_logs)
- relay: SSRF 防护 (禁止内网地址、限制 http scheme、30s 超时)
- config: 生产环境强制 ZCLAW_SAAS_JWT_SECRET 环境变量
- error: 500 错误不再泄露内部细节给客户端
- main: CORS 支持配置白名单 origins
- 全部 21 个测试通过 (7 unit + 14 integration)
This commit is contained in:
iven
2026-03-27 13:07:20 +08:00
parent 00a08c9f9b
commit 94bf387aee
9 changed files with 134 additions and 31 deletions

View File

@@ -12,10 +12,14 @@ const MAX_BODY_SIZE: usize = 1024 * 1024; // 1MB
async fn build_test_app() -> axum::Router {
use zclaw_saas::{config::SaaSConfig, db::init_memory_db, state::AppState};
// 测试环境设置开发模式 (允许 http、默认 JWT secret)
std::env::set_var("ZCLAW_SAAS_DEV", "true");
std::env::set_var("ZCLAW_SAAS_JWT_SECRET", "test-secret-for-integration-tests-only");
let db = init_memory_db().await.unwrap();
let mut config = SaaSConfig::default();
config.auth.jwt_expiration_hours = 24;
let state = AppState::new(db, config);
let state = AppState::new(db, config).expect("测试环境 AppState 初始化失败");
let public_routes = zclaw_saas::auth::routes();
@@ -174,7 +178,7 @@ async fn test_full_authenticated_flow() {
let resp = app.clone().oneshot(list_req).await.unwrap();
assert_eq!(resp.status(), StatusCode::OK);
// 查看操作日志
// 查看操作日志 (普通用户无 admin 权限 → 403)
let logs_req = Request::builder()
.method("GET")
.uri("/api/v1/logs/operations")
@@ -183,7 +187,7 @@ async fn test_full_authenticated_flow() {
.unwrap();
let resp = app.oneshot(logs_req).await.unwrap();
assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(resp.status(), StatusCode::FORBIDDEN);
}
// ============ Phase 2: 模型配置测试 ============