安全指南#
允许 LLM 访问外部资源(例如搜索界面、数据库或 Wolfram Alpha 等计算资源)可以显著提高其能力。然而,LLM 完成代际生成的不可预测性意味着——如果未进行仔细集成——这些外部资源可能会被攻击者操纵,从而导致这些组合模型部署风险的急剧增加。
本文档阐述了关于安全可靠地为 LLM 提供外部数据和计算资源访问权限的指南和原则。
黄金法则#
将 LLM 视为实际上完全受用户控制的 Web 浏览器,并且其生成的所有内容均不可信。 任何被调用的服务必须在 LLM 用户的上下文中被调用。 在设计资源和 LLM 之间的内部 API(见下文)时,请问问自己“我是否会故意将此资源与此接口直接暴露于互联网?” 如果答案是“否”,您应该重新考虑您的集成。
假定的交互模型#
我们假定访问外部资源的数据流具有以下逻辑组件
LLM,它接收提示作为输入并生成文本作为输出。
解析/调度引擎,它检查 LLM 输出,以指示是否需要调用外部资源。 它负责以下事项
识别必须调用一个或多个外部资源
识别请求的特定资源并提取要包含在外部调用中的参数
使用正确的参数(包括与 LLM 用户关联的任何身份验证和/或授权信息)调用与请求资源关联的内部 API
接收响应
将响应以正确的格式在正确的位置重新引入 LLM 提示中,并将其返回给管理 LLM 的进程以进行下一次 LLM 执行
充当解析/调度引擎和单个外部资源之间网关的内部 API。 这些 API 应尽可能具有硬编码的 URL、端点、路径等,旨在最大限度地减少攻击面。 它负责以下事项
验证当前已通过 LLM 身份验证的用户是否有权使用请求的参数调用请求的外部资源
验证输入
与外部资源交互并接收响应,包括任何身份验证
验证响应
将响应返回给调度引擎
解析步骤可以采用多种形式,包括预加载带有令牌或动词的 LLM 以指示特定操作,或者对输出行进行某种形式的嵌入搜索。 目前常见的做法是包含一个特定的动词(例如,“FINISH”)来指示 LLM 应将结果返回给用户——实际上也使用户交互成为外部资源——但是,这个领域还很新,以至于没有所谓的“标准做法”。
我们将内部 API 与解析/调度引擎分离,原因如下
将验证和授权代码与相关的 API 或服务共同定位
将外部 API 所需的任何身份验证信息与 LLM 隔离(以防止泄漏)
实现 LLM 使用的外部资源的更模块化开发,并减少外部 API 更改的影响。
具体指南#
优雅且秘密地失败 - 不要泄露服务详情#
当由于任何原因(包括由于格式错误的请求或授权不足)无法访问资源时,内部 API 应返回一条 LLM 可以适当响应的消息。 来自外部 API 的错误消息应被捕获并重写。 给解析引擎的文本响应不应指示调用了哪个外部 API 或失败原因。 解析引擎应负责处理由于缺少授权而导致的失败,并重建 LLM 生成,就好像未尝试调用资源一样,并处理其他与授权无关的失败,并返回不泄露集成细节的非特定失败消息。
应该假设服务用户将尝试发现他们的特定提示或 LLM 会话未启用且他们没有授权使用的内部 API 和/或动词; 用户不应能够根据与 LLM 的交互来检测到某些内部 API 的存在。
记录所有交互#
至少应记录以下内容
从解析/调度引擎触发操作的文本
该文本如何解析为内部 API 调用,以及参数是什么
提供给内部 API 的授权信息(包括:身份验证/授权的方法和时间、到期时间或持续时间、范围/角色信息、用户名或 UUID 等)
从内部 API 到外部 API 进行了什么调用,以及结果
结果文本如何重新插入到 LLM 提示中
参数化并验证所有输入和输出#
对外部服务的任何请求都应参数化并具有严格的验证要求。 这些参数应注入到针对已验证版本的外部 API 进行匹配的经过审计的模板中,并将用户控制限制在最小的可行参数集。 应特别注意潜在的代码注入途径(例如,SQL 注入;python 的注释字符注入;搜索查询中的开放重定向等)以及响应中远程文件(或数据)包含的风险。 在可能的范围内,还应根据预期内容和格式验证从外部 API 返回的值,以防止注入或意外行为。
除了上述验证要求外,还应检查所有输出中是否包含私人信息,然后再返回给解析/调度引擎,特别是泄漏的 API 密钥、用户信息、API 信息等。 反映诸如用户身份验证、IP 地址、LLM 访问资源的上下文等信息的 API 可能会一直令人头疼,必须主动设计以防止出现这种情况。
尽可能避免持久化更改#
来自 LLM 对外部 API 的请求应避免产生持久状态更改,除非服务的功能需要。 执行高风险操作,例如:创建或删除表; 下载文件; 将任意文件写入磁盘; 建立和 nohup 进程; 除非明确要求,否则都应明确禁止。 在这种情况下,内部 API 应与内部服务角色关联,该角色隔离进行和持久化这些更改的能力。 在可能的情况下,考虑其他使用模式,这些模式允许在不需要 LLM 外部服务直接执行这些操作的情况下实现相同的效果(例如,提供指向预填表格的链接以安排约会,用户可以在提交之前修改该表格)。
任何持久化更改都应通过参数化接口进行#
当外部 API 的主要功能是记录某些持久状态(例如,安排约会)时,这些更新应完全参数化并进行严格验证。 此类 API 记录的任何信息都应与请求用户相关联,并且应仔细评估和控制任何用户检索该信息(无论是针对他们自己还是任何其他用户)的能力。
优先使用允许列表和故障关闭#
在一切可能的情况下,任何外部接口都应默认为拒绝请求,并将特定的允许请求和操作放在允许列表中。
将所有身份验证信息与 LLM 隔离#
LLM 应无权访问外部资源的任何身份验证信息; 任何密钥、密码、安全令牌等都应仅对调用外部资源的内部 API 服务可访问。 调用服务还应负责验证用户是否有权访问相关资源,可以通过内部授权检查或通过与外部服务交互来完成。 如上所述,应从文本输出中删除有关任何错误、授权失败等的所有信息,并返回给解析服务。
主动与安全团队合作评估接口#
将 LLM 与外部资源集成本质上是一项 API 安全练习。 在设计这些接口时,尽早且及时地让安全专家参与可以降低与这些接口相关的风险,并加快开发速度。
就像 Web 服务器一样,在 Web 规模上进行红队测试和测试是接近行业级解决方案的要求。 以零成本和最小的 API 密钥注册摩擦公开 API 是行使系统的规模、稳健性和审核能力的必要条件。
对抗性测试#
AI 安全和安保是一项社区工作,这也是我们向社区发布 NeMo Guardrails 的主要原因之一。 我们希望将许多开发人员和爱好者聚集在一起,为可信赖的 AI 构建更好的解决方案。 我们的初始版本是一个起点。 我们构建了一系列护栏和教育示例,这些示例提供了有用的控制并抵御各种常见攻击,但它们并非完美。 我们对这些示例机器人进行了对抗性测试,并将很快发布关于更大规模研究的白皮书。 以下是在创建自己的机器人时需要注意的一些事项
过度激进的审核:一些 AI 安全护栏有时可能会阻止原本安全的请求。 当多个护栏一起使用时,这种情况更有可能发生。 解决此问题的一种可能的策略是在流程中使用逻辑来减少不必要的调用; 例如,仅对事实性问题调用事实核查。
规范形式的过度概括:NeMo Guardrails 使用规范形式,如
ask about jobs report
来指导其行为并概括 Colang 配置中未明确定义的情况。 它有时可能会错误地进行概括,从而导致护栏遗漏某些示例或意外触发。 如果发生这种情况,通常可以通过在 Colang 文件 中添加或调整define user
形式,或修改 配置 中的示例对话来改进它。非确定性:LLM 使用称为温度的概念以及其他技术来引入其响应的变化。 这创造了更加自然的体验,但是,有时会在 LLM 应用程序中创建意外行为,这些行为可能难以重现。 与所有 AI 应用程序一样,最好使用全面的评估和回归测试套件。
结论#
将外部资源集成到 LLM 中可以显著提高其能力,并使其对最终用户更有价值。 然而,表达能力的任何提高都伴随着潜在风险的增加。 为了避免潜在的灾难性风险,包括未经授权的信息泄露,直至远程代码执行,允许 LLM 访问这些外部资源的接口必须从安全第一的角度进行仔细和周到的设计。