优化、测试与安全

提示词中的个人信息与密钥检测

API 密钥、密码和个人数据如何进入 LLM 提示词,敏感信息检测如何工作,以及如何在发送任何内容之前进行脱敏。

译自英文原文。代码、提示词和模型输出保留英文。

发送给托管模型的每一个提示词都会离开你的环境。如果其中包含 API 密钥、密码或客户的个人数据,这些信息就已经在别人的系统里,还可能出现在双方的日志中。敏感信息检测,就是在提示词发送之前发现这类内容的做法。

敏感数据如何进入提示词

很少是故意的。常见途径:

  • 粘贴的日志和堆栈跟踪,其中包含 token、连接字符串或会话 Cookie。
  • 为调试而共享的配置文件:.env、YAML、Terraform。
  • 硬编码了凭据的代码。
  • 工单、邮件和聊天记录中的客户记录。
  • 检索到的文档,包含的内容超出了问题所需。
  • 仓库中的提示词文件,有人曾用真实密钥做过测试。
  • 智能体循环中的工具结果,未经过滤就被转发给模型。

两类数据,两种风险

密钥授予访问权限:API 密钥、token、密码、私钥、连接字符串。泄露的密钥可以被立即利用。应对办法是吊销并轮换。

**个人数据(PII)**可识别个人:姓名、电子邮件地址、电话号码、邮寄地址、支付卡号、国民身份证号。发送这些数据可能违反你的隐私承诺或法律,而且它们无法轮换。

检测如何工作

检测器会组合多种方法,因为每种方法都有盲区。

已知格式。 许多提供商签发的密钥带有可识别的前缀和长度。可以高置信度地匹配这些密钥。

上下文模式。 像 password = "..." 或 api_key: ... 这样的赋值,会把该值标记为凭据,无论它是什么格式。

熵。 随机字符串的香农熵很高。紧挨着“token”或“secret”这类词的、较长且熵很高的值,很可能是凭据,即便格式未知。

结构化标识符。 电子邮件地址、电话号码和卡号都遵循一定模式。卡号还可以通过校验和确认。

命名实体识别。 统计模型可以找出没有固定模式的姓名、组织和地点。覆盖面更广,但误报更多,并且需要一个模型。

PromptFlowEngine 提示词安全扫描器使用前四种。它是确定性的,并在本地运行,所以被检查是否含有密钥的文本,不会为了检查而被发送到任何地方。

报告位置,而不是值

打印出所发现密钥的检测器,会在日志或终端里制造出该密钥的第二份副本。行为良好的扫描器只返回类别和位置:

{
  "hasSensitiveData": true,
  "countsByCategory": { "api_key": 1, "email": 1 },
  "matches": [
    { "category": "api_key", "start": 118, "end": 164 },
    { "category": "email", "start": 176, "end": 196 }
  ]
}

这就是 PromptFlowEngine 在所有界面中返回的结构。完整示例见敏感数据规则。

脱敏

脱敏用占位符替换每个检测到的值,同时保留周围文本的含义。

Before: Connect with postgres://admin:hunter2@db.internal:5432/app
After:  Connect with [REDACTED_CONNECTION_STRING]

像 [REDACTED_API_KEY] 这样带类型的占位符,比一排星号更好,因为模型仍然知道那里原本是什么类型的东西,可以在看不到它的情况下对其推理(“这个连接字符串看起来格式有误”)。

对于任务需要引用的个人数据,在同一次请求内使用一致的化名:同一个电子邮件的每次出现都变成 [EMAIL_1],下一个地址是 [EMAIL_2]。这样模型可以区分不同的人,而你的应用也可以在响应之后把占位符映射回去。

检查应放在哪里

尽早检测,并且在不止一个地方检测。

位置 能拦截什么
编辑器或聊天框中 一次粘贴,在发送之前
应用代码中,API 调用之前 来自用户、记录和检索的数据
智能体各步骤之间 即将进入上下文的工具结果
CI 中,针对提示词文件 提交到仓库的凭据
记录日志之前 即将被存储的内容

Chrome 扩展会在 ChatGPT、Claude 或 Gemini 中的草稿含有密钥时发出警告,并可以在你的设备上对其脱敏。VS Code 扩展会在提示词发送到聊天之前运行隐私防护,提供严格、脱敏和警告三种模式。在 CI 中,检查门禁默认在出现任何严重级别的发现时失败,所以已提交的密钥会让构建停止。

策略选择:拦截、脱敏还是警告

  • 拦截:密钥绝不应被发送时。最安全,也最具干扰性。
  • 脱敏:作为默认选项。提示词在去掉敏感值之后通过。
  • 警告:需要由人来决定时,例如代码中可能的误报。

无论你选哪一种,都请在本地执行密钥检测。为了弄清文本发送是否安全,却把文本发送到远程服务的检查,违背了初衷。

你应当了解的局限

  • 漏报。 格式不寻常的密钥,或者像对某人的描述这样没有固定模式的个人数据,可能会漏过。检测可以降低风险,却不能证明提示词是干净的。
  • 误报。 哈希、UUID 和测试固件可能看起来像密钥。请把已知安全的值加入允许名单,而不是禁用检查。
  • 图片与文件。 文本扫描器不会读取截图或 PDF,除非先进行转换。
  • 上下文。 一个名字在某种场合是公开的,在另一种场合却是机密。只有你的策略才能做出判断。

超越检测:少发送

最可靠的控制是根本不包含这些数据。

  • 传递一个 ID,让工具去查找该记录,这样模型永远看不到它不需要的字段。
  • 在构建提示词之前去掉相关字段。
  • 把凭据保留在你的应用中,直接交给工具。模型永远不需要你的 API 密钥来请求某个工具调用 API。
  • 在示例和提示词文件中使用测试数据。

如果密钥已经被发送

  1. 立即吊销并轮换。把它视为已被泄露。
  2. 检查访问日志,看是否被使用过。
  3. 从仓库历史和提示词文件中删除它。
  4. 添加一项检查,让下次能拦截同样的途径。

关于相关的威胁模型,参阅提示词安全。关于数据进入上下文之后试图将其提取出来的攻击,参阅提示词注入。