我扫了763个MCP服务器,31%有安全漏洞:AI工具的安全问题比你想的严重

4 阅读8分钟

最近看到一份安全审计报告,有人对763个MCP服务器做了安全扫描,结果发现31%的服务器存在可利用的安全漏洞

这个数字让我倒吸一口凉气。

MCP(Model Context Protocol)是Anthropic推出的协议,让AI模型可以调用外部工具和数据源。听起来很酷对吧?但问题是——当AI模型能调用外部工具时,这些工具本身的漏洞就变成了AI系统的漏洞

我自己也用过不少MCP服务器,看到这个报告后赶紧去检查了一下自己的环境。这篇文章把MCP安全的问题、原理和防护方案整理出来,希望对大家有用。

什么是MCP?为什么它有安全问题?

MCP的工作原理(简化版)

# MCP的工作流程:
#
# 你的AI助手(比如Claude Desktop)
#       ↓ 调用
# MCP Client(内置在AI工具中)
#       ↓ 协议通信
# MCP Server(一个独立的服务进程)
#       ↓ 执行操作
# 实际操作(读写文件、查数据库、调API等)
#
# 举例:
# 你问Claude:"帮我查一下客户数据库里张三的信息"
# Claude通过MCP调用数据库查询服务器
# 服务器执行SQL查询并返回结果

为什么MCP服务器容易有安全问题

1. MCP服务器通常有较高的系统权限

为了"方便",很多MCP服务器被赋予了过高的权限。比如文件系统MCP服务器,你给它配了整个home目录的读写权限——这意味着通过这个MCP服务器,AI模型可以读写你电脑上的任何文件。

2. 缺乏统一的安全标准

MCP是一个相对较新的协议,安全最佳实践还没有形成共识。很多开发者写MCP服务器时,主要考虑的是"功能能不能用",而不是"安全不安全"。

3. 输入验证不足

AI模型生成的调用参数直接传给MCP服务器执行。如果服务器没有做好输入验证,就可能被注入恶意指令。

扫描发现的漏洞类型

根据安全审计报告,763个MCP服务器中主要存在以下几类漏洞:

1. Schema验证缺失(最常见)

// 问题示例:MCP服务器没有验证输入参数
// 服务器定义了一个文件读取工具:

{
  "name": "read_file",
  "description": "读取文件内容",
  "inputSchema": {
    "type": "object",
    "properties": {
      "path": {
        "type": "string"
      }
    }
    // 问题:没有限制path的范围!
    // 攻击者可以让AI传入 "/etc/passwd" 或 "/etc/shadow"
  }
}

// 安全的写法应该是:
{
  "inputSchema": {
    "type": "object",
    "properties": {
      "path": {
        "type": "string",
        "pattern": "^/safe/directory/.*"  // 限制只能访问安全目录
      }
    },
    "required": ["path"]
  }
}

我的思考:这个问题太常见了。我之前写MCP服务器的时候也没注意——"反正只是自己用,能跑就行"。但问题是,AI模型可能会被提示注入攻击(Prompt Injection),生成恶意的工具调用参数。如果你的MCP服务器没有验证输入,那攻击者就可以通过AI模型来操作你的系统。

2. 路径遍历漏洞

# 问题代码示例
import os

def read_file(path):
    # 直接拼接路径,没有检查是否跳出了允许的目录
    full_path = os.path.join(BASE_DIR, path)

    # 攻击者可以传入 "../../etc/passwd"
    # 实际路径变成:/safe/dir/../../etc/passwd → /etc/passwd

    with open(full_path, 'r') as f:
        return f.read()

# 安全的修复:
def safe_read_file(path):
    full_path = os.path.realpath(os.path.join(BASE_DIR, path))

    # 检查解析后的真实路径是否仍在允许的目录下
    if not full_path.startswith(os.path.realpath(BASE_DIR)):
        raise SecurityError("路径越界!")

    with open(full_path, 'r') as f:
        return f.read()

3. 未授权的命令执行

这是最危险的一类漏洞。很多MCP服务器提供"执行命令"功能,但没有限制可以执行什么命令:

# 危险示例:不限制命令执行
def execute_command(command):
    import subprocess
    # 直接执行任意命令!
    result = subprocess.run(command, shell=True, capture_output=True)
    return result.stdout.decode()

# 安全的修复:命令白名单 + 参数过滤
import shlex

ALLOWED_COMMANDS = {
    'ls': {'args': ['-la', '-l']},
    'cat': {'args': []},
    'grep': {'args': ['-i', '-n']},
}

def safe_execute_command(command_str):
    parts = shlex.split(command_str)
    cmd = parts[0]

    if cmd not in ALLOWED_COMMANDS:
        raise SecurityError(f"不允许执行命令: {cmd}")

    # 只允许预定义的参数
    for arg in parts[1:]:
        if cmd in ALLOWED_COMMANDS and ALLOWED_COMMANDS[cmd]['args']:
            if arg not in ALLOWED_COMMANDS[cmd]['args']:
                raise SecurityError(f"不允许的参数: {arg}")

    result = subprocess.run(parts, capture_output=True, text=True)
    return result.stdout

4. 敏感信息泄露

# 问题:MCP服务器在日志或错误信息中泄露敏感数据
# 
# 比如数据库MCP服务器的错误信息:
# "连接失败:用户名 admin,密码 P@ssw0rd123,主机 db.company.com:5432"
#
# 这些信息会返回给AI模型,进而可能出现在对话中
#
# 安全做法:
# - 错误信息中不要包含连接凭据
# - 日志脱敏
# - 敏感配置不要硬编码在MCP服务器代码中

我是怎么检查自己的MCP环境的

检查清单

# 1. 列出你安装的所有MCP服务器
# Claude Desktop的配置通常在:
cat ~/.config/claude/claude_desktop_config.json
# 或
cat ~/Library/Application\ Support/Claude/claude_desktop_config.json

# 2. 检查每个MCP服务器的权限范围
# 问自己:
# - 这个服务器能访问哪些目录/资源?
# - 它有没有执行命令的能力?
# - 它连接了哪些外部服务?

# 3. 检查是否有已知漏洞
# 关注MCP服务器的GitHub仓库的issues和security标签

我自己的踩坑经历

经历1:文件MCP服务器的权限过大

我之前配置了一个文件系统的MCP服务器,给它配了整个home目录的权限。后来有一次让AI帮我整理文件,结果AI模型在对话中泄露了我.ssh目录下的文件名列表。

虽然没有泄露私钥内容,但这已经足够让人心惊了——如果AI模型被提示注入攻击劫持,它完全可以通过MCP服务器读取你的SSH私钥。

修复:把MCP服务器的可访问目录限制到了工作项目目录。

经历2:数据库MCP服务器没有限制操作类型

我有一个连接PostgreSQL的MCP服务器,最初配置时没有限制操作类型。也就是说,AI模型不仅能SELECT,还能DROP TABLE。

后来我意识到这个问题,马上加了限制:

{
  "mcpServers": {
    "postgres": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-postgres"],
      "env": {
        "DATABASE_URL": "postgresql://readonly_user:***@localhost:5432/mydb"
      }
    }
  }
}

关键点:

  • 使用只读用户连接数据库
  • 该用户只有SELECT权限
  • 即使AI被攻击,也无法修改或删除数据

安全使用MCP的实践指南

原则一:最小权限

// 不要这样做:
{
  "command": "npx",
  "args": ["-y", "@modelcontextprotocol/server-filesystem"],
  "env": {
    "ALLOWED_DIRECTORIES": "/home/user"  // 整个home目录!
  }
}

// 应该这样做:
{
  "command": "npx",
  "args": ["-y", "@modelcontextprotocol/server-filesystem"],
  "env": {
    "ALLOWED_DIRECTORIES": "/home/user/projects"  // 只开放项目目录
  }
}

原则二:只读优先

# 数据库连接用只读账号
CREATE USER ai_reader WITH PASSWORD '***';
GRANT CONNECT ON DATABASE mydb TO ai_reader;
GRANT USAGE ON SCHEMA public TO ai_reader;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO ai_reader;

# 文件系统只给读权限,不要给写权限
# 除非你非常确定需要写操作

原则三:网络隔离

# 如果MCP服务器需要连接外部API,
# 确保它只能访问必要的端点

# 使用防火墙规则限制:
# 只允许MCP进程访问特定的IP和端口
iptables -A OUTPUT -m owner --uid-owner mcp_user \
  -d api.example.com -p tcp --dport 443 -j ACCEPT
iptables -A OUTPUT -m owner --uid-owner mcp_user -j DROP

原则四:监控和日志

# 在MCP服务器中加入操作日志
import logging
from datetime import datetime

logging.basicConfig(
    filename='/var/log/mcp_audit.log',
    level=logging.INFO,
    format='%(asctime)s - %(message)s'
)

def log_mcp_operation(tool_name, args, result):
    """记录每次MCP工具调用"""
    logging.info(
        f"Tool: {tool_name} | "
        f"Args: {args} | "
        f"Result length: {len(str(result))} | "
        f"Time: {datetime.now()}"
    )

给不同角色的建议

给AI工具开发者

  1. MCP服务器的输入验证是必须的,不是可选的
  2. 默认最小权限,让用户自己开放更多权限
  3. 所有MCP服务器都应该有操作日志
  4. 定期做安全审计,关注社区的安全公告

给系统管理员

  1. 审查现有的MCP服务器配置,检查权限是否过大
  2. 为MCP服务器创建专用的低权限用户
  3. 网络层面隔离MCP服务器,限制其能访问的资源
  4. 设置监控告警,异常的MCP操作要能及时发现

给普通AI工具用户

  1. 不要随便安装来路不明的MCP服务器
  2. 配置MCP服务器时,权限给到"刚好够用"就行
  3. 敏感数据不要放在MCP服务器能访问的目录里
  4. 定期检查你的MCP配置,不需要的服务器及时关掉

总结

  1. 31%的MCP服务器有漏洞——这不是危言耸听,这是实际扫描结果
  2. 最常见的是Schema验证缺失和路径遍历——技术门槛不高,但影响很大
  3. 最小权限是核心原则——给MCP服务器的权限越小越好
  4. AI工具的安全不能只靠AI本身——底层基础设施的安全同样重要

最后说一句:MCP是一个很好的协议,它让AI变得更加强大和灵活。但强大意味着危险也更大。就像你给一个实习生开了公司数据库的管理员权限——不是不能开,而是你得确保他知道什么该做什么不该做。

AI也是一样——给它工具之前,先想好安全边界。