尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

MCP 安全配置避坑指南:密钥管理、Shell 权限与远程边界盘点

MCP 安全配置避坑指南:密钥管理、Shell 权限与远程边界盘点 我先说明一下这个选题的由来。最近帮团队搭 MCPModel Context Protocol服务配置完 Claude Code、Cursor 那一堆工具后总有人问我同一个问题MCP 配置到底需不需要做安全检查我的回答很直接——不是需要是必须。你想想MCP 服务器的本质是什么它给了 AI 一套能调用的工具这套工具里只要有一个能执行 Shell 命令、读写文件、访问数据库的能力就等于把一把半开的钥匙交了出去。钥匙本身没错问题是你能保证用钥匙的人不乱开锁吗这篇东西我从实际踩坑的角度出发把 Secret 管理、Shell 权限、Remote MCP 接入方式和权限边界这四个最关键的检查点完整过了一遍每一个都附上了测试过程和结论适合所有正在用或准备用 MCP 的人。1. 先弄清风险模型MCP 安全看哪几个点在动手检查之前必须先知道 MCP 的信任边界长什么样。MCP 的连接模型很简单一个客户端Claude Code、Cursor、自研 Agent连到一个或多个 MCP ServerServer 暴露若干工具客户端按需调用。问题恰恰出在这个“简单”上——工具是 AI 调的但 AI 的意图是用户给的如果用户被诱导AI 被越权调用工具整条链路的安全就全看 Server 这一层怎么兜。1.1 风险维度的三维拆解我把 MCP 的安全检查拆成三个维度检查时照着这个框架走基本不会漏。第一是 Secret 维度也就是配置里藏着的密钥。MCP Server 要调用外部 API通常需要 API Key、Access Token、数据库密码这些凭证放在哪儿、怎么传、会不会被客户端读走是第一个要查的。第二是 Shell 维度也就是 Server 暴露出来的命令执行能力。很多 MCP Server 提供 shell 工具帮用户执行本地命令这类工具的权限边界没划清楚AI 就能借着你的电脑跑任何命令这是最危险的一类。第三是 Remote 维度也就是 MCP 的传输层。MCP 可以用 stdio 走本机进程也可以用 SSE/HTTP 走远程一旦走网络鉴权、加密、来源校验就全都要跟上否则任何人只要能连到端口就能调用你的工具。1.2 信任模型本地和远程不能一个标准我见过很多人把本机用的 MCP 配置直接复制一份改成远端地址这是大忌。本地 stdio 模式的信任基础是“进程在谁的机器上跑、由谁启动”这个模型默认客户端可信所以工具调用比较放得开。Remote MCP 的信任基础完全不同你连的是一台服务器你根本不知道对面是谁在响应。所以检查的出发点必须区分信任模型本地 MCP 重点防“失手”防 AI 误操作防恶意提示词诱导远程 MCP 重点防“入侵”防未授权访问、防数据回传、防伪装服务端。两者的侧重点不一样检查清单自然也不一样。2. Secret 安全密钥最常出问题的地方Secret 虽然只是配置里的几个字段但我实际查下来90% 的 MCP 配置问题都出在这几个字段上。不是大家不想管好而是配置这东西太容易“先跑通再说”了先把 key 填进去后面再也不回头。2.1 环境变量优先配置文件其次MCP 的配置方式主流有两种一种是直接写在客户端的配置文件里比如 Claude Code 的.mcp.json、Cursor 的 MCP 配置面板另一种是通过启动命令里的环境变量传进去。这是我的第一条硬性建议凡是敏感凭证一律走环境变量不要硬编码到配置文件里。举一个最典型的例子我团队里有人把数据库连接串直接写进了 Cursor 的 MCP Server 配置里那串连接串带用户名带密码还贴在共享屏幕上。当时我看了眼那个配置文件直接让他换掉。环境变量可以放在.env文件里配置文件用${DB_PASSWORD}这类占位符引用或者在启动命令里用env参数注入这样即使配置文件被截图、被分享密码也不会漏出去。为什么强调这一点因为 MCP 配置文件经常被放进 dotfiles 仓库里做版本管理一旦硬编码了密钥git 历史里就会永久留一份。就算你后面删了重新提交历史记录里的密钥也等于已经公开了只能作废重换。这个损失比配置麻烦大太多。2.2 攻击面Secret file 如何变成泄露口热词里有个 “secret file”听起来像 CTF 题的描述但真实世界里的密钥泄露路径比 CTF 题还离谱我列几个真实见过的场景。第一种是日志输出。某些 MCP Server 在 debug 模式会把整个配置对象打出来包括密钥字段。我排查问题时就遇到过日志里明晃晃打印着apiKey: sk-xxxx。所以检查清单里要加上一条Server 的日志输出必须脱敏密钥字段要打***。第二种是错误响应回传。AI 调用工具出错时错误信息会被返回给客户端如果 Server 不做处理异常对象里的请求头、配置字段会原封不动出现在聊天窗口里。这等于 AI 亲手把密钥交到了对话里而对话记录又可能被同步到云端风险链就这么打通了。第三种是配置文件权限。很多人.mcp.json用的还是默认权限同机的其他用户、其他进程都能读。检查时顺手ls -l看一眼确保配置文件只有当前用户能读写这一步成本极低但真的没几个人做。注意任何关键时刻请记住一个判断标准——密钥一旦可能被除预期接收方以外的第三方看到就要立刻作废重换。不要抱着“应该没人看到吧”的侥幸。3. Shell 执行权限MCP 的“内鬼”重灾区如果说 Secret 是配置层面的坑那 Shell 权限就是运行时层面的雷。MCP Server 提供 shell 工具的本意是让 AI 能帮你操作本地环境比如跑构建、查进程、操作 git但如果这个工具没有边界AI 就能变成一台无人值守的终端。3.1 从白名单机制开始允许哪些命令安全检查的第一步不是考虑 AI 能干什么而是考虑 AI 不该干什么。我强烈建议 MCP Server 的 shell 工具做成命令白名单机制而不是黑名单。别迷信黑名单。你封了rm -rf /AI 可以用find / -type f -delete你封了curlAI 可以用python3 -c import urllib...。黑名单永远不可能覆盖所有绕过路径只有白名单能真正限制能力边界。白名单要怎么设计按需分类。比如本地开发类 MCP白名单可以覆盖git status、git diff、git log、npm run build、node --version、ps aux、df -h这类只读或半只读命令。凡是写操作类命令比如git push、rm、mv、sed -i需要单独设置一个“执行需确认”的开关由用户在客户端侧再确认一次。AI 调用时命令在白名单内直接放行不在白名单内直接拒绝并在响应里说明原因。3.2 参数过滤和防注入同样关键命令白名单只能挡住“命令级”的越权挡不住“参数级”的注入。我举个例子白名单里允许了git logAI 执行git log --format%x00...这类怪参数虽然大概率干不了坏事但像cat这种命令白名单开了之后AI 就能读任意文件所以参数过滤不能省。对于需要带路径或文件名的命令要做两级过滤。第一级是过滤特殊字符命令和参数里出现;、|、、$()、反引号直接拒绝——因为这是拼接式命令注入最典型的路子。第二级是校验路径合法性——解析参数里的路径去掉..和符号链接后确认它落在允许的目录前缀之下比如项目目录内。实操时我建议不要自己裸写 shell 拼接去执行而是用 Node.js 的execFile或者 Python 的subprocess.run(list_args)这种传参列表的方式从机制上避免走 shell 解释器。这样参数里就算有特殊字符它也只是“参数”不会被当成命令执行。有一次我测试时故意让 AI 执行cat ../../etc/passwd白名单居然放行了就是因为只检查了命令名没检查路径。后来加了路径解析校验这类越权立刻就堵上了。排查 MCP 相关 issue 时很多人吐槽“AI 能读我所有文件”多半就是栽在这个细节上。4. Remote MCP 的边界远程入口必须单独设防Remote MCP 最近越来越流行因为一个 MCP Server 部署在服务器上多个客户端能共享着用。但我可以很直白地说远程模式下的 MCP 配置问题是最多的。很多人把本地的配置搬到远程只改了个地址身份校验完全没跟上等于把家门的钥匙挂在了门口。4.1 鉴权第一关谁来访问你的 ServerRemote MCP 的基本传输是 SSEServer-Sent Events和 HTTP POST也就是说它本质是一个 Web 服务。是 Web 服务就要回答一个问题是否任何人都能调用实测下来很多 MCP Server 框架的默认配置是没有鉴权的。启动一个 SSE 端点谁拿到地址都能连连上之后工具随便调数据库随便读。我在测试环境搭了一个演示用的 Remote MCP从另一台机器上直接用 HTTP 请求就能拉取工具列表、执行工具调用整个过程没有任何身份校验。这就是把数据库的 3306 端口直接暴露公网却没有设密码。正确的做法是加一层 Bearer Token 验证。客户端配置里带上Authorization: Bearer token服务端在处理请求前先校验 token。而且 token 要能配置、能轮换、能撤销不能写死在代码里。若要上生产环境还应该用 HTTPS 而不是裸 HTTP否则 token 和数据都在明文传输谁在中间都能截走。4.2 传输安全不要开裸奔的 HTTP 端口关于传输这块我再说细一点。起步阶段可以用 HTTP 调试但对外服务时务必在网关层把 TLSHTTPS终结掉。你可以用 Nginx 做反向代理把 MCP Server 的端口藏在内网由 Nginx 对外提供 HTTPS同时在 Nginx 层再做一层 IP 白名单或 Basic Auth。我自己的习惯是Network 层、HTTP 层、应用层各设一道关。网络层上MCP 服务端口只对需要的客户端 IP 开放其他一律拒绝HTTP 层上token 校验做在网关或 Server 入口应用层上Server 内部还要维护一份它接受的来源列表防止 token 被复制走以后从任何 IP 都能调用。很多公网 MCP 服务出事就是这三层全裸。别嫌麻烦远程 MCP 的每一条边界都值得你多花 10 分钟去检查。4.3 和 Computer Use 的区别为什么单独说权限级别搜索热词里有个“computer use 和 MCP 的区别”这里顺带解释一下因为它涉及权限边界。MCP 的授权方式是工具调用——Server 暴露有限数量的工具AI 在已有工具集里选着用。Computer Use 不是它给 AI 的是屏幕截图和鼠标键盘操作能力AI 能自己点开任何窗口、键入任何内容能力泛化到整个操作系统。用权限视角看MCP 是“授予特定职能”Computer Use 是“授予全权委托”。所以 Remote MCP 出现时我们至少还能通过工具列表来收紧权限检查起来相对可控。但任何带 Computer Use 能力的配置安全等级直接拉满绝对不可远程开放也不建议在真实环境乱开。这点在安全检查报告里一定要单独标注。5. 权限边界实测用最小白名单跑一遍说完了风险模型和四个检查维度接下来是我最推荐的实操手段——把配置调到“最小可用”状态然后实测一遍。只有实际跑过测试你才知道白名单的洞补上没有、远程鉴权拦没拦住。5.1 文件系统边界AI 能碰到哪些目录先测文件访问范围。我给测试用的 MCP Server 配了文件操作工具初始配置是允许读写项目目录下的文件。测试时故意让它读几个不该读的地方家目录下的.ssh/id_rsa、/etc/passwd、/tmp下的临时敏感文件。实测结果记录如下测试目标初始配置结果收紧后结果读项目内文件成功成功读/etc/passwd被拒绝被拒绝读家目录.ssh/id_rsa成功漏洞被拒绝穿越目录../../成功漏洞被拒绝写项目外临时目录成功漏洞被拒绝这个表能直观看出问题很多 MCP Server 的文件工具默认允许访问当前用户的完整文件系统。这是因为它们在实现时用了path.resolve()就直接读文件了没有在入口处做根目录校验。收紧方案是增加一个虚拟根目录解析路径后强制要求路径前缀等于允许目录如果目标路径是符号链接还要解析出真实路径再校验否则符号链接能轻松绕过。5.2 网络边界MCP Server 能访问哪些外网地址文件系统测完后测网络。MCP Server 里如果带了 HTTP 请求类工具AI 就可以让 Server 去访问任意 URL。很多人会忽略这一点Server 运行在你自己电脑上它访问内网资源时和你本机访问内网资源没有区别这意味着 AI 可以借你的位置访问企业内部系统。我的测试方案是配一个内部监控面板地址和一个云元数据地址看 Server 是否能访问到。默认配置下HTTP 工具是可以直接访问内网地址的响应还会被 AI 分析后回复给你。这就是典型的 SSRF 风险——服务端请求伪造。收紧方案有两个方向。第一是目标域名白名单限制 HTTP 工具只能访问预配置的域名或者前缀比如允许api.github.com、api.openai.com其余一律拦截。第二是网络层隔离把 MCP Server 放进一个网络命名空间或者容器里让它只能出公网、不能进内网。两者结合最稳。5.3 进程执行权限白名单命令实际跑一遍最后测命令执行。我前面提过白名单机制这里给出一个实际执行的样例方便你理解检查时的判断逻辑。假设白名单里有node、npm、git、python3、ls、cat我测试时会让 AI 依次执行这些命令的“正常用法”和“越权用法”node --version正常放行node -e process.mainModule.require(child_process).execSync(id)这是越权用法初始配置可能放行python3 -c import os; os.system(whoami)越权用法初始配置可能放行git log --oneline -5正常放行cat ../.env越权用法看路径校验是否生效实测发现白名单只检查命令单词的配置对上述 2、3、5 三条都能放行。因为node本身是白名单命令参数里怎么写脚本完全没被检查。换句话说你开了node白名单AI 就拥有了任意代码执行能力和给你开个终端没什么区别。这也是为什么我在前面强调“参数过滤不能省”。进程执行类的白名单要更苛刻如果是脚本解释器要限制脚本文件的来源必须是项目目录内的文件且脚本文件本身要经过人工审查不能是 AI 现场生成的。说白了允许 AI 运行node build.js可以允许 AI 运行node -e 任意代码坚决不行。6. 常见问题与排查技巧实录安全检查做完了我把实际项目里经常碰到的问题整理成一份速查表遇到类似的可以直接照着排查。症状可能原因排查步骤解决方案AI 能读我所有本地文件文件工具没做根目录校验让 AI 读一个项目外的测试文件验证实现虚拟根目录 符号链接解析校验日志里打印出 API KeyServer 日志未脱敏检查 debug 模式日志输出日志过滤器统一遮罩敏感字段配置文件被分享后密钥泄露密钥硬编码在.mcp.jsongit 历史搜索sk-前缀改用环境变量注入轮换已泄露密钥远程 MCP 任何人都能调用没有做 token 验证未带 token 请求访问工具列表增加 Bearer Token 校验 HTTPS 网关AI 用node -e执行任意代码白名单只查命令名测试node -e 恶意代码限制脚本来源拒绝内联参数远程 Server 能访问内网系统HTTP 工具没做 SSRF 防护让 Server 请求内网地址验证目标域名白名单 网络层隔离修改配置后不生效MCP 配置被缓存查看客户端日志确认配置加载清理缓存目录重启客户端进程排查时有个小技巧所有 MCP 工具的调用记录尽量打开日志。很多框架默认只记调用成功与否不记参数。安全检查时看不到完整入参很多问题定位不到根因。把日志调成记录工具名和脱敏后的参数排查效率能翻一倍这一点非常建议从一开始就配上。另外多个 MCP Server 同时跑的时候注意确认工具名不要冲突。之前我见过一个环境里两个 Server 都定义了read_file客户端随机分发结果该读甲的文件读到了乙的目录里场面相当混乱。排查起来倒是简单但一开始配的时候就该把工具名域化。最后说一个实用性很强的习惯给每个 MCP 工具加一个description字段写清楚它能做什么、不能做什么、参数限制是什么。很多框架会把 description 直接塞给 AI 做工具选择参考。描述写得越清楚AI 越不容易误调用描述含糊AI 就会放飞想象力。这不是安全机制但在实战里能挡掉很多误触发的风险属于性价比极高的低成本手段。回到我自己的体会MCP 这东西的便利性太突出很容易让人忽略它背后的权限问题。但只要你按前面的思路做一轮检查把 Secret 收进环境变量、把 Shell 收进白名单、把远程 MCP 配上鉴权和加密、给文件系统和网络访问划出边界MCP 其实是很好用而且可控的。别被“AI 失控”的恐慌带着走真正的风险点并不神秘它藏在每一份配置里等着你去审一遍。
返回列表