fix(security): close unauthenticated CMA user API surface + audit tool (cma-api-auth-surface-audit-20260914)
Root cause: main.py include_router had no global auth dependency; user routers (products/cost/predict/...) relied on assert_entity_scope, which treats a missing session token as the Bot service channel and lets the request through. Result: 46 user endpoints returned data without any token on a public site. Changes: - auth_middleware.py: add require_auth_401 (missing Bearer -> 401, delegates to require_auth otherwise); 401/403 semantics are explicit. - router-level Depends(require_auth_401) on products, cost, predict, notifications, permissions, tenant, alignment; endpoint-level on /auth/roles and /admin/cache/clear. - deps.py: document that get_entity_id/assert_entity_scope are NOT auth. - frontend: add the missing Bearer header to 5 tokenless fetch/axios calls that hit the newly protected endpoints (KPIAlignment x2, RolePermissions x2, Dashboard x1). - tests: new test_api_auth_surface_20260914.py (58 cases: no-token 401, token 200, cross-entity 403, bot channel unchanged); adapt test_predict / test_kpi_forecast to send session tokens like production. - scripts/audit_api_auth_surface.py: reusable FastAPI dependency-graph audit (423 endpoints; A bot / B gap / C public), exits 1 when a B-class gap exists.
This commit is contained in:
@@ -116,6 +116,15 @@ def assert_entity_scope(
|
||||
- 会话 token 绑定实体存在(登录用户):explicit 与之不符 → 403(含 0=全部)
|
||||
- 无 token(Bot 服务通道):explicit 需存在且 active,否则 403(防越权注入)
|
||||
返回会话账套 entity_id(无 token → None,由调用方按原口径兜底)。
|
||||
|
||||
⚠️ 契约(cma-api-auth-surface-audit-20260914):本函数**不是鉴权**。
|
||||
「无 token → 按 Bot 服务通道放行」这一分支**仅对真正以 X-BOT-KEY 鉴权的 Bot 端点有效**
|
||||
(bot_bridge / bot_kpis / bot_iron_law / bot_suggestions / cash_vouchers_json 等,
|
||||
见 app/api/bot_bridge.py 的 verify_bot_key)。
|
||||
用户端点(前端 Bearer 调用)**必须**在 router 级或端点级挂 `require_auth` /
|
||||
`require_auth_401`;否则未挂鉴权的用户端点 = 公开可访问(无 token 直接取数/写数)。
|
||||
自查:`grep -n 'require_auth' app/api/<文件>.py` 无命中 且 该文件路由非 /api/cma/bot* →
|
||||
即存在鉴权缺口。
|
||||
"""
|
||||
session_entity = get_session_entity(request)
|
||||
if session_entity is not None:
|
||||
|
||||
Reference in New Issue
Block a user