Supabase MCP安全漏洞詳解:allow_unrestricted_queries配置錯誤致PostgreSQL全庫泄露
摘要:Supabase MCP安全漏洞實戰警示:SQL數據庫全量泄露是怎么發生的?MCP配置錯誤導致全庫泄露的真實案例Hacker News上有個開發者貼出自己的事故復盤:他用Supabase MCP連接PostgreSQL,只改了一行配置,結果整個數據庫被爬空。問題出在supabase.toml里這行:[database] # 錯誤配置:允許任意客戶端執行任意查詢 allow_unrestric...
Supabase MCP安全漏洞實戰警示:SQL數據庫全量泄露是怎么發生的?
MCP配置錯誤導致全庫泄露的真實案例
Hacker News上有個開發者貼出自己的事故復盤:他用Supabase MCP連接PostgreSQL,只改了一行配置,結果整個數據庫被爬空。
問題出在supabase.toml里這行:
[database]
# 錯誤配置:允許任意客戶端執行任意查詢
allow_unrestricted_queries = trueMCP Server啟動后,攻擊者直接連上mcp://<host>:6543,發了個SELECT * FROM users;,接著是SELECT * FROM payments;,最后把整庫pg_dump走。沒有認證繞過,沒有0day,純屬配置放開+暴露端口。
MCP協議本身不危險,危險的是默認行為和權限模型
MCP不是新協議,它是Supabase為簡化多云數據同步封裝的一層gRPC/HTTP網關。它的風險點很具體:
- 端口暴露即入口:MCP Server默認監聽
6543(非PostgreSQL原生端口),但只要防火墻放行、沒配TLS或IP白名單,就等于把數據庫門把手焊死在大街上 - 權限繼承混亂:MCP不自動繼承PostgreSQL的行級策略(RLS)。你數據庫里開了
ENABLE ROW LEVEL SECURITY,MCP照樣能繞過——除非顯式啟用enable_rls = true并綁定策略函數 - 角色映射缺失:Supabase Auth的
auth.uid()在MCP上下文中默認不可用。不手動注入x-user-id頭或配置JWT解析,所有請求都以postgres超級用戶身份執行
三個必須落地的防護動作
1. 權限隔離:砍掉所有“全局”權限
Supabase MCP不支持GRANT ALL ON DATABASE這種粗粒度授權。必須按表、按列、按操作精確控制:
// 正確做法:創建專用MCP角色,僅授予必要權限
await supabase.rpc('create_mcp_role', {
role_name: 'mcp_reader',
schema: 'public',
table: 'orders',
columns: ['id', 'status', 'created_at'],
permissions: ['SELECT']
});對應SQL:
-- 在PostgreSQL中執行
CREATE ROLE mcp_reader;
GRANT USAGE ON SCHEMA public TO mcp_reader;
GRANT SELECT(id, status, created_at) ON TABLE public.orders TO mcp_reader;
-- 禁止該角色訪問敏感表
REVOKE ALL ON TABLE public.payments FROM mcp_reader;2. 策略校驗:用RLS兜底,別信應用層過濾
MCP支持透傳RLS策略,但需要顯式開啟。在supabase.toml中:
[database]
# 必須設為true,否則RLS完全失效
enable_rls = true
[database.rls_policies]
# 綁定策略函數到具體表
"public.orders" = "user_can_read_order"對應的策略函數:
CREATE POLICY user_can_read_order ON public.orders
FOR SELECT
USING (auth.uid() = user_id OR is_admin());3. RBAC集成:把Auth角色映射到MCP會話
MCP Server啟動時需加載Supabase JWT密鑰,并在請求頭中傳遞Authorization: Bearer <token>:
# 啟動命令必須包含JWT驗證配置
supabase start --mcp-jwt-secret=your-supabase-jwt-secret服務端自動解析role字段,映射到PostgreSQL角色。不需要手寫setAuth()——那是前端SDK的邏輯,MCP Server要的是后端可信身份。
復盤那個被拖庫的配置
回到開頭的事故,真正的問題鏈是:
supabase.toml中allow_unrestricted_queries = true(默認為false)- 防火墻開放了
6543端口給0.0.0.0/0 - 沒啟用
enable_rls = true,PostgreSQL的RLS策略形同虛設 - 數據庫連接池用的是
postgres超級用戶,而非最小權限角色
修復只需三步:
- 改
allow_unrestricted_queries = false - 改
enable_rls = true并綁定策略 - 把
DATABASE_URL里的postgres換成專用角色mcp_reader
別依賴課程,先做這三件事
安全不是學出來的,是改出來的:
- 立刻檢查你的
supabase.toml:搜allow_unrestricted_queries和enable_rls,確認值符合生產要求 - 登錄數據庫執行
\du:看是否存在mcp_*專用角色,且沒被賦予SUPERUSER或CREATEDB權限 - 用
nc -zv your-host 6543測試端口:如果公網可連,加防火墻規則或改用VPC內網通信
MCP本身沒問題。出問題的是把數據庫當玩具配的習慣。