十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Google ADK 零信任 AI Agent 实战:签名、沙箱与网关如何拦住误操作

Google ADK 零信任 AI Agent 实战:签名、沙箱与网关如何拦住误操作 一次退款请求为什么能改写生产数据工位上的工程师收到一张客服退款工单订单金额是149美元用户却要求退回10000美元。新接入的AI Agent会读邮件、生成查询语句还能直接调用生产数据库。监控里出现了一条UPDATE记录WHERE条件指向了另一个账户。这个瞬间说明能写代码的助手已经开始改变真实业务状态。工单系统记录的只是请求真正要保护的是落库动作。恶意请求往往不需要复杂技巧用户只要把破损、紧急和超额退款写在同一段话里模型就可能把它们拼成一个看似合理的动作。它会先读取订单再计算金额接着调用退款工具。每一步单独看都像正常流程串起来却可能越过审批边界。真正危险的地方不是模型会回答而是回答会触发副作用。这类事故也不局限于退款修改库存、删除客户、发起付款和执行脚本都属于同一种风险。Agent一旦拿到共享数据库连接攻击者就能借它的权限改变记录。日志可能只留下模型说了什么却没有留下谁批准了什么。没有可验证的身份事后排查只能依赖猜测。资产范围也应随请求一起确认。Google Developers Blog在2026年8月17日讨论了这类零信任Agent方案场景正是客服与退货流程。文章把风险拆成数据库写入、动态代码执行和模型输入输出三个位置。它的重点不是给系统提示词增加更多禁令而是把约束放到模型之外。对工程团队来说这个思路比换一个更听话的模型更有落地价值。本文沿着一次退款请求的路径来拆解这套做法先看谁有权写入再看代码能跑到哪里最后看业务规则在哪里拦截。你会看到Cloud KMS、HSM和gVisor分别解决什么问题。你也会得到一段只依赖Python标准库的本地验证代码。代码能帮助你理解流程但生产环境仍要接入真实的密钥、沙箱和审批系统。零信任不是把Agent当成敌人而是承认它可能被输入带偏。模型可以负责理解自然语言和选择工具却不能单独决定一笔不可逆的写入。每个副作用动作都应留下可验证的证据并经过独立规则检查。这样即使模型判断失误错误也会在真正落库前停住。模型仍能规划但不再拥有最后一笔写入权。先把动作分成读取和写入安全边界才有清楚的落点。读取可以自动完成写入必须带着资源和审批信息。金额、订单状态与请求人都要成为结构化字段。这样的划分让工程师能在每个副作用发生前插入拒绝点。这一步也让测试环境与生产环境可以使用同一套接口。规则可核对。系统提示词挡不住越权很多项目的第一道防线是一句“退款金额不得超过订单金额”再配上一段很长的系统提示词。它在正常对话里看起来有效因为模型会复述规则并给出礼貌答复。可是提示词只是上下文中的文字不是数据库能够验证的权限。攻击者改变输入模型就可能重新解释那条规则。模型还会受到上下文混淆的影响客服邮件、网页内容和工具返回值都可能携带新的指令。只要这些内容进入同一个上下文模型就要在不同可信等级之间做判断。它没有硬件身份也没有天然的事务边界。把安全责任全部压给它等于让执行者自己决定自己是否违规。传统应用通常把权限写在服务账号、网关和数据库策略里Agent系统却常把权限藏在自然语言里。自然语言适合描述意图不适合证明授权。一个“请帮我处理退款”的句子不能说明金额上限、订单归属和审批人。真正的授权必须落在结构化字段和可验证的策略上。授权字段必须由服务端生成和核对。可以把一次工具调用拆成四个问题谁发起改了什么为什么能改以及谁批准。模型只能提供候选答案不能自己回答完全部问题。签名负责确认操作者网关负责检查业务条件数据库入口负责最后拒绝。三者各自独立任何一层失败都不应由模型自行绕过。每个答案都要可追溯。边界解决的问题失效时的后果签名确认哪个Agent提交了写入无法证明来源或发现篡改沙箱限制动态代码接触主机可能读密钥或连接外网语义网关检查业务规则和数据流向合法身份也可能执行错事表里的三道边界不是并列的产品开关而是一条连续的拒绝链。签名通过并不代表业务允许沙箱隔离也不代表数据正确。每一层都应该能够独立记录拒绝原因并把结果传给审计系统。这样排查时能知道请求究竟在哪一扇门前被挡住。拒绝结果不能被后续模型调用覆盖。安全设计还要把“读”和“写”分开读取订单通常可以自动完成退款和删除则必须提高门槛。权限模型不应只按工具名称区分还要看参数、资源归属和金额。相同的refund工具处理测试订单与处理生产订单风险完全不同。模型看到的是一句话策略看到的应是一组字段。策略越靠近资源越容易在事故前生效。给每一次写入绑定可验证的身份第一道硬边界放在数据库入口之前Agent不能把一条裸SQL直接交给生产系统。它需要先构造一个待签名载荷里面写明Agent身份、动作类型、资源编号和变更值。签名覆盖的是完整载荷而不是一段描述性文字。任何字段在传输中被改动验签都应该失败。写入服务还要拒绝缺失字段和异常格式。生产环境可以为每个Agent分配独立的Service Account再给它绑定Cloud KMS里的非对称签名密钥。私钥由HSM保护应用拿到的是受权限控制的签名能力不是可复制的密钥文件。这样容器被读取时攻击者也很难直接带走私钥。每个Agent的权限范围和审计记录也能单独管理。密钥权限变化也要进入审计记录。签名之前必须固定序列化规则否则同一份数据在不同语言或不同字段顺序下会得到不同摘要。常见做法是对JSON对象按键排序并明确字符编码和分隔符。金额也要使用统一的整数分单位避免浮点数在签名和验签时出现差异。安全协议最怕的不是复杂而是两端理解不一样。数据库服务收到载荷后不能只相信调用方附带的Agent名称。入口服务应根据密钥目录找到对应公钥验证签名再检查资源归属和业务阈值。通过以后才开启事务并把原始载荷、签名和结果写入不可随意修改的审计记录。验签失败要在写入发生前返回不能先写后补日志。Google的本地演示用HMAC模拟Cloud KMS原因是HMAC可以在没有云账号的电脑上跑通签名和验签。它不能替代HSM也不能提供同样的密钥隔离能力。工程师可以先用它验证字段覆盖、篡改检测和失败路径。迁移到生产时再把签名实现换成Cloud KMS客户端。这样本地测试也能看到失败路径并验证篡改确实会被拒绝。这里有一个常被忽视的细节签名证明的是“这个载荷来自某个Agent”并不证明“这个载荷符合业务”。一个拥有合法密钥的Agent仍可能因为提示注入而提交超额退款。于是数据库入口还要重复检查金额、订单状态和审批标记。身份验证与业务授权必须同时成立不能互相替代。签名是身份证明不是业务通行证。审计记录也要能回答时间问题载荷中应带请求编号和单调可比较的时间字段。服务端要拒绝过期请求、重复请求和已经消费过的请求。否则攻击者拿到一条旧的合法签名就可能再次提交同一笔操作。签名让篡改容易被发现重放保护让旧请求无法无限复用。请求状态也要有明确的生命周期。让动态代码待在没有网络的沙箱里Agent常被赋予一个run_python工具用来处理附件、计算价格或转换数据。这个工具一旦直接调用主进程的exec或subprocess模型生成的代码就进入了应用所在的运行环境。代码可能读取环境变量、扫描文件也可能打开网络连接。它不需要理解业务只要找到一条可利用的路径就够了。它的权限越大潜在损失就越难收拾。普通容器并不是完整的安全边界因为容器进程仍然共享宿主机内核。配置错误、过大的Linux能力或内核漏洞都可能让隔离失效。即使不考虑逃逸容器里默认开放的网络和文件权限也足以造成数据外传。动态代码执行应被当成高风险外部输入而不是普通函数调用。所以不能只看镜像名称。gVisor提供了一层用户态内核常见实现会由Sentry截获系统调用再交给受控的运行时处理。它不是把不可信代码变成可信代码而是减少代码能观察和触碰的对象。Agent只应该拿到完成任务所需的最小目录和最小输入。其余文件、设备和主机能力都应从沙箱中消失。关键是减少暴露面而不是改变模型行为。网络隔离是这道边界的核心运行不可信代码时可以明确设置network为none。没有默认路由、DNS和外部接口代码即使尝试发送环境变量也没有出口。文件挂载应使用只读模式容器能力应全部丢弃。资源限制则负责防止死循环和内存消耗拖垮宿主机。这些限制都要在启动参数中显式写出。沙箱配置还要设定CPU、内存、临时目录大小和最长执行时间所有上限都应写入部署文件。超时后要销毁运行实例而不是继续等待模型给出解释。返回结果也要限制长度并清理控制字符避免把终端内容原样送回上下文。隔离的目标是把失败关在一次任务里。上限应按任务类型分别设定。在本地验证时可以故意让测试代码读取环境变量并创建socket连接再观察沙箱返回的错误。这个测试不能只看进程是否退出还要检查宿主机没有新增文件、网络连接和异常权限。对于生产集群还要把逃逸测试、资源耗尽测试纳入发布前验收。安全边界必须用失败案例证明而不是用配置截图证明。gVisor也不是万能药宿主机内核、容器运行时和挂载策略仍然需要维护。沙箱内若放入长期有效的云凭证攻击者依旧可能在允许的范围内滥用权限。更稳妥的办法是使用短时令牌、无网络执行和专门的结果服务。沙箱负责限制运行环境凭证治理负责限制数据价值。云端凭证仍然要按最小权限配置。在模型输入输出外再加一层语义网关第三道边界处理的是签名和沙箱都无法判断的业务语义。一个合法Agent可以用自己的密钥签署一笔149美元退款也可以在沙箱里安全地计算金额。可是订单已经超过退款期限时这笔操作仍然不该执行。业务规则需要一个不依赖模型自觉的确定性检查点。这道检查决定动作是否值得继续。语义网关可以放在用户消息进入模型之前也可以放在模型决定调用工具之后。前一处负责识别高风险意图、敏感数据和不允许的请求类型。后一处负责检查工具名、参数、资源归属和审批状态。两边都不应该让模型自己修改检查结果拒绝结果要由代码直接返回。网关的判断要比模型的解释更有优先级。在Google ADK工作流里可以把安全逻辑挂到Runner的插件或回调层让每个Agent共享同一套策略。Before Tool Callback收到工具名和参数后先执行金额、订单状态和权限检查。通过以后才进入签名或沙箱流程失败则返回固定错误类型。这样新增加的Agent不会因为漏写一段提示词而少一道防线。回调结果要能被测试和审计。网关规则最好使用结构化配置策略中明确资源类型、金额上限、时间窗口和人工审批条件。规则匹配应有稳定的优先级不能让模型生成的自然语言覆盖配置结果。每次修改策略都要配套回归用例至少覆盖正常请求、边界值、缺字段和恶意输入。安全规则也是代码应该按代码的方式评审。输出侧同样需要检查模型返回的内容可能包含内部编号、访问令牌或未经转义的HTML。发送给前端前应做敏感信息过滤和上下文编码不能把模型输出直接拼进页面。错误信息也要避免泄露数据库结构和密钥路径。输入拦截保护工具输出拦截保护用户和系统。任何异常都应被记录但不被回显。语义网关要记录原始请求摘要、命中的规则、工具参数摘要和最终决定但不要把完整密钥或个人数据写进普通日志。记录拒绝原因时要使用稳定的错误码方便按版本比较拦截率。审计人员需要看到“为什么拒绝”开发人员还要看到“哪条规则拒绝”。两种视角都保留排障速度才不会被牺牲。网关不能替代人工审批尤其是付款、删除和批量修改这类不可逆动作。对于超过阈值的请求系统可以生成待审批任务冻结原始载荷等真人确认后再签名执行。审批人看到的内容必须和最终签名的内容完全一致。否则人工确认只是一个漂亮的按钮并没有真正参与授权。把三道边界接进 Google ADK 工作流把三道边界接进工作流时入口顺序比组件数量更重要。用户请求先经过输入侧网关再交给ADK决定是否需要调用工具。工具调用前再次检查参数数据库写入则进入签名服务。动态代码调用则进入隔离运行器两条路径都把结果带回审计链。每个节点都只承担一种防护责任。Runner初始化时可以挂载统一安全插件插件负责注册回调、错误码和审计钩子。每个业务Agent只声明自己需要的工具和资源不重复实现金额校验。这样策略变化可以集中测试避免多个Agent出现细微差异。插件本身也要保持小而清晰不能变成另一个无法审计的模型层。插件越简单越容易做版本审计。数据库工具不应接收任意SQL字符串而应接收有限的动作对象。对象可以包含操作类型、表名、主键、变更字段和请求编号字段集合由服务端白名单决定。工具把对象交给签名服务签名服务再交给数据库入口。数据库入口拒绝未知字段防止模型借一个合法工具拼出未授权操作。执行Python的工具也需要固定输入输出协议代码、输入文件和资源上限分别传递。运行器为每次请求创建短生命周期实例挂载只读文件关闭网络并设置超时。返回值先经过大小限制和字符清理再由Agent决定如何向用户解释。任何异常都只表示这次任务失败不应暴露沙箱内部路径。高风险工具还要有幂等键和审批状态模型重试不能制造第二笔退款。签名载荷里携带同一个请求编号入口服务处理过一次后就拒绝重复消费。审批状态要与载荷摘要绑定审批之后金额发生变化必须重新走流程。这样重试、网络重连和模型重复规划都不会绕开授权。可观测性要覆盖模型决定和工具结果之间的空白区域不能只采集输入输出文本。至少要记录回调触发、网关结果、签名请求、沙箱启动和数据库结果。日志中的关联ID应贯穿一次任务方便从用户请求追到最终事务。监控指标还要区分模型拒绝、策略拒绝、验签失败和运行超时。上线前应做一轮故障演练篡改金额、替换主键、重放旧签名、读取环境变量和制造死循环。每个案例都要有明确的预期状态包含“没有写入”“没有外连”和“审计可查”。如果只能看到模型说它拒绝了却看不到系统实际拒绝验收就还没有完成。安全能力必须落在外部可观测的结果上。从演示代码走向生产验收下面的程序可以直接用Python运行它用本地HMAC模拟签名服务并把业务阈值放在入口检查里。程序故意构造一次合规请求再修改金额后重新验签。你会看到签名校验和业务校验是两件事缺少任何一件都可能放行错误操作。它不启动容器所以不能代替gVisor的隔离测试。先看结果再把依赖替换成云服务。import hashlib import hmac import json AGENT_KEYS {refund-agent: blocal-demo-key-change-me} MAX_REFUND_CENTS 100000 def canonical(payload): return json.dumps(payload, ensure_asciiFalse, sort_keysTrue, separators(,, :)).encode(utf-8) def sign(agent_id, payload): key AGENT_KEYS[agent_id] return hmac.new(key, canonical(payload), hashlib.sha256).hexdigest() def verify(agent_id, payload, signature): key AGENT_KEYS.get(agent_id) if key is None: return False expected hmac.new(key, canonical(payload), hashlib.sha256).hexdigest() return hmac.compare_digest(expected, signature) def allow_refund(payload): return ( payload.get(order_owner) payload.get(requester) and payload.get(refund_cents, 0) MAX_REFUND_CENTS and payload.get(approved) is True ) def main(): payload { agent_id: refund-agent, order_owner: user-7, requester: user-7, refund_cents: 5000, approved: True, } signature sign(payload[agent_id], payload) print(valid:, verify(payload[agent_id], payload, signature), allow_refund(payload)) payload[refund_cents] 900000 print(tampered:, verify(payload[agent_id], payload, signature), allow_refund(payload)) if __name__ __main__: main()把这段代码保存后运行第一行应同时得到两个True第二行应同时得到两个False。金额改变以后原签名无法匹配新的载荷业务阈值也会拒绝请求。这个结果只证明拒绝链的基本关系不代表本地HMAC具备云端密钥的防护能力。工程团队可以把它作为单元测试的起点。测试通过后还要补充重放和超时用例。接入真实环境时先把HMAC替换为Cloud KMS的非对称签名再为每个Agent配置独立Service Account。接着把动态代码交给带gVisor运行时的容器明确网络、能力、文件和资源上限。最后把业务规则挂到ADK回调和数据库入口两处。三处都通过以后才谈自动执行生产动作。每次替换都要保留同样的载荷格式。变更过程也要保留记录。验收清单还应包含密钥轮换、旧签名拒绝、重复请求拒绝和审批内容不可修改。沙箱测试要验证没有外网、没有敏感挂载、超时会销毁实例。网关测试要覆盖缺字段、边界金额、错误资源和输出泄露。每次策略或模型升级都应重跑同一组攻击样例。验收记录应与版本号一起保存。零信任Agent的价值不在于让模型永远不犯错而在于把犯错的代价压缩在可控范围内。模型负责理解和规划签名负责身份沙箱负责环境网关负责业务。只要权限、运行环境和业务规则都写在模型之外Agent才有资格碰生产系统。真正的自动化不是放弃控制而是把控制变成可验证的工程边界。
返回列表