最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
SafeDB MCP 如何通过策略层提供只读数据库访问?
时间:2026-09-13 11:48:01 编辑:袖梨 来源:一聚教程网
SafeDB MCP 是一个为 AI Agent 提供只读数据库访问的 MCP Server。它位于 Agent 与数据库之间,不把任意 SQL 原样交给数据库,而是先解析语句、识别实际访问的表和列,再应用 schema 与表级策略、行数限制、超时、字段脱敏和审计规则。项目支持 PostgreSQL、MySQL、MariaDB 与 SQLite,适合模式探索、数据问答和只读分析。
它解决的是纵深防御问题,而不是创造一种绝对安全的 SQL。项目文档明确把当前版本称为 MVP,倾向于宁可误拒绝,也不放行无法确认安全的查询,并且不声称能够形式化证明所有 SQL 都安全。生产部署仍然必须使用数据库原生的最小权限账户。
策略层解决什么问题
直接把数据库凭据交给 Agent,意味着一次错误提示、工具参数或生成语句就可能读取敏感数据、拖慢实例甚至修改数据。仅在系统提示中写“只执行 SELECT”属于行为约束,不是技术边界。
SafeDB MCP 把约束下沉到工具服务。Agent 只能看到服务暴露的工具,服务再依据配置决定哪些 schema、表和列可见。即使模型要求访问 secrets 表,策略层也应在执行前拒绝。
这层控制还能输出稳定的错误与审计记录,便于开发者区分语法错误、策略拒绝、资源超限和数据库故障。它无法保护绕过 MCP 的其他连接,所以真实凭据不应同时出现在 Agent 可读配置或上下文中。
六个 MCP 工具
项目暴露 list_schemas、list_tables、describe_table、run_readonly_query、explain_query 和 get_safedb_policy 六类工具。前三个帮助模型逐步理解结构,查询工具执行读取,解释工具查看计划,策略工具让客户端了解当前边界。
工具数量较少有助于降低模型选错能力的概率。结构探索与真实查询分离,也便于对不同动作设置审计和限额。
get_safedb_policy 返回的应是可公开策略摘要,而不是数据库密码、完整配置路径或秘密展开后的内容。上线时需要实际检查响应,确认环境变量值不会被工具回显。
AST 校验为何优于关键词扫描
SafeDB MCP 使用 AST 支持 SELECT、WITH 后接 SELECT、UNION 和 EXPLAIN SELECT。解析器会把文本转成结构树,再判断语句类型和引用对象。
简单规则常检查输入是否以 SELECT 开头,但它难以可靠处理注释、多语句、CTE、嵌套子查询和方言语法。关键词也可能出现在字符串或列名中,引发误拒绝。
AST 能识别顶层语句、子查询、别名和集合运算。项目还会阻止多语句输入,避免在合法查询后追加写入或 DDL。
解析器仍有方言边界。项目明确不以支持每一种合法的数据库专有只读语法为目标。无法解析的查询应被拒绝,而不是因为看起来像 SELECT 就放行。
如何发现真正访问的表
表策略不能只读取 FROM 后的第一个名字。真实 SQL 可能通过 JOIN、CTE、嵌套子查询、别名和 UNION 访问多个对象。
SafeDB MCP 会遍历结构,提取这些位置中的真实表,再将每个对象与 schema 策略对照。如果任何一个表被拒绝,整条查询都不应执行。
CTE 名称与物理表名必须区分。WITH recent AS (...) 后续 FROM recent 引用的是临时结果,而 CTE 内部可能读取受限表。只检查最终 FROM 会漏掉真正的数据源。
同样要防止未限定名称利用数据库搜索路径解析到意外 schema。生产配置应固定允许 schema,并让数据库账户的 search_path 或默认库符合预期。
允许列表与拒绝列表
配置可在每个 schema 下声明 allow_tables 和 deny_tables。允许列表适合默认拒绝模型:只有明确批准的业务表可见。拒绝列表适合从较大集合中排除少量敏感对象,但新建表可能自动暴露,风险更高。
两种规则同时存在时,需要确认冲突优先级。安全预期通常是拒绝优先,即使某表也在允许列表,deny 命中仍应拒绝。
推荐在生产使用小而明确的允许列表,把认证、密钥、支付、个人身份和内部审计表排除。模式变更时通过代码评审更新策略,不使用通配符自动纳入新表。
只读语法不等于只读结果
一条 SELECT 可能读取完整客户表、进行昂贵笛卡尔积,或调用带副作用的函数。语法类型只是第一道判断。
PostgreSQL 的函数可能以定义者权限运行,MySQL 函数与视图也可能扩大访问范围。数据库账户不应拥有执行任意过程、创建对象或加载扩展的权限。
SafeDB MCP 不支持写操作、迁移、存储过程执行或 COPY,这缩小了攻击面。部署者仍应检查数据库中的视图与函数,避免允许表间接暴露被禁止对象。
只读事务提供第二道约束
项目说明在驱动支持时,会把查询放进只读事务并设置本地语句超时。即使应用层漏判某种写语法,数据库事务仍有机会拒绝修改。
不同数据库对只读事务的语义并不完全一致。临时对象、序列、用户变量和某些管理语句可能有特殊行为。必须针对所用驱动和数据库版本运行集成测试。
最关键的防线仍是连接角色自身只读。只读事务是请求级约束,角色权限是数据库级约束,两者应同时存在。
外层 LIMIT 如何控制结果
配置包含 default_limit 与 max_limit。项目通过外层 LIMIT 限制返回行数,防止 Agent 一次把整张大表拉入模型上下文。
默认限制适用于没有明确限制的查询,最大限制约束客户端请求的上限。即使用户写了更大的 LIMIT,服务也应将结果压到配置值。
行数限制不能限制扫描成本。数据库可能在返回一百行前扫描、排序或聚合数百万行,因此还需要 statement_timeout_ms、索引和数据库资源治理。
外层包装也可能改变某些 EXPLAIN、锁定子句或方言结构的语法。升级时应覆盖每种数据库驱动的测试,不假设一套 SQL 改写在所有方言中相同。
语句超时的作用
示例配置把超时设为五秒。超时用于中止慢查询,降低错误 JOIN、全表扫描和复杂聚合占用连接的时间。
超时不是容量控制。许多短查询并发执行仍会压垮数据库,项目路线图中的每工具和每表速率限制尚未等同于当前能力。部署端需要连接池上限、并发限制和基础设施层限流。
查询超时后还要确认驱动真正取消了服务端语句,而不只是客户端停止等待。监控数据库活动会话,验证连接可回收且事务已结束。
字段脱敏的四种方式
SafeDB MCP 支持 redact、email、partial 和确定性 hash。redact 用固定占位隐藏全部值;email 保留有限结构;partial 展示一小部分字符;hash 把相同输入映射为稳定标识。
确定性哈希便于分组和关联同一主体,但容易遭受字典攻击。手机号、邮编和状态码等低熵字段即使哈希也可能被枚举。生产环境应加入受保护的密钥或直接阻止读取。
partial 与 email 掩码仍会泄露长度、域名或首尾字符。选择方式要依据数据分类,而不是为了让结果看起来友好。
投影检查防止别名绕过
仅在结果列名等于 users.email 时脱敏并不可靠。查询可以给字段设置别名,放入表达式,或与其他文本拼接。
项目说明会检查列投影,阻止通过别名或表达式直接选择被掩码字段。这意味着守卫需要追踪表达式来源,而不仅看最终响应键名。
测试应覆盖 SELECT email AS note、字符串拼接、大小写转换、子查询转发、CTE 重命名和 SELECT *。任何无法可靠追踪来源的投影应拒绝。
脱敏仍可能被聚合推断
原帖讨论中,作者明确承认当前策略主要是结构与策略驱动,不理解用户意图。即使禁止直接返回敏感字段,攻击者仍可能把敏感列用于 WHERE、GROUP BY、ORDER BY 或 JOIN 条件,通过计数和重复查询逐步推断值。
例如,对邮箱前缀逐字符设置条件并观察计数变化,可以构造推断通道。行数限制不会阻止这种小结果、多请求的提取。
高敏感字段更稳妥的策略是禁止它们出现在投影和谓词的任何位置,或只暴露预先设计的聚合视图。项目作者也把谓词级限制视为值得补充的方向。
结构安全不等于意图合理
当用户只问活跃用户数量时,SELECT * 加多个 JOIN 可能在语法上完全只读,也只访问允许表,却明显超出任务需要。
MCP Server 通常只看到工具调用,缺少完整任务上下文,因此很难证明查询意图。SafeDB MCP 不声称完成这种意图判定。
宿主如果要增加这一层,可以在调用时附带受信任的任务声明,把允许指标、维度和时间范围与 SQL 对照。但声明必须来自宿主,不应由模型自己填写后自己审批。
JSONL 审计日志
项目将查询尝试、决策、检测到的表、返回行数和耗时写入 JSONL,不记录原始结果行,也不刻意记录密码和秘密。
不保存结果降低了审计系统再次泄露业务数据的风险。日志仍可能包含 SQL 文本,而 SQL 常带字面参数,因此需要确认实现是否脱敏并限制日志权限。
JSONL 便于追加、采集和导入日志平台,但本地文件可以被同一主机进程修改。高保证环境应远程发送并使用不可变存储。签名审计日志出现在项目路线图中,不能当成当前已有能力。
PostgreSQL 快速配置
项目提供 init、validate-config、test-connection 和启动命令。推荐先生成配置模板,使用环境变量注入连接地址,校验配置后再测试连接。
npx @safedb/safedb-mcp init --output safedb.yaml
DATABASE_URL='postgres://readonly:secret@localhost:5432/app'
npx @safedb/safedb-mcp validate-config --config safedb.yaml
不要把示例密码提交到仓库。固定 npm 包版本,核验包发布者与锁文件,并让运行用户只能读取所需配置。
数据库角色只授予 CONNECT、目标 schema 的 USAGE 和批准对象的 SELECT。不要授予超级用户、建库、建角色、CREATE 或默认所有表权限。
MySQL 与 MariaDB 注意点
在 MySQL 和 MariaDB 配置中,数据库名作为访问 schema。连接用户只对批准表拥有 SELECT,避免 PROCESS、FILE、SUPER 和管理类权限。
information_schema 可能暴露实例结构,是否允许列表工具看到它要单独验证。视图的 SQL SECURITY 定义也会影响最终权限。
两种产品及不同版本的语法存在差异。CTE、EXPLAIN 和函数语法的解析结果需要分别测试,不能因为共同使用 mysql2 驱动就假设完全一致。
SQLite 注意点
SQLite 配置使用数据库文件路径,并以 main 作为 schema。它没有服务器角色体系,真正的权限来自文件系统。
只读服务应以只读方式挂载数据库文件和目录,最好查询快照副本。关闭扩展加载,限制进程能读取的其他文件,防止附加数据库或扩展能力扩大边界。
sql.js 的运行方式与原生 SQLite 驱动不同,文件加载、内存占用和持久化行为都应在数据规模接近生产时验证。
EXPLAIN 也需要限制
配置可以选择是否允许 EXPLAIN。只读查询计划有助于理解索引和成本,但某些数据库的分析模式可能真正执行查询。
工具只声明支持 EXPLAIN SELECT,并不意味着任何带 ANALYZE 的变体都应放行。测试必须确认危险选项被拒绝,且计划输出不会暴露未授权对象或参数。
计划文本也可能很大,应受响应大小和超时限制。普通业务问答不需要时,可关闭 allow_explain。
配置文件的安全边界
SafeDB MCP 接受 YAML 或 JSON,并支持环境变量展开。配置决定允许对象、脱敏规则、上限与日志位置,本身属于安全策略。
运行进程不应允许 Agent 修改配置。配置文件设为只读,目录不可写,变更进入版本审查。环境变量缺失时要让校验失败,不能用不安全默认值继续启动。
启动前运行 validate-config,只证明结构合法,不证明权限正确。随后使用 test-connection,再通过真实工具调用检查可见表与拒绝行为。
容器部署检查
项目提供 Dockerfile,并建议只读挂载配置。构建时固定基础镜像和依赖锁文件,扫描镜像,不直接依赖浮动标签。
容器使用非 root 用户、只读根文件系统和最小网络出口。审计目录需要单独可写卷,但不能让 Agent 通过 SQLite 或其他路径读取日志。
项目路线图提到发布镜像与 Helm chart,说明当前仓库文档中的本地构建不等于已有受维护的官方生产镜像。
必须执行的攻击测试
准备包含 SELECT、CTE、UNION、JOIN、嵌套子查询、别名和 EXPLAIN 的合法样例,确认策略不会错误识别 CTE 名为真实表。
再测试 INSERT、UPDATE、DELETE、DDL、多语句、注释变形、存储过程、COPY、动态执行和方言特有结构,全部应在到达数据库前被拒绝。
针对脱敏列测试别名、表达式、星号、子查询、连接、排序、分组和条件推断。检查审计日志不包含原始结果、连接密码和敏感参数。
最后制造超时、数据库断连、无效配置和日志写入失败。安全组件遇到内部错误时应失败关闭,不应跳过策略直接执行。
上线前检查清单
确认只开放批准 schema 与表,拒绝规则优先;数据库账户原生只读,不拥有过程执行、扩展加载或管理权限。
确认默认与最大行数、语句超时、连接池和并发限制符合数据库容量;EXPLAIN 仅在需要时开放。
确认所有敏感字段的投影与表达式都受控,并评估 WHERE、GROUP BY、ORDER BY 与 JOIN 带来的推断风险。极敏感数据使用专用视图或完全排除。
确认配置不可被 Agent 修改,秘密不进入代码和日志,审计文件被采集到受保护存储。升级解析器或数据库版本后复跑完整语法回归。
SafeDB MCP 的价值在于把只读访问拆成多层可检查控制:AST 决定语句结构,表策略限定数据范围,投影检查和脱敏减少直接泄露,行数与超时控制资源,审计记录每次决策。它适合用作数据库最小权限之上的防御层,但不能理解完整用户意图,也不能彻底阻止聚合推断。把这些能力和边界同时纳入设计,才能让 AI 数据问答既可用又可治理。