摘要:MCP协议实战解析:Server鉴权加固与合规商业化路径Supabase漏洞事件:一个真实的权限失控现场Hacker News上那篇题为“Supabase MCP漏洞可导出全库SQL”的帖子不是假设,是真实发生的越权读取。攻击者没用0day,只靠一个未校验租户上下文的/v1/sql端点,加上默认开启的pg_dump权限,就拿到了整个PostgreSQL实例的结构和数据。问题不在Supabas...
MCP协议实战解析:Server鉴权加固与合规商业化路径Supabase漏洞事件:一个真实的权限失控现场
Hacker News上那篇题为“Supabase MCP漏洞可导出全库SQL”的帖子不是假设,是真实发生的越权读取。攻击者没用0day,只靠一个未校验租户上下文的/v1/sql端点,加上默认开启的pg_dump权限,就拿到了整个PostgreSQL实例的结构和数据。
问题不在Supabase本身,而在MCP Server实现层:它把“支持MCP协议”等同于“实现了MCP传输层”,却漏掉了最关键的租户隔离逻辑——没有在SQL执行前绑定current_user、没做schema级访问控制、也没校验请求头里的X-MCP-Tenant-ID是否匹配连接池中的实际租户。
这个漏洞暴露的不是MCP协议设计缺陷,而是Server开发者对协议语义的误读:MCP不定义权限模型,它只约定数据如何流动;权限必须由Server自己落地,且必须贯穿到每一行SQL、每一个HTTP响应头、每一次文件写入。
MCP Server权限控制的三个落地层
MCP协议文档里写的是“Server应确保多租户数据隔离”,但没说怎么确保。真正起作用的只有三层:
1. 连接层隔离(最基础也最容易被绕过)2. 查询层拦截(核心防线)
# 正确做法:在SQL解析阶段注入租户约束
def execute_sql(tenant_id: str, raw_sql: str) -> List[dict]:
# 1. 拦截DDL(禁止租户创建新schema)
if re.search(r'\b(CREATE|ALTER|DROP)\s+(SCHEMA|DATABASE)\b', raw_sql, re.I):
raise PermissionError("Tenant not allowed to manage schemas")
# 2. 自动重写SELECT语句,添加租户过滤
if raw_sql.strip().upper().startswith('SELECT'):
# 解析AST,找到FROM子句,对每个表注入WHERE tenant_id = ?
rewritten = inject_tenant_filter(raw_sql, tenant_id)
return run_query(rewritten, tenant_id)
# 3. 其他语句直接校验权限位
if not has_permission(tenant_id, 'sql_exec'):
raise PermissionError("SQL execution denied for tenant")
3. 响应层净化(最后一道闸)鉴权加固:从补丁到架构
Supabase事件后,我们重构了MCP Server的鉴权链,不再依赖单一Token校验,而是构建三级校验:
传输层校验:验证Authorization: Bearer 签名与有效期协议层校验:检查X-MCP-Request-ID是否在白名单内(防重放),X-MCP-Client-Version是否兼容业务层校验:根据X-MCP-Tenant-ID查租户策略表,确认本次请求的操作类型(sql_exec, file_read, config_update)是否被授权
关键改动在tenant_policy表结构:
CREATE TABLE tenant_policy (
id SERIAL PRIMARY KEY,
tenant_id TEXT NOT NULL,
operation TEXT NOT NULL CHECK (operation IN ('sql_exec', 'file_read', 'file_write', 'config_update')),
allowed BOOLEAN DEFAULT true,
max_rows INTEGER DEFAULT 10000,
timeout_ms INTEGER DEFAULT 5000,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- 策略生效示例
INSERT INTO tenant_policy (tenant_id, operation, allowed, max_rows)
VALUES ('acme-corp', 'sql_exec', true, 50000);
每次SQL执行前,查询该表并动态设置statement_timeout和LIMIT:
-- 在连接中执行
SET statement_timeout = 5000;
-- 在SQL末尾自动追加
-- LIMIT 50000
商业化落地:一个Agent项目的硬核变现路径

我们做的跨云数据同步Agent,上线6个月后开始收费。没走“免费版限功能”路线,而是用安全能力倒逼付费:
收费锚点直指合规痛点功能免费版付费版($299/月)
租户数据隔离
进程级隔离
数据库实例级隔离
SQL审计日志
仅记录成功操作
记录完整SQL+参数+执行计划
敏感字段脱敏
不支持
自动识别PII字段并AES加密
合规报告
自动生成SOC2/ISO27001模板
客户采购决策不是因为“功能多”,而是因为法务部明确要求:“生产环境必须满足租户间数据库实例隔离”。
关键转化动作下一步:把鉴权变成产品能力
别再把权限控制当成安全团队的补丁任务。把它做成可配置、可审计、可计费的产品模块:
真正的商业化,始于把安全约束翻译成客户愿意付费的确定性。