国产日韩欧美-97在线观看免费-亚洲欧洲日韩-亚洲free性xxxx护士白浆-国产精品网站在线观看-日韩有码一区-日本大片在线观看-欧美精品一区二区性色a+v-97在线精品-亚洲久草视频-天天操人人爽-你懂的国产精品-国产国语对白-就去干成人网-亚洲美女色视频

?? MCP生態

Supabase MCP插件權限校驗漏洞深度解析:防范數據庫裸奔導出風險

發布時間:2026-04-14 分類: MCP生態
摘要:Supabase MCP插件漏洞事件深度解析:如何避免“裸奔導出”風險漏洞本質:權限校驗被跳過,數據庫直接暴露Supabase MCP插件存在一個高危缺陷:它在處理MCP請求時,沒有強制驗證能力聲明(capability)是否真實來自可信令牌。攻擊者只需構造一個帶偽造 capability 聲明的 HTTP 請求(例如,手動設置 Authorization: Bearer ... 并篡改 p...

封面

Supabase MCP插件漏洞事件深度解析:如何避免“裸奔導出”風險

漏洞本質:權限校驗被跳過,數據庫直接暴露

Supabase MCP插件存在一個高危缺陷:它在處理MCP請求時,沒有強制驗證能力聲明(capability)是否真實來自可信令牌。攻擊者只需構造一個帶偽造 capability 聲明的 HTTP 請求(例如,手動設置 Authorization: Bearer ... 并篡改 payload),就能繞過所有權限檢查,直連 PostgreSQL 實例并執行 pg_dump 級別的全量導出。

這不是配置錯誤,而是代碼邏輯缺失——插件把 capability 當作輸入參數直接信任,沒做簽名驗證、作用域比對或上下文綁定。

MCP協議的關鍵約束,不是裝飾

MCP 協議本身不自動提供安全。它的機制只有在被嚴格執行時才起作用:

  • 能力聲明(Capability Declaration)
    是 JSON 對象,含 namedescriptionparameterspermissions 字段。permissions 字段必須明確列出所需數據庫權限(如 "supabase_read:public.users")。但聲明本身無加密或簽名,必須由服務端用令牌重新推導并校驗,不能直接信任客戶端傳入的值。
  • 權限沙箱機制(Permission Sandbox)
    不是進程隔離,而是運行時數據訪問控制。例如,一個聲明了 "supabase_read:public.orders" 的 capability,對應的實際數據庫查詢必須被硬編碼限制在 orders 表、只讀、且自動注入 WHERE tenant_id = ?(如果多租戶)。沙箱失效的根源,常在于 ORM 層未攔截原始 SQL 執行。
  • 認證與授權(Authentication and Authorization)
    MCP 要求每個請求攜帶 JWT。該 token 必須由可信簽發方(如 Supabase Auth)生成,payload 中需包含 sub(用戶 ID)、role(PostgreSQL 角色)、permissions(預計算的權限列表)和 exp。插件必須調用 supabase.auth.getUser() 或等效接口解碼并驗證 token,而不是僅檢查 Authorization 頭是否存在。

漏洞復現路徑(精簡版)

  1. 攻擊者用 Postman 發送請求:

    POST /mcp/execute HTTP/1.1
    Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
    Content-Type: application/json
    
    {
      "capability": {
        "name": "export_full_db",
        "permissions": ["supabase_read:*"]
      },
      "operation": "dump"
    }
  2. 插件解析 capability.permissions,發現 supabase_read:*,直接允許執行導出邏輯。
  3. 后端調用 pg_dump --dbname=... --format=custom,無租戶過濾、無行級安全(RLS)繞過檢查、無角色切換(仍以 postgresservice_role 運行)。

根本問題:插件把 capability 當作“指令”,而非“聲明”;把 token 當作“憑證”,而非“權威來源”。

防御性編碼:四條硬規則

  1. 能力聲明必須二次派生,不可信任客戶端輸入
    刪除所有直接解析請求體中 capability.permissions 的邏輯。改為從 JWT 中提取 permissions 字段,并與當前請求的操作做精確匹配:

    def handle_request(request):
        token = request.headers.get("Authorization", "").replace("Bearer ", "")
        if not token:
            return {"error": "missing token"}, 401
    
        try:
            payload = jwt.decode(token, SUPABASE_JWT_SECRET, algorithms=["HS256"])
        except jwt.InvalidTokenError:
            return {"error": "invalid token"}, 401
    
        # 從 token 中取權限,不是從 request.body
        allowed_perms = payload.get("permissions", [])
        required_perm = f"supabase_read:{request.table}"
    
        if required_perm not in allowed_perms and "supabase_read:*" not in allowed_perms:
            return {"error": "permission denied"}, 403
    
        # 繼續執行,但必須用受限角色連接 DB
        return execute_dump(request.table)
  2. 數據庫連接必須降權
    即使 token 有效,后端連接 PostgreSQL 時,絕不能使用 service_rolepostgres 用戶。應為每個租戶或每個能力組創建最小權限角色,并在連接時動態 SET ROLE

    -- 創建只讀角色
    CREATE ROLE mcp_read_only NOINHERIT;
    GRANT CONNECT ON DATABASE mydb TO mcp_read_only;
    GRANT USAGE ON SCHEMA public TO mcp_read_only;
    GRANT SELECT ON ALL TABLES IN SCHEMA public TO mcp_read_only;
    ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO mcp_read_only;

    Python 中連接后立即執行:

    conn.cursor().execute("SET ROLE mcp_read_only")
  3. 禁止原始 SQL 導出,改用受控快照
    pg_dump 是反模式。正確做法是:

    • 提前定義可導出的表清單(白名單)
    • 對每張表執行 COPY (SELECT * FROM table WHERE tenant_id = %s) TO STDOUT WITH CSV
    • 輸出流經內存緩沖,不寫磁盤,超時強制中斷
    • 導出文件名強制帶時間戳和哈希,不暴露原始表名
  4. 日志必須記錄權限決策鏈
    記錄不能只記“誰訪問了什么”,要記“為什么允許/拒絕”:

    logger.info(
        "mcp_request",
        extra={
            "user_id": payload["sub"],
            "requested_table": request.table,
            "token_permissions": payload.get("permissions", []),
            "allowed_by": "supabase_read:public.users" in payload.get("permissions", []),
            "status": "allowed" if allowed else "denied"
        }
    )

商業化切口:合規數據代理的真實機會

漏洞暴露的恰恰是市場缺口——企業需要有人替他們管住 Agent 的手。

一個可行的落地場景:

  • 某 SaaS 公司有 200 家客戶,每家數據隔離在獨立 schema(tenant_123)。
  • 他們想讓客服 Agent 查詢客戶訂單,但怕 Agent 寫錯 SQL 泄露其他租戶數據。

你的 Agent 服務不是“通用 MCP 網關”,而是:

  • Schema-aware 代理:收到 SELECT * FROM orders 時,自動重寫為 SELECT * FROM tenant_123.orders,且校驗 tenant_123 是否屬于當前 token 的 tenant_id 字段。
  • 字段級脫敏開關:配置 orders.credit_card_last4 字段對客服角色始終返回 ****,無需修改業務代碼。
  • 審計水印:所有導出 CSV 自動追加一行 # exported_by:agent-v2.1|tenant:123|timestamp:2024-05-22T08:30Z

收費模型更實際:

  • $300/月/租戶(按實際接入租戶數計費,非按 Agent 數量)
  • $1500 一次性配置費(含 RLS 規則審查 + 自動 schema 注入腳本)
  • 導出操作按次計費($0.02/次),抑制濫用

關鍵不是賣技術,是賣“責任轉移”——你簽 SLA,承諾數據不出界;他們省去內部安全團隊逐行審代碼。

部署 checklist:三步堵死漏洞

  1. 刪掉所有 capability 解析邏輯
    搜索代碼庫中的 request.json.get("capability")req.body.capability,全部刪除。權限只從 JWT 來。
  2. 強制連接降權
    在數據庫連接池初始化時,顯式設置 options="-c role=mcp_read_only"(libpq)或 connection_options={"options": "-c role=mcp_read_only"}(asyncpg)。測試時用 SELECT current_user, session_user, current_role 驗證。
  3. 上線前跑通這三條命令

    # 1. 確保無 service_role 連接
    psql -c "SELECT * FROM pg_stat_activity WHERE usename = 'service_role'"
    
    # 2. 確保 RLS 對所有敏感表啟用
    psql -c "SELECT schemaname, tablename, relrowsecurity FROM pg_tables WHERE schemaname = 'public' AND relrowsecurity = false"
    
    # 3. 模擬攻擊:用無效 token 請求,確認返回 401/403,不是 500 或數據
    curl -H "Authorization: Bearer invalid" https://your-api/mcp/export

漏洞修復不是加補丁,是重校準信任邊界:JWT 是唯一信源,數據庫角色是唯一執行主體,日志是唯一證據鏈。

返回首頁