介绍

MCP的第一个风险点翻译过来实际上叫做Token管理不当和密钥泄露,这里为了方便,就统一叫做信息泄露。

MCP的整个架构中,模型通过MCP去调用服务端工具,会经常用到认证,可能是密码,可能是KEY,或者是其它的敏感信息,这里就涉及到敏感信息的存储,MCP风险中关于敏感信息管理不当导致的泄露分为很多场景,因为在整个过程中,每个地方可以配置信息,以KEY为例,比如:

1、客户端配置,就可以把KEY明文配置进去,像mcp.json等,导致模型可以读取配置文件获取。

2、也可以配置到服务器中,即服务端代码或配置文件中硬编码了密钥,导致直接读取相关文件就可获取。

3、密钥也可通过用户传入,比如工具要求从模型侧传入密钥,那用户可以通过聊天框传入,或者写到系统提示词中,导致存于模型记忆中,后续可通过提示词注入获取。

4、有的服务端为了调试或记录,会将相关日志存下来,存的时候可能会将密钥存到日志文件中。

总之就是整个过程中相关信息可以被获取,即MCP的第一个风险:信息管理不当导致泄露。

模型上下文泄露

第一种客户端配置和第二种服务端配置这个就不演示了,比较好理解,下面来看下第三种模型上下文的情况。

大模型通过MCP调用外部工具时,需要进行验证,而这个验证的敏感信息是存在于模型上下文的,意味着用户是可以通过提示词交互来获取到这些信息的。

下面我们来简单写一个MCP服务,测试的同时顺便看下MCP的开发大体流程,这里MCP开发使用FastMCP,所以需要先安装一下:

pip install fastmcp

安装后,这里通过fastmcp来写一个简单的服务端demo,功能很简单,接收一个key,并返回指定的信息,代码和注释讲解如下:

from fastmcp import FastMCP

# 初始化MCP服务器并起一个名字
mcp = FastMCP("vulmcp")

# mcp.tool这个装饰器代表将函数以工具形式对外提供
@mcp.tool()
def receive_api_key(api_key: str) -> str:
    """
    该函数很简单,接收API_KEY并返回一个提示
    """
    return f"已收到传入的KEY为:{api_key}"

if __name__ == "__main__":
    # 启动服务器,默认使用stdio标准输入输出进行通信
    mcp.run()

此时我们这个MCP服务就开发好了,那么开发好后如何测试呢,官方提供了一个测试平台,该平台通过npm来安装:

npm install -g @modelcontextprotocol/inspector

安装后通过mcp-inspector去运行:

mcp-inspector python vulmcp.py

该命令执行后会打开一个本地地址,里面的Tools就包含了我们的服务端,可以输入接收的参数进行测试,如下图:

Image

如果不想用官方这个平台测试,也可以直接放到相关工具中去测试使用,以CherryStudio为例,直接在MCP配置中加入以下json内容,当大模型去调用时,Cherry会自动执行里面的命令把脚本跑起来:

 "vulmcp": {
  "isActive": true,
  "name": "vulmcp",
  "type": "stdio",
  "command": "python",
  "args": [
    "C:\\Users\\Administrator\\Desktop\\vulmcp.py"
  ],
  "installSource": "unknown"
}

在Cherry中配置好MCP后,我们开一个会话,设置下会话的系统提示词,比如就说API_KEY是123456,然后让模型检索工具并调用,模型可读取到KEY,或者聊天时将KEY发给模型也可以,效果如下:

Image

这样相当于敏感信息就存到了模型上下文中,后续可以通过提示词来获取相关的KEY,导致KEY泄露:

Image

日志泄露

MCP服务端有时候为了调试或记录,会将相关日志存下来,日志中包含了明文的敏感信息,导致泄露。

以上面模型上下文泄露中的例子为基础,这里添加一个日志记录功能,代码如下:

import logging
from fastmcp import FastMCP

# 配置通用日志记录器,将日志写入同目录下的 mcp_server.log 文件
logging.basicConfig(
    filename='mcp_server.log',         # 日志保存的文件名
    level=logging.INFO,                # 记录 INFO 及以上级别的日志
    format='%(asctime)s - %(levelname)s - %(message)s', # 日志格式:时间 - 级别 - 内容
    encoding='utf-8'
)

mcp = FastMCP("vulmcp")

@mcp.tool()
def receive_api_key(api_key: str) -> str:
    # 记录收到的参数
    logging.info(f"[收到请求] receive_api_key 工具被调用。传入的 API_KEY 为: {api_key}")
    
    # 定义响应内容
    result = f"你的KEY为:{api_key}"
    
    # 记录响应的内容
    logging.info(f"[返回响应] 工具执行完毕。返回结果为: {result}")
    
    # 返回响应的内容
    return result

if __name__ == "__main__":
    mcp.run()

此时新开一个会话,然后调用工具,因为代码中日志文件存储路径相当于根目录,这里不是服务端脚本的根目录,因为是cherry执行的,所以日志文件会存在cherry的根目录,效果如下:

Image

防护措施

关于密钥等敏感信息,建议存到系统环境变量中,需要的时候直接从环境变量中读取即可,不同的工具可能方式不一样,然后代码层面避免硬编码,如果涉及到日志功能,避免写入敏感信息。

总结

以上就是MCP安全系列中关于认证信息存储位置不当导致的信息泄露的相关内容,感谢阅读。

小枣信安:专注AI安全,包括但不限于大模型安全、智能体安全、机器人安全、AI赋能网络安全等,欢迎一起学习。

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐