MCP 的安全与权限边界
MCP 把本地文件、内网数据库、浏览器会话交给了模型驱动的程序。出问题通常不是被攻破,而是一次看似正常的调用改错了东西:覆盖配置、删掉目录、把生产数据写进聊天记录。本章给一套可落地的边界:最小权限、只读优先、敏感目录排除、密钥进环境变量、审计留痕、环境隔离、工具白名单。
先定权限模型:四要素
每个 MCP 服务端上线前都要答全这四个问题,答不全就先别开。
| 要素 | 要回答的问题 | 具体做法 |
|---|---|---|
| 身份 | 以谁的权限运行 | 专用低权限账号与专用目录,不用管理员账号 |
| 范围 | 能碰到哪些资源 | 根目录白名单、库表白名单、域名白名单 |
| 动作 | 允许做哪些操作 | 读优先;写、删、执行命令单独授权 |
| 时限 | 什么时候有效 | 任务级开关,用完即关,能设超时就别常驻 |
只读优先:从最小能力开始
默认全关,按任务逐个打开,是唯一可维护的做法。
| 阶段 | 文件 | 数据库 | 浏览器 | 用途 |
|---|---|---|---|---|
| 第一周 | 只读指定目录 | 只读账号 + LIMIT | 只抓取不点击 | 观察它到底会做什么 |
| 稳定后 | 允许新建文件 | 仍只读 | 测试站点可点击 | 日常草稿与调研 |
| 必要才开 | 允许改名移动 | 走单独工单写库 | 生产站点只读截图 | 高风险动作,人工在场 |
{
"mcpServers": {
"files": {
"command": "<你的文件 MCP 服务端启动命令>",
"args": ["--root", "D:/ai-workspace", "--read-only"],
"env": {
"ALLOW_DELETE": "false",
"FOLLOW_SYMLINKS": "false",
"MAX_FILE_MB": "5"
}
}
}
}
三个开关最值得关注:--read-only 决定能不能写,FOLLOW_SYMLINKS=false 防止从软链接跳出白名单,MAX_FILE_MB 防止一次读进超大文件把上下文塞满。
敏感目录与文件排除
「绝对不许碰」的清单要写死在服务端配置里,而不是靠提示词提醒。
| 类别 | 例子 | 处理方式 |
|---|---|---|
| 密钥与凭据 | .env、私钥文件、云凭据目录 | 不挂载,或列入拒绝清单 |
| 版本库内部 | .git 目录 | 拒绝读取,避免泄露历史与远端地址 |
| 系统目录 | 系统盘、程序安装目录、用户配置目录 | 不加入白名单根目录 |
| 生产数据 | 导出文件、备份文件、客户资料 | 只在隔离目录放脱敏样本 |
| 浏览器数据 | 浏览器用户数据目录 | 不挂载,用独立配置隔离会话 |
deny_paths:
- "**/.env"
- "**/*.pem"
- "**/*.key"
- "**/.git/**"
- "**/secrets/**"
- "**/backup/**"
密钥只放环境变量
配置文件会被复制、被提交、被转发到群里;环境变量至少不会跟着文件走。
| 做法 | 反例 | 正例 |
|---|---|---|
| 存放位置 | 配置里写明文口令 | 系统环境变量或本地密钥管理工具 |
| 引用方式 | 把口令粘进提示词 | 配置里只引用环境变量名 |
| 轮换 | 人人共用的长期口令 | 每环境独立口令,定期轮换 |
| 注入范围 | 让模型进程读到全部环境变量 | 只注入它需要的那几个变量 |
export AI_DB_PASSWORD='<你自己的口令>' # 只在当前会话生效,不写进配置文件
git check-ignore -v .env || echo '警告:.env 没有被忽略'
工具白名单:只暴露需要的那几个
一个服务端往往暴露十几个工具,全开等于把「删除」和「执行任意命令」也交了出去。
| 工具类型 | 是否默认开 | 说明 |
|---|---|---|
| 读取与查询 | 是 | 只读、可回滚、影响面小 |
| 新建文件 | 视情况 | 限制在隔离工作目录内 |
| 改名与移动 | 否 | 先干跑出清单,人工确认 |
| 删除 | 否 | 基本不需要给模型 |
| 执行任意命令 | 否 | 改用固定脚本,把命令写死在脚本里 |
| 提交与推送 | 否 | 提交信息由你确认后再执行 |
{
"tools": {
"allow": ["read_file", "list_dir", "write_file", "search_content"],
"deny": ["delete_path", "move_path", "run_shell"]
}
}
审计与日志
没有日志,出事只能靠猜。至少要能回答:哪个会话、什么时候、调了哪个工具、参数是什么、结果如何。
| 记录项 | 为什么需要 |
|---|---|
| 时间与调用方 | 定位是哪次任务触发的 |
| 工具名与参数摘要 | 参数里的路径尤其要留 |
| 目标资源 | 文件路径、库表名、URL 域名 |
| 结果状态 | 成功、失败、被拒绝 |
| 审批痕迹 | 哪一步是人工确认后放行的 |
grep -Ei 'write_file|move_path|delete_path' mcp-audit.log # 所有写操作
grep -E '"(status|result)":\s*"(error|denied)"' mcp-audit.log # 失败与被拒绝
日志本身也是敏感数据:参数里可能带路径、表名甚至数据片段,别把它同步到公开位置。
生产与个人环境隔离
| 维度 | 个人/试验环境 | 生产环境 |
|---|---|---|
| 数据 | 脱敏样本、假数据 | 真实数据,默认不接入 |
| 账号 | 个人账号 | 专用只读账号,最小权限 |
| 网络 | 可直连互联网 | 走审计网关,域名白名单 |
| 写入 | 允许写工作目录 | 禁止模型直接写入 |
| 审批 | 事后看日志 | 关键动作事前确认 |
| 回滚 | 删掉工作目录即可 | 必须有经过验证的回滚方案 |
| 常见坑 | 后果 | 规避 |
|---|---|---|
| 用管理员账号跑 MCP 服务端 | 一次误调用伤到系统 | 专用低权限账号 |
| 把「请注意安全」写进提示词当防线 | 约束不可靠 | 权限写在服务端配置里 |
| 白名单设成整个用户目录 | 等于全盘开放 | 只挂一个隔离工作目录 |
| 软链接指向白名单外 | 绕过目录限制 | 关闭跟随软链接 |
| 日志只记「调用成功」 | 出事无法复盘 | 记录参数摘要与目标资源 |
小结:MCP 的安全不靠提示词而靠配置——权限模型定身份与范围,只读优先定能力上限,敏感目录与密钥管理挡住最贵的损失,白名单与日志让每次调用可追溯,生产与个人环境彻底隔离;上线前逐条打钩,再谈自动化。