MCP Server插件權(quán)限漏洞分析:修復(fù)未認(rèn)證訪問導(dǎo)致的數(shù)據(jù)庫泄露風(fēng)險(xiǎn)

MCP Server插件權(quán)限漏洞剖析:MCP協(xié)議安全邊界實(shí)戰(zhàn)筆記
一、真實(shí)問題現(xiàn)場
某MCP Server插件上線后不久,客戶反饋數(shù)據(jù)庫被全量導(dǎo)出。日志顯示,一個(gè)未認(rèn)證的HTTP請求調(diào)用了/tools/list_tools端點(diǎn),返回結(jié)果里赫然包含users、payments、auth_sessions等表名,以及字段定義和索引信息。攻擊者據(jù)此構(gòu)造SQL注入載荷,繞過應(yīng)用層直接讀取敏感數(shù)據(jù)。
這不是理論風(fēng)險(xiǎn)——是已發(fā)生的生產(chǎn)事故。
二、漏洞根因拆解
權(quán)限校驗(yàn)完全缺失
插件收到MCP請求時(shí),直接執(zhí)行工具邏輯,未檢查request.context.permissions字段。MCP協(xié)議要求Server在調(diào)用任何工具前驗(yàn)證權(quán)限上下文,但該插件把permissions當(dāng)成了可選字段處理。
后果很直接:任意客戶端(包括curl、Postman)都能觸發(fā)list_tools,而這個(gè)工具又沒做輸入過濾或輸出脫敏。
mcp.tools.list_tools暴露結(jié)構(gòu)信息
該工具本意是供Agent運(yùn)行時(shí)動態(tài)發(fā)現(xiàn)可用能力,但插件實(shí)現(xiàn)中:
- 直接返回了數(shù)據(jù)庫連接池的元數(shù)據(jù)(
pg_catalog查詢結(jié)果) - 未剝離
information_schema中的敏感字段(如column_default含密碼哈希邏輯) - 返回體未做角色過濾——管理員和訪客看到的工具列表完全一致
元數(shù)據(jù)不是“輔助信息”,它是攻擊鏈的第一塊墊腳石。
RBAC形同虛設(shè)
插件聲明支持RBAC,但實(shí)際只做了兩件事:
- 在配置文件里寫了
"role": "admin"硬編碼 - 所有工具函數(shù)都忽略
context.role參數(shù)
結(jié)果:普通用戶調(diào)用delete_user時(shí),代碼路徑和管理員完全相同。
三、Supabase場景下的放大效應(yīng)
當(dāng)MCP Server對接Supabase時(shí),問題更致命。Supabase默認(rèn)開啟Row Level Security(RLS),但前提是客戶端必須提供有效JWT。而該插件:
- 用服務(wù)端私鑰直連Supabase,繞過RLS
list_tools返回的表名直接映射到Supabase的公開視圖名- 攻擊者拿到
auth.users表結(jié)構(gòu)后,立刻用https://your-project.supabase.co/rest/v1/auth.users?select=*發(fā)起跨域請求
Supabase沒破防,是MCP Server把門鑰匙交給了路人。
四、守住MCP安全邊界的實(shí)操要點(diǎn)
協(xié)議規(guī)范的關(guān)鍵約束
MCP協(xié)議對權(quán)限的強(qiáng)制要求就三條,必須落地:
- 所有工具調(diào)用前,必須校驗(yàn)
context.permissions是否包含當(dāng)前操作所需scope list_tools返回的工具列表,必須按context.role動態(tài)過濾(例如user角色看不到db.dump)context對象不可被客戶端篡改——Server需用簽名驗(yàn)證其完整性
Server開發(fā)必須做的三件事
權(quán)限校驗(yàn)前置
在路由層統(tǒng)一攔截,拒絕permissions為空或缺失必要scope的請求:def require_permission(scope: str): if not request.context.permissions or scope not in request.context.permissions: raise PermissionError(f"Missing permission: {scope}")工具元數(shù)據(jù)嚴(yán)格分級
list_tools返回值按角色隔離:guest: 僅返回weather.get、calculator.adduser: 增加db.query(但隱藏table參數(shù)枚舉)admin: 才返回db.dump、system.exec
禁用危險(xiǎn)反射
禁止工具函數(shù)通過getattr()動態(tài)調(diào)用數(shù)據(jù)庫方法。所有DB操作必須顯式聲明依賴的表和字段,并在啟動時(shí)注冊白名單:# 正確:白名單驅(qū)動 DB_OPERATIONS = { "users.read": {"tables": ["users"], "fields": ["id", "email"]}, "payments.write": {"tables": ["payments"], "fields": ["amount", "status"]} }
商業(yè)化案例中的硬性紅線
醫(yī)療AI Agent的MCP Server部署時(shí),我們強(qiáng)制執(zhí)行:
- 所有數(shù)據(jù)庫操作必須走預(yù)編譯語句(
PreparedStatement),禁止拼接SQL context.permissions由OIDC ID Token解碼生成,不接受客戶端傳入的任何權(quán)限字段- 每次
list_tools調(diào)用觸發(fā)審計(jì)日志,記錄client_ip、user_role、timestamp - 敏感工具(如
db.export)需二次確認(rèn),且導(dǎo)出文件自動加密+72小時(shí)過期
這些不是“最佳實(shí)踐”,是HIPAA合規(guī)的底線。
五、m.gsdl.org.cn的定位
m.gsdl.org.cn不做MCP協(xié)議翻譯器,只做三件事:
- 把協(xié)議規(guī)范里的安全條款,轉(zhuǎn)換成可測試的代碼檢查清單(比如“
list_tools響應(yīng)體必須包含role字段”) - 公開真實(shí)漏洞的復(fù)現(xiàn)環(huán)境和修復(fù)diff(含Supabase、Postgres、MongoDB三套方案)
- 拆解商業(yè)化Agent的權(quán)限模型設(shè)計(jì)——從醫(yī)療到金融,每份架構(gòu)圖都標(biāo)注了MCP協(xié)議如何嵌入現(xiàn)有IAM體系
六、立刻能做的四件事
- 檢查你的
list_tools實(shí)現(xiàn)
用curl發(fā)個(gè)無權(quán)限請求:curl -X POST http://localhost:3000/tools/list_tools,看返回里有沒有數(shù)據(jù)庫表名或系統(tǒng)路徑。 給所有工具加權(quán)限守衛(wèi)
在每個(gè)工具函數(shù)開頭插入:assert "db.read" in context.permissions, "Permission denied"- 刪掉所有
eval()、exec()、getattr(..., user_input)
MCP工具必須是純函數(shù),輸入輸出完全可預(yù)測。 用Supabase RLS做最后一道閘
即使MCP Server出問題,也讓數(shù)據(jù)庫自己攔住非法查詢:ALTER TABLE users ENABLE ROW LEVEL SECURITY; CREATE POLICY select_own ON users FOR SELECT USING (auth.uid() = id);