Skip to content

出口脱敏与敏感库

8 个 MCP 工具的出口在返回给 AI 之前实时跑脱敏规则;命中即替换为 [REDACTED:xxx] 给 AI,明文 AES-GCM 加密入「敏感库」。

本章讲安全模型视角,UI 操作详见 敏感库 (功能页)

为什么需要出口脱敏

即使你给 AI 配了「凭据永远不暴露」「策略只读」,AI 还能这么做:

AI 调 sftp_read("/etc/mysql/my.cnf")
→ 拿到文件内容(含 root password=...)
→ 把内容写进它的对话上下文
→ 用户看不到,但 LLM 提供商的日志看到了

这种「凭据从合法输出里被复述出去」的攻击面,没有出口脱敏就堵不住

触发点:8 个 MCP 工具

工具输出经过脱敏?
ssh_exec
ssh_exec_script
ssh_exec_multi✅(每台都过)
sftp_read
db_query✅(结果集每行)
tail_log
redis_get
redis_scan✅(值部分)
sftp_list❌ 目录列表无明显敏感性
system_info / disk_usage❌ 内容结构化无凭据

人用通道(终端 / SFTP UI / SQL 工作台)不脱敏——给你自己看的。

处理流程

原始输出(含 "mysql_root_password=Sup3rS3cr3t!")

对每行扫描所有启用的规则
     ↓ 命中 mysql_root_password 规则
找出匹配的子串("Sup3rS3cr3t!")

明文 → AES-256-GCM 加密 → vault.value_enc

入库 sensitive_vault 表,得 vault_id

原文该子串替换为 "[REDACTED:mysql_root_password]"

返回脱敏后的输出给 AI

审计记录 vault_id 指针

规则引擎

每条规则 = (name, pattern, kind, enabled)

yaml
- name: mysql_root_password
  pattern: '(?i)password\s*[=:]\s*(?P<secret>\S+)'
  kind: credential
  enabled: true

(?P<secret>...) 捕获组指明要替换的部分(其他部分保留)。

kind 分类

kind用途
credential密码 / passphrase
tokenAPI Key / Bearer Token
private_keyPEM / OpenSSH 私钥
url_with_authhttps://user:pass@host
generic其它疑似敏感

内置规则(约 20+ 条)

规则命中
generic_password_linepassword\s*[=:]\s*\S+
mysql_root_passwordmysql.*password 上下文
aws_access_keyAKIA[0-9A-Z]{16}
aws_secret_key40+ 长 base64 + 上下文
private_key_pem-----BEGIN .* PRIVATE KEY----- 整块
ssh_authorized_keysssh-rsa AAAA…
bearer_tokenBearer\s+[A-Za-z0-9._-]+
api_key_assignapi[_-]?key\s*[=:]\s*\S+
url_with_authhttps?://\S+:\S+@\S+
...

完整清单见仓库 src-tauri/ssh-core/src/redaction/builtin_rules.yaml

用户级 YAML 扩展

<app data>/redaction.yaml

yaml
rules:
  - name: company_internal_token
    pattern: 'CMP-[A-Z0-9]{32}'
    kind: token
    enabled: true

  - name: prod_db_string
    pattern: 'mysql://prod_admin:(?P<secret>\S+)@'
    kind: credential
    enabled: true

修改后下次加载生效(应用启动 / 敏感库 → 重载规则)。

规则测试器

敏感库 页 → 工具栏 测试规则 按钮:

  1. 粘贴一段测试文本
  2. 选规则集
  3. 实时高亮命中位置 + 命中的规则名
  4. 调试新规则前必跑

自定义规则的安全建议

写新规则时:

建议原因
(?P<secret>...) 命名捕获仅替换敏感子串,保留上下文
加边界(\b、行首 ^防止把 "passwordless" 也命中
(?i) 大小写不敏感实际日志大小写混杂
加 unit test(用规则测试器)防止下次升级失效

误报处理

规则误命中时(例如把无关字符串识别成密码):

  • 敏感库行 → 标假阳性 → 状态 已丢弃 + 加入误报样本
  • 后续规则优化时可参考误报样本

漏报处理

规则漏掉了真的敏感数据:

  • 审计行能看到原始输出(如果未命中规则,明文没入库)
  • 不可恢复的损失(理论上 AI 已经看到了)
  • 唯一对策:补规则

现实

出口脱敏是纵深防御的最后一层,不能替代「AI 不该看的就别给它看」。

  • 该用 Readonly 档位的别用 Trusted
  • 敏感配置文件别让 AI sftp_read
  • 关键库别让 AI db_query

与凭据库的区别

维度servers / installed_servicessensitive_vault
来源用户主动添加 / 一键装服务AI 工具输出被动捕获
用途SSH / DB 登录使用后续 Reveal / 转凭据 / 审计
删除策略软删保留审计期TTL 过期自动清 value_enc
加密AES-256-GCMAES-256-GCM(同 DEK)

与审计的联动

每条敏感库条目:

  • 关联审计行 ID(哪次 AI 调用产生的)
  • 关联触发的规则名
  • 关联服务器

审计页有「跳转敏感库」按钮看完整上下文。

一键转凭据

敏感库 → 行 转凭据 按钮:

  • 把敏感库条目转成正式 installed_services 凭据
  • 适合场景:"AI 帮我装了一个 MySQL,输出里的密码我现在确认要保留"

过期清理

每条 vault 记录有 TTL:

  • 默认 30 天
  • Sweeper 每小时检查 expires_at
  • 到期 → value_enc 清空,状态 已过期,hash 留审计

设置 可改全局默认 TTL。

与凭据加密共用 DEK

sensitive_vault.value_enc 用的是同一组 DEK(凭据加密):

  • 锁定时无法 Reveal
  • 重置凭据库时 vault.value_enc 一起清

下一步

受控的远程运维助手 — 让 AI 安全地帮你管服务器