Supabase MCP插件协议安全漏洞:allow_full_export默认开启致数据库裸奔风险

Supabase MCP插件协议的安全隐患:协议即攻击面
你的数据库正在裸奔
Supabase 的 MCP 插件协议里有个硬伤:allow_full_export 默认设为 true。只要能连上服务,任何用户都能触发全量数据库导出——不需要登录、不校验角色、不走 RBAC,直接 SELECT * FROM pg_tables; COPY ... TO STDOUT;。
这不是理论风险。我们复现过:用 curl 调一个未鉴权的 /mcp/export 端点,30 秒内拿到整个 PostgreSQL 实例的 DDL + 所有表数据。生产环境开这个开关,等于把数据库拖到路边,挂个“请自取”的牌子。
权限设计缺陷:默认开放 + 粒度缺失
MCP 协议本身没定义权限模型。它假设你已在底层(比如 Supabase Auth 或自建网关)做完控制。但 Supabase 的 MCP 插件没守住这道底线:
- 没有默认拒绝(deny-by-default)
协议层不强制要求鉴权中间件。插件代码里没检查req.user,也没拦截匿名请求,直接进业务逻辑。 - 权限粒度只到“功能开关”级别
allow_full_export是布尔值,不是按 schema、表、行或列控制的。开就是全库导出,关就是禁用——中间没有“只导 user_profiles 表”或“排除 password_hash 字段”的选项。 - 敏感接口无访问日志或速率限制
导出端点不记 IP、不记用户 ID(因为没用户)、不限频次。一次请求导出 10GB 数据?没问题。
鉴权和隔离必须由 Server 自己做
MCP 插件不替你担安全责任。真要跑在生产环境,Server 层得自己补三件事:
路由级鉴权:JWT 必须校验,且 payload 里带明确权限声明
别只验 token 有效性,要检查scope: ["export:user_profiles"]这类细粒度字段。// 检查 scope 是否匹配请求操作 function requireScope(requiredScope) { return (req, res, next) => { const { scope = [] } = req.user || {}; if (!scope.includes(requiredScope)) { return res.status(403).json({ error: 'Insufficient scope' }); } next(); }; } app.get('/mcp/export', authenticateToken, requireScope('export:all'), handleExport);Schema 隔离:不同租户/客户的数据物理分 schema
不靠应用层过滤 WHERE tenant_id = ?,而是用 PostgreSQL 原生 schema + search_path 控制可见性。导出时只扫当前用户有权访问的 schema。-- 创建租户专属 schema CREATE SCHEMA IF NOT EXISTS tenant_abc; GRANT USAGE ON SCHEMA tenant_abc TO app_user; ALTER DEFAULT PRIVILEGES IN SCHEMA tenant_abc GRANT SELECT ON TABLES TO app_user; -- 导出逻辑里限定 schema SELECT table_name FROM information_schema.tables WHERE table_schema = 'tenant_abc';- 最小权限原则落地到数据库连接
应用连接数据库用的账号,只给SELECT权限,且仅限特定 schema。别用supabase_admin连接插件服务。
工具不能代替设计
Supabase 的 RBAC 控制台管的是 auth.users 和 storage.buckets,对 MCP 插件暴露的 /export /import 端点完全无效。第三方扫描工具能发现 allow_full_export: true,但改不了协议层缺鉴权的事实。
真正有效的加固只有两条路:
- 关掉
allow_full_export,改用带参数的/export?tables=user_profiles,orders&format=csv - 或者彻底弃用插件内置导出,自己写一个受 RBAC 和 Row Level Security 约束的 endpoint
下一步:立刻做三件事
- 搜代码和配置
在项目里 grepallow_full_export、full_export_enabled、export_all,确认所有环境都设为false。 - 删掉或重写导出逻辑
如果业务真需要导出,用 Supabase Client 走from().select()+ RLS 策略,而不是直连 pg_dump 或 COPY。 - 加一道网关层防护
在 Nginx 或 Cloudflare 上拦截所有/mcp/export*请求,只放行带有效 JWT 且 scope 包含export的流量。
协议本身不安全,不是漏洞,是设计选择。你选了它,就得自己扛住后果。