空安全值命名空间混淆是运行时策略校验断层导致的越界,本质是系统将“空”或“未声明”的租户上下文误判为合法通配符而跳过隔离检查。

空安全值命名空间混淆不是语法错误,而是运行时策略校验断层引发的越界——本质是系统把“空”或“未声明”的租户上下文当成了合法通配符,跳过了关键隔离检查。
重点查三类“空值”逃逸路径
这类问题往往藏在边界条件里,不是常规请求能触发的。要主动构造空、缺、错、双等异常组合:
-
HTTP Header 空值伪造:发请求时显式设置
X-Tenant-ID: ""或完全不带该头,观察是否仍能通过网关、进入业务逻辑甚至返回数据 -
Kubernetes Namespace 空字符串绕过:调用 API Server 时故意使用路径如
/apis/example.com/v1/namespaces//secrets(注意双斜杠),验证 RBAC 是否因namespace=""被跳过 NamespaceScope 检查 -
JWT 声明缺失 + Header 冗余覆盖:用合法 token(但 payload 中无
tenant_id字段)配合任意X-Tenant-ID: fake-123,测试 MCP 或网关是否只校验 header、忽略 JWT 声明一致性
定位策略引擎失效点
不要只看代码,要抓策略实际生效位置:
- 在 Envoy / APISIX / Spring Cloud Gateway 的 Filter 链中,插入日志打印:
req.header("X-Tenant-ID") + " | jwt.tenant_id=" + jwt.getClaim("tenant_id") + " | ns=" + req.namespace() - 检查 Policy Server 日志,确认其输入 context 是否已含 namespace 字段;若日志中
namespace=null或namespace=""却返回allow:true,说明策略规则未设非空断言 - 对 Kubernetes Admission Webhook,用
kubectl auth can-i --list --as=system:serviceaccount:default:my-app模拟不同 namespace 下的权限,验证其是否对空 namespace 返回宽泛授权
验证数据库层是否兜底拦截
即使上层放行,数据库也应拒绝无租户约束的操作:
- 执行
EXPLAIN ANALYZE SELECT * FROM users WHERE id = 123;(不带 tenant_id 条件),确认执行计划是否命中全表扫描,且无隐式 tenant_id 过滤 - 在 HikariCP 连接池配置中启用
connection-init-sql=SET SESSION tenant_id = NULL,再发起查询,看是否报错或返回空结果——若仍成功返回数据,说明连接级租户绑定未生效或被忽略 - 对 PostgreSQL,检查
pg_roles和pg_namespace权限,确认是否存在publicschema 对所有角色开放写入,导致跨租户表可被意外访问
修复必须做两件事
单点补丁治标,机制加固才能治本:
- 在所有租户上下文提取入口(Filter、Interceptor、Webhook Handler)强制校验非空:
if (tenantId == null || tenantId.trim().isEmpty()) { throw new AccessDeniedException("tenant_id required"); } - 策略配置中显式禁止空值:Policy Server 的 Rego 规则需包含
input.namespace != "",K8s RBAC RoleBinding 必须指定namespace: xxx,禁用namespace: ""或省略字段的写法

















