-
保护你的 App:智能体功能的风险缓解
了解如何评估因间接提示词注入而导致的威胁,例如数据外泄和意外操作。探索在使用 App Intents 和 Foundation Models 框架时需要注意的系统防护措施与安全最佳做法,包括用户确认、安全提示词设计和身份验证等风险缓解措施。
章节
- 0:00 - Introduction
- 2:06 - Risks
- 6:32 - Threat modeling
- 11:56 - Implementing mitigations
- 12:03 - Foundation Models
- 17:55 - App Intents
资源
相关视频
WWDC26
- 使用 App Schemas 打造智能 Siri 体验
- 使用 Foundation Models 框架构建智能体 App 体验
- 探索适用于 Siri 和 Apple 智能的 App Intents 高级功能
WWDC25
WWDC20
-
搜索此视频…
你好 我是Willy 今天 我将告诉你如何识别 并降低App中智能体功能的新风险 随后 我的同事Akshay将提供 具体的可行步骤 帮助你利用平台上的API 保护你的App 随着大语言模型(LLM)日益普及 许多App正在探索如何借助它们 实现新的智能功能 使LLM成为关键的系统组件 在你的应用中 你可以 发送指令和提示词 包含用户请求和额外上下文 发送给LLM 让它执行 一个或多个操作 以获取中间结果 直到最终向用户提供响应 我们的平台让你可以通过 以下方式创建智能体体验 使用Foundation Models框架 设计自定义智能体 或使用App Intents框架 让App与Siri协作
新能力带来了新的安全风险 LLM在你的应用中引入了 一个新的概率引擎 它功能强大 但也存在被欺骗的风险 本次演讲旨在重点介绍新的安全风险 与智能体功能相关的 并提供你可用于保护用户的 技术和API 关键是 我们希望确保你的App 按预期运行 并将用户安全放在首位 在继续之前 我们要明确 本次演讲不涉及的内容 我们不会讨论模型安全 即确保模型输出内容的安全性 我们也不会讨论模型护栏 以及防止规避措施 虽然我们将讨论的一些原则 可用于处理此类情况 但我们将聚焦于试图攻击 你应用的外部攻击者 如需了解模型安全 请查看下方链接的精彩演讲
我们先来谈谈智能体系统 带来的新风险 首先 思考一下攻击者为何 会将你的App作为目标 你的App可能做一些 攻击者感兴趣的事情 例如 托管敏感用户数据 执行金融交易 访问麦克风或摄像头等系统资源 甚至控制物理设备 攻击者可能会利用你的App 来实现他们的目标 为帮助说明攻击手段和缓解措施 我们将使用Loose Leaf应用 这是一个示例App 可能成为下一代社交网络 专注于各类茶文化 从热茶到冷茶再到珍珠奶茶 我们相信Loose Leaf 是社交网络的未来
Loose Leaf已具备 一些令人兴奋的功能 例如可以向朋友发送茶叶配方消息 或分享你拍摄的精彩茶会照片 我们之前讨论了 如何进行威胁建模 以缓解这些传统功能的风险 值得回顾那个视频 确保不遗忘基础知识 现在 Loose Leaf的开发者们 一直在酝酿 他们兴奋地宣布一项名为 "举办茶会" 该功能使用Foundation Models 和App Intents框架来 查看你的日历以找到 举办茶会的最佳时间 确定应邀请哪些朋友 以及根据朋友偏好 决定提供哪种茶 并下单购买大家喜欢的茶叶 哇!
这项新功能依赖于Loose Leaf 的智能体循环 并具有两个值得关注的特性 第一 该功能从多个来源 获取上下文 帮助智能体做出决策 第二 智能体可以代表用户 调用一个或多个操作 这些操作可能带来 不同类型的副作用
从第一个特性出发 我们引入一种新风险 间接提示词注入 间接提示词注入是指 嵌入额外上下文中的指令 提供给模型 旨在转移控制流
在我们的智能体循环中 这是指某些指令 可能嵌入提示词中的 初始额外上下文里 或工具结果中
在实践中 这可能表现为 用户请求组织茶会 并附上日历 但日历中包含一个事件 带有给模型的指令 执行另一个操作 例如删除敏感用户数据! 真糟糕! 我们将进行的威胁建模练习 包括识别所有 不受信任的上下文来源 我们智能体系统的第二个特性 是操作调用能力 这可能会产生副作用 或执行操作的意外后果
当与间接提示词注入结合时 攻击者可能触发 带有副作用的操作 从而实现其目标 例如窃取用户数据 盗取资金 控制物理设备或删除数据
当间接提示词注入 导致意外操作时 我们可以认为注入 具有两种不同的影响 第一种是数据污染 即攻击者影响已执行操作的参数 例如 用户可能想 向妈妈发送消息 但攻击者注入指令 将消息发送给自己
第二种是操作污染 攻击者影响执行哪个操作 用户可能只是请求 摘要一封邮件 但攻击者可能引导LLM 打开恶意网页 将邮件附加到攻击者选择的URL上
概念化这些风险 我们可以参考 Simon Willison的"致命三元组" 该概念描述了用户 面临最大风险的情况 当智能体系统具备以下条件时 可访问私有数据 接触不受信任的内容 以及具备对外通信的能力 最后一条我们可以进一步概括 以考虑任何具有副作用的 操作风险
总结本节内容 我们想强调 解决间接提示词注入 是一个活跃的研究领域 这意味着目前的最佳方法 是了解你的App面临多大风险 并着力降低该风险 既然我们已讨论了 智能体系统带来的风险 我们将进行一次威胁建模练习 你可以对自己的App进行 以识别不受信任的数据来源 并识别潜在的高风险操作 我们首先对智能体循环输入 进行数据流分析 即提示词 我们要识别用于构建 提示词的数据来源 在此练习中 我们要精确找出 不受信任的上下文来源 这些来源可能包含提示词注入 回到我们的Loose Leaf应用 有几个数据来源用于构建提示词 首先是向LLM提供指导的指令 关于其目的和角色 接下来是用户的提示词 LLM将处理的任务 以及要实现的目标 提示词还可以包含额外上下文 以帮助LLM实现目标 例如包含过去的茶叶订单 用户保存的茶叶配方 即将到来的日历事件 以确定最佳的茶会时间 以及好友动态 以获取朋友分享的内容 一旦了解了输入到 提示词的数据来源 我们需要识别哪些是不受信任的 一般来说 我们可以将任何输入 来自外部实体的视为攻击面 在我们的案例中 我们将日历内容识别为 以及好友动态视为不受信任 因为 任何人都可以向用户发送日历邀请 该邀请可能被输入模型 而用户的"好友"可以在 动态中发布任何内容 这些内容会被输入提示词 这些都可能包含提示词注入 以影响执行的操作
在识别不受信任的上下文来源之后 我们要检查智能体可用的操作 及其可能产生的副作用 首先 我们有OrderTeaTool() 这是为茶会订茶的必备操作
PostAndFetchPublicFeedTool() 将在用户动态发布帖子 内容由模型生成 有助于向朋友传播消息
BrewingTimerIntent() 将在茶会期间为你提供帮助 确保你的茶叶冲泡时间恰好 最后 Delete Photo将从 用户动态中删除照片 以防茶叶看起来不够完美 在考虑所有这些操作时 我们需要识别每个操作 可能产生的副作用
OrderTeaTool() 与金融风险相关 这意味着如果意外调用 用户可能损失资金
另一方面 PostAndFetchPublicFeedTool() 存在数据外泄风险 因为模型可能通过公开帖子 泄露敏感信息
BrewingTimerIntent() 本身可能没有副作用 但如果它接受标签 则可能允许提示词注入 为后续攻击写入更多指令
Delete Photo存在数据丢失风险 尤其在没有撤销功能的情况下
既然我们已识别出 恶意输入可能进入LLM的位置 以及操作可能产生的副作用 我们可以开始设计和实施缓解措施 以保护用户 我们想强调应尽量专注于 确定性缓解措施作为基线 因为其安全保障 更易于审计和分析
考虑到模型能力的快速发展 我们也可以考虑其他 具有更多概率保障的缓解措施 在此 我们介绍 几种不同的缓解措施 可用于保护你的应用 通过在提示词级别添加检查 或在操作执行阶段添加检查 我们在设计Siri AI时 使用了其中一些措施 我们来逐一介绍 首先 我们可以回顾提示词 并开始添加提示词缓解措施 我们可以对敏感数据进行脱敏 例如个人身份信息(即PII) 这些信息可能存储在过去的订单中 这样敏感数据就永远不会传入LLM 因此无法被外泄 接下来 我们可以向模型 应用spotlighting 以表明此内容被视为不受信任的 这是一种概率性缓解措施 因为提示词注入 可能以某种方式构造 使spotlighting失效 不过我们建议采纳此措施 因为不同模型能 更有效地执行这些限制
现在 我们来看 可以实施的操作缓解措施
首先 考虑哪些操作 应该需要用户确认 这些操作值得在继续之前 由人工检查 由于它们包含副作用 接下来 考虑哪些工具应仅在 设备已通过身份验证 或解锁时运行 由于智能体可能从锁屏可访问 对用户存在重大风险的操作 不应可被访问
我们已了解了不同类型的缓解措施 以及它们如何应用于你的系统 但还有许多其他类型 我们欢迎你去探索它们 以降低App的风险
进行威胁建模时 关键要记住的是 你要识别攻击者可能希望 从你的应用中获取什么 并从中应用缓解措施 以应对提示词级别的风险 或操作执行阶段的风险 现在Akshay将向你展示具体工具 帮助你保护你的App 有请Akshay!
谢谢你 Willy 大家好 我是Akshay 我将向你展示如何保护智能体App 使用Willy刚刚讨论的一些护栏 如果你使用Foundation Models 框架构建App 我将向你展示如何注入安全检查点 到你的智能体执行过程中
如果你使用App Intents与 Apple 智能集成 我将介绍其中可用的安全缓解措施 让我们从Foundation Models开始 Foundation Models框架 提供了强大的构建智能体的API 我将重点介绍生命周期事件修饰符API 并使用它注入安全护栏 我将假设你对该框架已有基本了解 如需深入了解 请查看下方链接的精彩演讲 我们首先使用Foundation Models 为Loose Leaf构建简单的智能体 不知道你怎么想 但我离不开 我的那杯大吉岭红茶 所以在一切开始之前 我们先构建一个订茶工具 要定义工具 我们需要遵循Tool协议 我们为工具指定名称 描述 和Arguments 模型使用这些元数据了解 工具的用途及调用方式 接下来 我们提供调用工具时 实际执行的Implementation
让我们再定义一个工具 PostAndFetchPublicFeedTool 将你的消息发布到公开动态 并获取最新发布的消息 构建智能体的下一步是创建Profile 在Profile中 我们首先添加 模型Instructions 以及我们刚才定义的工具 然后附加会话属性 例如使用哪个模型 在此 我们使用的是设备端模型
此Profile随后用于实例化 LanguageModelSession 随后可在智能体循环中使用 有了基本智能体 我们将注入安全策略 为此 我们将使用生命周期事件修饰符 这些修饰符是确定性触发的回调 在会话执行的特定生命周期节点 因此 我们可以将这些 生命周期事件用作检查点 以实施安全策略 我们现在来看其中两个修饰符
让我们回到简化版的智能体循环 如同西西弗斯 LLM在 每次迭代时输出一个操作 此操作由Executor执行 其输出被反馈给LLM 用于下一次迭代 第一个修饰符让我们 在工具运行前拦截工具调用 这就是.onToolCall修饰符 它保证在LLM输出工具调用时触发 在执行器运行工具之前 重要的是 如果此回调抛出错误 则工具永远不会被执行 控制权立即返回循环 这是强制执行用户确认的最佳位置
回到我们的Loose Leaf智能体 我们注意到OrderTeaTool 存在金融影响 这让我非常担忧 所以我希望始终请求用户确认 在运行此工具并转账之前
为此 我们在profile中添加 .onToolCall回调 由于此回调在每次工具调用前运行 我们首先检查当前工具 是否为OrderTeaTool 如果不是 我们立即返回并运行工具 但如果是 我们向用户请求确认 如果用户未确认 我们抛出一个错误 从而阻止工具运行 你需要用自己的实现替换 confirmWithUser()函数 关键是 通过将确认逻辑 仅添加到代码中的这一处 我们就能覆盖所有工具调用 总结一下 记住此修饰符在 每次工具执行前运行 工具本身在此回调返回之前不会运行 你可以抛出错误来阻止工具执行 从概念上来说 .onToolCall修饰符 在模型输出上运行 现在来看一个帮助我们 检查模型输入的修饰符 .historyTransform会触发 在脚本呈现给模型进行推断之前 这发生在新用户请求到来时 以及循环的每次迭代时 转换会修改脚本的尾部 我们将用它进行spotlighting 和脱敏PII 回到我们的示例 注意到 PostAndFetchPublicFeedTool() 返回公开动态中的帖子 攻击者可以轻松向该动态 发布提示词注入 我们必须对此动态的输出保持警惕 因此我们要用特殊标签标记此输出 以告知模型这是不受信任的数据
我们通过添加Spotlighting分隔符来实现 在.historyTransform中 在回调中 我们首先遍历所有条目 只关注来自我们工具的 toolOutput条目 所有其他条目不加修改地 复制到输出脚本 然后我们修改toolOutput条目 我们遍历各片段 对每个相关片段 添加分隔标签 在此示例中 我们使用尖括号 "<>" 你将使用适合你模型的标签 delimit()函数(我们将跳过其实现) 将文本片段转换为 含分隔内容的片段 现在来看脱敏处理 实际上 我们可以用完全相同的方法 脱敏敏感数据 我们只需替换delimit()函数 替换为脱敏函数 用于替换敏感数据 使用占位符字符串""
有一件重要的事需要记住 转换后的条目仅限于当前推断迭代 这意味着这些修改 在下一次推断调用中不可见 你必须再次应用它们 对于你希望持久化的耗时转换 使用@SessionProperty注解 这让你可以对会话历史 应用有状态的转换 详情请查阅文档 我们了解了生命周期 事件修饰符如何 提供确定性钩子以注入安全策略 但我没有介绍所有修饰符 该框架还提供了许多其他修饰符 这些修饰符在智能体循环中的 其他关键节点触发 该框架还允许你构建 自己的profile修饰符 并将其打包为可复用的组件 请查阅Foundation Models文档 以深入了解 以及许多其他强大功能 好的 现在切换到App Intents App Intents让你将App 与Apple 智能集成 以及Siri Spotlight Shortcuts等丰富系统体验 在本次演讲的剩余部分 我将假设你已熟悉App Intents 和App Schemas的基础知识 如需深入了解 请查看下方链接的精彩会话 简单回顾一下 当App Intent 采用intent schema时 它就作为工具提供给Siri模型 例如 我们的DeletePhotoIntent 采用photos域中的 deleteAssets schema 从概念上说 这将Delete Photo操作添加到Siri工具箱 这让Siri可以对我们的 工具定义进行推理 并调用它来响应用户查询 然而 由于由模型决定 调用哪个intent 提示词注入攻击可能让 攻击者滥用你的App 用于数据外泄或其他恶意目的 例如 此处我们使用外部上下文运行 该上下文可能试图在无用户意图的 情况下运行Delete Photo 如果此类攻击成功 而我们没有任何其他确定性护栏 尽管Willy已大力警告 那么就存在数据丢失的真实风险 具有外部可见副作用 或破坏性的操作 对攻击者而言是诱人的目标 App Intents系统内置了多项护栏 帮助开发者缓解此类攻击 我们将介绍其中两项 确认和锁屏身份验证 让我们从确认开始 系统使用基于风险的情境确认机制 这会自动对App中的高风险操作 触发确认 操作的风险通过考量 静态操作元数据来确定 以及动态系统状态 当选定一个intent时 在执行之前 系统将使用intent的风险元数据 调用风险评估系统 我们稍后将回到此元数据 风险评估组件还将系统的 动态状态作为输入 它综合两者来确定 此intent的总体风险 如果风险被认为较高 将要求用户确认 如果用户确认此操作 正常控制流将继续 intent将被执行
另一方面 如果用户拒绝 执行将被阻止 intent将永远不会被调用 现在回到风险元数据
风险元数据是分配给 所有intent的内部风险数据 它基于intent的副作用 某些副作用被认为 比其他副作用风险更高 例如 删除设备状态的intent 例如我们的DeletePhotoIntent 可被视为高风险 外泄数据的intent也可能造成损害 如果在被污染的上下文中执行 对共享内容执行操作的 更新intent也可能存在风险 系统更可能对高风险工具触发确认 那么风险元数据如何与 你的App Intent关联
当intent采用schema时 风险元数据会自动分配给它 你无需做任何额外操作 从技术上来说 是schema 与风险元数据相关联 例如 deleteAssets schema用于删除照片 因此具有破坏性副作用 因此我们的DeletePhotoIntent 也被分配了这个破坏性副作用 但风险是微妙的 让我们定义一个 设置冲泡计时器的新intent 此intent采用createTimer schema 我们如何看待此schema的风险 从表面上看 攻击者似乎 无法造成太大损害 通过创建计时器 因此 我们可能不需要确认此操作 但深入分析 该schema定义了 一个可选的String属性 作为计时器的标签 记住 由模型决定 你的intent的参数 因此提示词注入可能导致 此标签被设置为攻击者控制的值 后续的列出计时器查询 可以提取这些攻击者控制的数据 到那个上下文中 从而污染新的上下文 因此完全跳过确认是不安全的 例如在createTimer等情况下 系统能理解这些中间情况 这正是我们之前讨论的 动态系统状态发挥作用的地方 此信息用于确定是否需要确认 在当前系统上下文中 从而捕捉此操作的动态风险 总结一下 记住确认系统 是情境性的 基于风险的 你的intent将从它们采用的 intent schema继承副作用 具有高风险副作用的操作 更可能需要确认 现在来看锁屏身份验证 如你所知 你可以在锁屏上 与Siri互动 无需先解锁设备 这对于完成快速任务很方便 或双手占用时 但这也意味着实际持有 锁定设备的攻击者 可能通过Siri调用你的intent 因此如果不小心 你的App 可能被此类攻击者利用 用于数据外泄或执行恶意操作 针对此类威胁的主要缓解措施 是要求用户解锁其设备 然后再运行高风险操作 来看如何在App Intent上 定义身份验证策略 对于自定义App Intents 你可以明确设置身份验证行为 通过设置authenticationPolicy属性 例如 由于我们的 DeletePhotoIntent具有破坏性 我们希望确保它不在锁定设备上运行 因此我们明确设置 authenticationPolicy属性 设置为.requiresAuthentication 当你的@AppIntent采用 intent schema时情况略有不同
Schema有自己的默认 authenticationPolicy 此策略在内部基于 每个schema的敏感性设置 以及它处理的数据 与副作用类似 你的intent会自动分配到 schema的默认策略 但如果你想 仍可明确覆盖默认策略 唯一的限制是你的策略必须更严格 例如 假设默认策略 deleteAssets schema的默认策略是 .requiresAuthentication 那么由于我们没有在此明确设置策略 我们的@AppIntent被分配了相同的策略 并将在运行前要求身份验证
但如果我们尝试设置更弱的策略 我们会收到一个有用的构建错误 提示允许的最低策略 总结一下 身份验证是 针对锁屏攻击的重要缓解措施 Schema有自己的默认身份验证策略 这些策略被分配给你的App Intent 你可以覆盖schema策略 但只能将其设置得更严格 请结合锁屏行为来审查你的intent 现在回到Willy! 讲得好 Akshay! 总结一下 你的智能体应用 的后续步骤 包括制定威胁模型 这需要找出提示词中 不受信任的上下文来源 然后确定每个操作的风险级别 基于其副作用 在Akshay的指导下 你有了一些起步参考 关于如何为你的App 实施最佳缓解措施 使用Foundation Models框架 和App Intents框架 现在让我们提高标准 立刻注入你的防御措施!
-
-
12:50 - Tools
// Tools struct OrderTeaTool: Tool { let name = "orderTeaTool" let description: String = "Orders a particular quantity of a tea from the store." // Arguments // Implementation } struct PostAndFetchPublicFeedTool: Tool { let name = "postAndFetchPublicFeedTool" let description: String = "Posts a message to the public feed.” // Arguments // Implementation } -
13:13 - Profile
// Profile class LooseLeafAgent { struct DefaultProfile: LanguageModelSession.DynamicProfile { var body: some DynamicProfile { Profile { Instructions("You are a helpful, tea-loving assistant ... ") OrderTeaTool() PostAndFetchPublicFeedTool() } .model(SystemLanguageModel()) } } } -
13:28 - Session
// Session class LooseLeafAgent { struct DefaultProfile: LanguageModelSession.DynamicProfile { var body: some DynamicProfile { Profile { Instructions("You are a helpful, tea-loving assistant ... ") OrderTeaTool() PostAndFetchPublicFeedTool() } .model(SystemLanguageModel()) } } let session: LanguageModelSession public init() { self.session = LanguageModelSession(profile: DefaultProfile()) } } -
14:33 - Confirmation via onToolCall
// Confirmation via onToolCall var body: some DynamicProfile { Profile { Instructions("You are a helpful, tea-loving assistant ... ") OrderTeaTool() // Financial impact; risky tool. // Other Tools } .onToolCall { call in guard call.toolName == "orderTeaTool" else { return } guard ConfirmationAction.confirmWithUser() else { throw LooseLeafError.userConfirmationDenied } } } -
15:56 - Spotlighting via historyTransform
// Spotlighting via historyTransform var body: some DynamicProfile { Profile { Instructions("You are a helpful, tea-loving assistant ... ") PostAndFetchPublicFeedTool() // Returns untrusted data; requires spotlighting // Other Tools } .historyTransform {γentries in entries.map { entry in guard case .toolOutput(var toolOutput) = entry, toolOutput.toolName == "postAndFetchPublicFeedTool" else { return entry } } toolOutput.segments = toolOutput.segments.map { segment in delimit(segment: segment, startDelimiter: "<<UNTRUSTED>>", endDelimiter: "<</UNTRUSTED>>") } return .toolOutput(toolOutput) } } func delimit(segment: Transcript.Segment, startDelimiter: String, endDelimiter: String) -> Transcript.Segment -
16:48 - Redaction via historyTransform
// Redaction via historyTransform var body: some DynamicProfile { Profile { Instructions("You are a helpful, tea-loving assistant ... ") PostAndFetchPublicFeedTool() // Returns untrusted data; requires spotlighting // Other Tools } .historyTransform {γentries in entries.map { entry in guard case .toolOutput(var toolOutput) = entry, toolOutput.toolName == "postAndFetchPublicFeedTool" else { return entry } } toolOutput.segments = toolOutput.segments.map { segment in redactPII(segment: segment, placeHolder: "[REDACTED]") } return .toolOutput(toolOutput) } } func redactPII(segment: Transcript.Segment, placeHolder: String) -> Transcript.Segment -
23:08 - Intent authentication policy
// Intent authentication policy struct DeletePhotoIntent: DeleteIntent { var entities: [LooseLeafPhoto] static var authenticationPolicy: IntentAuthenticationPolicy = .requiresAuthentication func perform() async throws -> some IntentResult { // Implementation } } -
23:27 - Schema authentication policy
// Schema authentication policy @AppIntent(schema: .photos.deleteAssets) struct DeletePhotoIntent { var entities: [LooseLeafPhoto] // Example: Schema default authentication policy is .requiresAuthentication func perform() async throws -> some IntentResult { // Implementation } }
-
-
- 0:00 - Introduction
Agentic features introduce new security risks. We cover how to identify those risks and introduce techniques and APIs to protect your users.
- 2:06 - Risks
Understand new risks that come with using agentic systems in your app.
- 6:32 - Threat modeling
A threat-modeling exercise for your app can help identify which context sources are untrusted and which actions are potentially risky.
- 11:56 - Implementing mitigations
Learn about concrete tools that you can use to secure your agentic app.
- 12:03 - Foundation Models
If you use the Foundation Models framework, learn how to inject security checkpoints into your agent execution.
- 17:55 - App Intents
Learn about security mitigations available when integrating with Apple Intelligence using App Intents.