三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

系统提示词为什么会被提取,以及分层防护如何落地

系统提示词为什么会被提取,以及分层防护如何落地

系统提示词被提取,通常不是因为模型“记住了密码”,而是因为应用把不该当作秘密的指令,放进了一个会和用户输入、检索内容、工具返回共同参与推理的上下文里。

只要攻击者能反复试探输出差异,就可能逐步恢复提示词的意图、边界,甚至原文片段。OWASP 在 LLM07:2025 中把这类风险单列为 System Prompt Leakage,并明确提醒:系统提示词不应承载密钥、授权逻辑或核心安全控制。

因此,正确的问题不是“怎样写一段完全不会泄漏的提示词”,而是“提示词泄漏后,系统还能不能守住数据和动作边界”。

先分清要保护的四类东西

系统提示词、业务规则、身份凭据和工具权限经常被混在一起,但它们的安全属性完全不同。

  • 系统提示词:用于约束模型行为,可以降低误用概率,但不能视为秘密。
  • 业务规则:应由确定性的服务端代码执行,不能只靠模型记住。
  • 身份凭据:密钥、连接串、内部令牌不能进入提示词或模型上下文。
  • 工具权限:应按用户身份、数据范围和动作风险在调用时重新判断。

一个常见错误,是把“只能查询当前客户数据”写进系统提示词,却让模型持有一个可以查询全部客户的数据库工具。提示词一旦被绕过,真正的权限边界也就消失了。

把授权移到模型之外

模型可以建议动作,但最终是否允许执行,应该由独立的策略层判断。下面是一个最小化的工具调用入口:

typeToolRequest={userId:stringtenantId:stringtool:"ticket.read"|"ticket.update"resourceId:stringargs:Record<string,unknown>}asyncfunctionexecuteTool(req:ToolRequest){constsubject=awaitloadIdentity(req.userId)awaitpolicy.enforce({subject,tenantId:req.tenantId,action:req.tool,resourceId:req.resourceId,})returntoolRegistry.run(req.tool,req.args)}

这里有三个关键点:

  1. 租户和用户身份来自受信任会话,不从模型生成内容中读取。
  2. 每次工具调用都重新鉴权,不能因为上一步通过就默认后续都通过。
  3. 高风险写操作还要检查业务状态,例如工单是否仍可修改、订单是否已经结算。

即使系统提示词被完整看到,攻击者仍拿不到额外数据,也不能越权执行动作,这才是可验证的安全边界。

用分层控制缩小泄漏影响

可以把防护拆成五层:

用户输入与外部内容

输入标记与风险识别

模型推理

结构化输出校验

策略鉴权与人工审批

工具执行

结果确认与审计

输入来源层给用户输入、检索文档和工具返回值标记来源,避免把外部内容误当成系统指令。

风险识别层对明显的提示词提取、角色覆盖和编码绕过请求进行识别。它适合降低噪声,不适合承担最终安全责任。

输出约束层要求模型只输出结构化意图,例如工具名、资源 ID 和参数,不让自然语言直接变成可执行指令。

权限控制层由策略引擎完成权限检查,对删除、付款、发布、设备控制等动作增加人工确认。

审计层记录请求、策略版本、工具参数、执行结果和最终业务状态,支持复盘与对账。

做这层检查时,团队可以先用覆盖注入与泄漏面的 trace 审计清单核对输入来源、权限决策和执行结果,再把缺失字段补进实际链路。

在实际实现中,每条 trace 至少要能关联会话、用户、租户、输入来源、模型版本、策略版本、工具名、参数摘要、审批人、执行结果和最终业务状态。参数摘要应脱敏,原始凭据不落日志;审计写入失败时,高风险动作应停止而不是静默继续。这样出现问题后,团队才能区分是提示词被套取、策略判断错误、工具越权,还是下游状态没有确认。还要给同一会话保留连续事件视图,避免把多轮试探误判成互不相关的普通请求。

输出过滤不能只查关键词

简单屏蔽“system prompt”“忽略之前指令”等词,容易误伤正常问题,也挡不住分段提取、翻译、编码或侧信道试探。

更实用的做法是组合判断:

  • 检查输出是否包含凭据格式、内部标识和大段固定指令片段。
  • 对高相似度内容做阻断或脱敏,但保留人工复核入口。
  • 给异常会话设置速率限制,避免无限次试探。
  • 让安全响应只说明“无法提供内部指令”,不要复述被命中的规则。
  • 将命中记录关联到同一会话和用户,观察连续试探路径。

真正要关注的不是某一次回复看起来是否安全,而是多轮交互能否拼出不该暴露的信息。

上线前怎样验证

测试时不要只写几个“忽略之前指令”的样例。至少覆盖这些路径:

  1. 直接索要系统提示词、工具定义和内部规则。
  2. 要求翻译、总结、补全或逐字输出已有指令。
  3. 在检索文档、网页内容和工具返回中夹带指令。
  4. 用分段提问、多语言、编码和角色扮演逐步提取。
  5. 在提示词疑似泄漏后,继续尝试越权读取或执行写操作。
  6. 模拟策略服务超时,确认系统默认拒绝而不是放行。
  7. 检查审计记录能否还原输入来源、策略判断和最终动作。

最后看一个判断标准

系统提示词泄漏本身应被监控和修复,但它不应该直接导致数据泄漏或越权操作。

上线评审时可以反问一句:假设攻击者已经看到了完整提示词,他还能多读一条不属于自己的数据吗?还能跳过审批执行一次高风险动作吗?还能拿到任何密钥吗?

只要答案中有一个“能”,问题就不在提示词写得不够严,而在系统把真正的安全控制放错了位置。

← 返回列表