跳到主要内容

71 篇博文 含有标签「security」

查看所有标签

第三份副本:向量存储、删除完整性以及 RAG 团队一直忽视的 GDPR 缺口

· 阅读需 12 分钟
Tian Pan
Software Engineer

用户根据 GDPR 第 17 条提交了删除请求。你的团队删除了 Postgres 中的行,清除了 S3 中的缓存文档,并从 CDN 中轮换掉了缓存的 PDF。搞定。隐私团队签字,安全团队签字,工单关闭。六个月后,一名拥有向量索引读取权限的数据分析工程师为了一项聚类实验提取了一组 float[1536] 数组样本,通过公开可用的反演模型(inversion model)运行这些数据,并重建了原始 32-token 文本块中大约十分之九的内容——包括你已经“删除”的文档。没人预料到这一点。没人怀有恶意。流水线完全按照设计运行,只是威胁模型从未将向量存储视为数据副本。

在我见过的几乎每个 RAG 团队中,这种思维误区都是一致的:嵌入(embeddings)被视为不透明的数值产物——是衍生品,而非数据。安全评估批准上线是因为“嵌入不是 PII(个人身份信息)”。隐私评估批准了删除处理,是因为“源文本已不存在”。这两个团队都错了,谁都没有将向量存储建模为用户数据的第三份副本——它紧挨着源数据库和分析仓库,任何拥有索引读取权限的人都可以查询,且由于没有任何工具能识别出 1536 维的浮点向量属于敏感数据,它完全处于所有 DLP(数据泄露防护)扫描器的范围之外。

你的智能体发件箱将是你的下一个送达率事故

· 阅读需 13 分钟
Tian Pan
Software Engineer

当这种情况第一次发生时,值班工程师正盯着已经全红的 Gmail Postmaster 仪表盘,支持信箱因为客户重置密码邮件落入垃圾邮件箱而告急,而导致这一切的智能体(Agent)仍在运行。在当地时间凌晨 4 点到上午 9 点之间,它从公司的主要发送域名发送了 8 万封“个性化跟进邮件”,且全部使用了计费系统所用的同一个 DKIM 密钥签名。等有人注意到时,花费三年建立的域名声誉已毁于一旦,接下来六周内,公司所依赖的每一条事务性消息的收件箱投递率也将随之化为乌有。

从智能体发送邮件看起来就像是一个单行的工具调用。send_email(to, subject, body) 是最经典的演示,每个框架都将其作为入门集成提供。但邮件不同于其他工具。错误的数据库查询可以回滚,错误的 API 调用会返回错误。而一批糟糕的邮件会降低你公司发送的每一封其他邮件的送达率,且持续数周之久。这里没有可以回滚的事务,因为邮件已经发送到了接收方的邮件服务器,而这些服务器正在记录你域名的声誉历史。

你的 API 曾假设一次只有一个人类用户。并行智能体打破了这一契约。

· 阅读需 14 分钟
Tian Pan
Software Engineer

我认识的一位后端工程师在一个周二的下午盯着一个从未有过波动的 Datadog 图表:其内部日历服务的单用户 429 计数器。投诉的客户并没有改变他们的行为。他们只是开启了助手功能,现在每当用户说“帮我找下周的时间”时,该功能就会针对同一个日历 API 并行启动八个规划线程。速率限制器(Rate Limiter)——每用户每分钟 60 次请求,这个设置非常合理,是多年前针对一个在物理上无法点击得那么快的 UI 编写的——在每次请求的前三秒内就会触发,并悄无声息地破坏了助手一半的响应。

速率限制不是 Bug。契约才是 Bug。那个后端,就像大多数在 2024 年之前编写的内部服务一样,在每一层都植入了一个悄然执行的假设:一个用户意味着一条活动流,其节奏受限于人类的反应时间,拥有一个 cookie 罐、一个 CSRF 令牌和一套在出现问题时可以重新提示的凭据。Agent 一次性粉碎了所有这五个假设,故障表现为一系列看似无关的事件——429 风暴、“最后写入者胜”(last-write-wins)导致的数据损坏、无法取证的审计日志、挂起无头工作线程的重新认证循环——在模式被命名之前,没有人会将它们联系起来。

我一直与平台团队沟通的一个简短总结是:你拥有的每一个后端都与它的调用者有一个未记录的契约,而那个契约是与人类协商达成的。现在 Agent 出现了,要求重新协商。你可以选择在代码审查中主动进行协商,也可以选择在下一次事故期间被动进行。

DLP 应存在于你的 AI 网关中,而非生搬硬套到每个应用里

· 阅读需 12 分钟
Tian Pan
Software Engineer

第一个内部 LLM 网关的构建通常是出于那些枯燥的原因:成本归因,以便财务可以回答“哪个团队花了推理预算”;速率限制,防止某个失控的脚本烧掉月度配额;以及供应商故障转移,确保 OpenAI 的小故障不会导致助手挂掉。数据泄露防护 (DLP) 虽然出现在幻灯片上,但交付时却变成了“每个应用团队在调用模型前应自行脱敏敏感字段”。六个月后,生产环境中有九个应用,三个维护得半吊子的脱敏库(带有微妙差异的正则表达式集),两个完全绕过网关“仅用于测试”的原型,以及一起 Prompt 中包含客户数据的事故——而这本该是由每个人的中间件来防止的,因为并没有人的中间件是规范的出站口。

这不是工具问题,而是架构错误。DLP 是一种出站控制,而出站控制只有在路径强制执行时才有效。当你让应用团队负责脱敏时,你就放弃了让 DLP 发挥作用的特性——即敏感数据只能从一个地方流出,且你可以证明流出了什么。2025 年的 LayerX 安全报告用大多数团队尚未意识到的数据说明了问题的规模:2025 年初,与生成式 AI (GenAI) 相关的 DLP 事故增加了一倍多,目前占 SaaS 流量中所有数据安全事故的 14%,员工平均每天向 GenAI 工具粘贴 6.8 次内容,其中超过一半包含公司信息。影子路径默认在胜出。

Agent 的策略即代码 (Policy-as-Code):OPA、Rego 以及你的工具循环中缺少的决策点

· 阅读需 14 分钟
Tian Pan
Software Engineer

当监管机构第一次要求你证明你的支持代理在 3 月 14 日没有访问某位二级客户的账单记录时,你会发现关于你的鉴权架构的一个令人不悦的事实:系统提示词说“不要访问二级客户的账单”,YAML 工具清单说 tools: [search_orders, refund_order, get_billing],而在两者之间,模型做出了决定。由于不存在决策点,因此没有决策记录。代理是否做了正确的事是无法审计的,只能从发生的日志中推断。

这是智能体工程中没人画在架构图上的部分。如今的工具权限仍然存在于由创建智能体的人编辑的 YAML 文件中,通过描述意图的系统提示词呈现给模型,并由包裹每个工具调用的应用代码强制执行(如果真的执行了的话),例如 if user.tier == "premium" 检查。随着工具目录超过 50 个条目,且条件在租户、数据类别和用户角色之间成倍增加,这种手动构建的网格便不再具备扩展性,而系统提示词也不再是一个可靠的执行面。模型不是你的鉴权层,即使它的表现看起来像是一个鉴权层。

取而代之的是策略即代码(policy-as-code):一个专门的策略引擎 —— OPA 配合 Rego、AWS Cedar 或类似的声明式工具 —— 作为策略决策点(Policy Decision Point)位于每个工具调用之前。引擎在每次调用时只回答一个问题:给定这个主体(principal)、这个工具、这些参数和这个上下文,该操作是否被允许?智能体运行时(agent runtime)从未参与投票。这篇文章将探讨这种架构在实践中的样子,以及它所解决的四个即使是提示词工程也无法解决的问题。

MCP 服务端坟场:当你的智能体依赖停止更新时

· 阅读需 12 分钟
Tian Pan
Software Engineer

你的 Agent 每五分钟调用一次的 MCP 服务,其最后一次 commit 还是在八个月前。它所封装的上游 API 在二月份推出了新的身份验证模型。目前有 47 个未解决的 issue,其中 12 个被标记为安全风险。维护者的 GitHub 账号自十月以来就没有过任何活动。你的 Agent 仍然能够连接,仍然能够接收工具描述,仍然能够执行调用 —— 而在无声无息中,每一次调用都流经一段无人看管的基础设施。

这就是 MCP 被遗弃的现状。不是恶意的卷款跑路(rug pull),也不是被攻破的软件包,仅仅是由于疏忽。有人在 2025 年发布了一个有用的服务,被大家采用后,便转向了其他项目。该服务之所以能继续运行,是因为没有任何因素强行让它崩溃。直到它彻底崩溃 —— 而到那时,你的 Agent 每五分钟跨越一次的信任边界其实早已失效。

大多数团队采用社区 MCP 服务的方式与采用 npm 包的方式如出一辙:运行 install 并阅读 README。这种思维模型在面对 MCP 时失效了。在 MCP 中,依赖是一个动态的信任边界,LLM 在循环中携带凭据,并在生产数据上对其进行调用。

你的 OAuth 令牌在任务执行途中过期:长时运行 Agent 的隐形故障模式

· 阅读需 12 分钟
Tian Pan
Software Engineer

当一个生产环境中的 Agent 首次运行 40 分钟,并在 40 个步骤中的第 27 步遇到 401 错误时,故障复盘的情形几乎总是如出一辙。房间里有人会问为什么令牌没有刷新。另一个人指出刷新逻辑是存在的,但它存在于 HTTP 客户端中,而 Agent 的工具封装层(tool wrapper)从未与之对接。第三个人注意到,即使触发了刷新,Agent 的两个并行工具调用也会尝试在同一瞬间轮换同一个刷新令牌,从而导致会话崩溃。大家纷纷点头。然后,团队在接下来的一周里,为一个假设请求会在 800 毫秒内完成的架构苦哈哈地补齐凭据生命周期管理。

OAuth 的设计初衷是让访问令牌(access token)的寿命长于使用它的请求。长运行 Agent 颠覆了这一假设。现在的请求——实际上是在数分钟或数小时内编排的数十次或数百次工具调用链——比令牌活得更久。整个行业花了十年时间围绕“短请求”假设构建库、代理和刷新流,而这些几乎都无法干净地移植到 Agent 循环中。

你的规划器知道用户无法调用的工具

· 阅读需 10 分钟
Tian Pan
Software Engineer

一个免费层级用户打开你的支持聊天窗口并询问:“你能为订单 #4821 退款吗?”你的智能体(agent)回答:“我无法办理退款 —— 这是管理员才能执行的操作。你可以通过控制面板进行升级,或者我可以为你转接。”拒绝是正确的。退款工具上的 ACL 是正确的。而你刚刚告诉了一个匿名用户:存在一个名为 issue_refund 的工具,它受名为 manager 的角色限制,并且你的平台接受格式为 #NNNN 的订单 ID。

你的规划器(planner)知道用户无法调用的工具。这种不对称性 —— 推理层可见完整目录,而动作层仅能执行部分目录 —— 正是大多数智能体权限控制(agent authorization)悄无声息出错的地方。工具边界处的 ABAC 能拦截未经授权的调用。但它无法拦截已经发生的“能力泄露”,这种泄露往往出现在前一个 token 中,比如规划、拒绝,或是关于变通方案的“热心”建议。

语义缓存是安全隐患,而非性能提升

· 阅读需 14 分钟
Tian Pan
Software Engineer

语义缓存命中是唯一一种能在不到一毫秒的时间内,将错误答案发送给错误用户的 LLM 优化方式。SQL 缓存之所以会返回你或他人的数据行,是因为有人写错了 join —— 这种故障模式属于查询 bug。而语义缓存返回另一个租户的响应,是因为两个 embedding 在 0.03 的余弦距离内落到了一起,这正是系统完全按设计运行的结果。缓存完成了它的工作,问题在于这份工作本身。

大多数团队将语义缓存作为一种成本方案来推行 —— 每个 AI 工程 Slack 频道里都流传着一份“削减 70% 账单”的 PPT —— 并且像对待 Redis TTL 一样审查缓存键(cache key):完全不审。这种审查通常交由性能团队负责。安全团队永远看不到设计文档,因为没有人会为“我们增加了一条更快的路径”提交安全审查。六个月后,某人的合规审计发现,“我无法登录我的账户,我的电子邮件是 [email protected]”和“我无法登录我的账户,我的电子邮件是 [email protected]”在向量化后都处于“我无法登录我的账户”的阈值内,于是缓存愉快地向 Bob 提供了原本为 Jane 生成的响应,其中包含了她账户请求的密码重置链接。

这篇文章将讨论为什么语义缓存值得拥有与 SQL 谓词相同的审查严谨性、如何通过缓存键设计从结构上防止跨用户泄露,以及你需要什么样的审计追踪来区分“缓存命中提供了正确答案”与“缓存命中在亚毫秒级延迟下提供了他人的答案”。

Token 消耗是你的 SOC 尚未监控的安全信号

· 阅读需 12 分钟
Tian Pan
Software Engineer

你技术栈中最灵敏的泄露信号并不在 SIEM 中。它隐藏在财务人员月初打开的一份电子表格里。当攻击者窃取了 LLM API 密钥、利用提示词注入(prompt injection)窃取数据,或者通过被入侵的租户会话查询相邻客户的内存时,痕迹首先会表现为 Token 使用异常——这远在任何 DLP 规则触发、任何身份验证警报响起或任何终端代理察觉到异常之前。财务看到了,而安全部门却没看到。

这种差距并非理论上的。Sysdig 的威胁研究团队在观察到攻击者利用窃取的云凭据产生每日五位数的账单后,创造了“LLMjacking”一词。这一类别现已演变成一个有组织的犯罪产业,出现了每个账号 30 美元的交易市场,且有记录显示某些活动让受害者的损失每天超过 100,000 美元。OWASP 记录了一家初创公司因为密钥泄露,在 48 小时内产生了 200,000 美元的账单。斯坦福大学的一个研究小组由于在 Jupyter notebook 中遗忘了一个 Token,在 12 小时内烧掉了 9,200 美元。所有这些事件的共同点是:在安全团队察觉之前,账单图表就已经在几个小时甚至几天前揭示了真相。

受监管行业的 AI 合规基础设施:大语言模型框架没能提供给你的东西

· 阅读需 12 分钟
Tian Pan
Software Engineer

在受监管行业部署 LLM 的大多数团队都会以惨痛的方式发现他们的合规差距:审计员出现并要求提供特定日期哪个文档影响了某个特定输出的完整日志,而团队却无法给出答案。这并不是因为系统没有记录——它记录了——而是因为 LLM 调用的文本日志并不等同于具有防篡改证据的审计追踪,而 LLM API 的响应主体也不等同于输出溯源(Output Lineage)。

金融、医疗和法律领域不仅仅是消费类软件的“更严格”版本。它们需要通用 LLM 框架从未设计的底层基础设施原语:不可变事件链、单次输出溯源、拒绝处置记录(Refusal Disposition Records)以及结构化可解释性钩子。目前流行的编排框架都没有提供这些开箱即用的功能。本文介绍了这种架构差距,以及如何在不重构整个技术栈的情况下弥补这一差距。

多用户 AI 会话:没人在设计阶段考虑的上下文归属问题

· 阅读需 10 分钟
Tian Pan
Software Engineer

2024 年 8 月,安全研究人员发现 Slack AI 在回答查询时会将公开频道和私密频道的内容同时拉入同一个上下文窗口。公开频道中的攻击者可以精心构造一条消息,当 Slack AI 摄取该消息时,就会将指令注入受害者的会话——由于 Slack AI 不引用来源,由此导致的数据外泄几乎无从追踪。这种攻击甚至可以泄露私信中嵌入的 API 密钥。Slack 在负责任披露后修复了这一问题。

这并不是传统意义上的漏洞。它是将上下文视为无用户访问控制的共享可变资源所带来的后果。而这正是大多数正在构建共享 AI 助手的团队现在都在犯的错误,只是更加悄无声息而已。