AI 时代 .env 文件不再安全——我试图找到替代方案,然后撞上了一堵墙

0 阅读6分钟

引言

用 Claude Code 的时候,我突然意识到一件事:它能读我的 .env

不是恶意的,这是正常的文件系统访问。但这让我开始想一个问题——在 AI Agent 拥有工具调用能力的时代,secrets 的边界是不是已经被打破了?

我花了很长时间试图找到解法,最后推导出了一个让我有点沮丧的结论。这篇文章记录整个思考过程。


一、问题的精确定位

先不要被"AI 读了你的 .env"这个标题吓到,精确化威胁模型很重要。

真实威胁:

Agent 模式下有文件系统访问权限
→ .env 在工作目录内可被读取
→ AI 工具上传代码上下文到服务商服务器
→ .env 内容可能随上下文一起被传走

Cursor 默认对全仓库做 embedding,这个过程是否包含 .env,你无法审计。这不是假设,是默认行为。

被夸大的威胁:

.env 本来就不该进 git——这是基础安全卫生,不是 AI 带来的新问题。本地读取 .env 数据不离本机,威胁相对有限。

所以精确的问题是:Agent 拥有文件系统工具调用能力后,secrets 的边界被打破了。

image.png


二、现有方案为什么不够

方案问题
.gitignore只防 git,不防运行时读取
1Password CLI op run注入环境变量,Agent 仍能读注入后的值
Vault / Doppler云端注入,上下文上传问题不变
权限收紧和 Agent 能力本身冲突

根本矛盾:Agent 要能工作就需要环境上下文,但 secrets 不应该是环境上下文的一部分。


三、三条路径

image.png

想清楚这个矛盾之后,解法只有三个方向:

A. 消灭凭证本身  → 用其他东西替代(支付、身份、证明)
B. 凭证生命周期归零 → 存在但单次/瞬时
C. 凭证无法被提取 → 存在但物理上不可读

A 路径:x402 Payment Protocol

x402 是 Coinbase 推动的 HTTP 402 扩展:

ClientServer: GET /resource
ServerClient: 402 + payment details
ClientServer: GET /resource + payment proof
ServerClient: 200 OK

核心思想:用支付替代凭证。没有需要保管的长期 API key,每次访问即时支付,payment proof 即授权,天然单次有效。

这是"消灭凭证本身"最彻底的实现。但冷启动问题几乎致命——API 厂商没有动机改造计费体系,开发者侧也强依赖 Base L2 + USDC。

B 路径:SPIFFE + UCAN

image.png

SPIFFE(Secure Production Identity Framework For Everyone)本来是给微服务设计的 workload identity 系统。移植到 Agent 场景:

每个 Agent task 获得一个生命周期绑定的身份:
spiffe://domain/agent/{agent-id}/task/{task-id}

SPIRE 颁发短期 X.509 证书(TTL = task 生命周期)
task 结束 → 证书自动过期
没有任何静态 secret

UCAN(User Controlled Authorization Networks)解决 capability 衰减问题:

用户授权 Agent:db:read + db:write
Agent 分配给 SubAgent:db:read(只能缩小)
SubAgent 分配给工具调用:db:read:table/users,maxCalls: 5

两者组合可以构成完整的 AAP(Agent Authorization Protocol)

Layer 0: TEE           硬件信任根
Layer 1: SPIFFE        身份层(Who are you)
Layer 2: AAP           能力层(What can you do)
Layer 3: Transport     mTLS / x402
Layer 4: SDK           框架集成层

技术上最完整,但有个前提:你必须控制 Agent runtime。

C 路径:TEE(可信执行环境)

TEE 是最彻底的 C 路径实现:

Agent 运行在 Intel TDX / AMD SEV-SNPTEE 里
secrets 只在 TEE 内存存在
即使 root 权限也读不到 TEE 内存
即使 context window 被完整泄露,secrets 也不在里面

服务端通过 Remote Attestation 验证:
  硬件真实?固件未篡改?代码度量值匹配?
  → 验证通过,下发 secrets 到 TEE 内
  → secrets 永远不离开 TEE

保护最彻底,但开发硬件门槛高,调试极其困难。


四、把这些放到 Claude Code 场景

这里有一个我一开始忽视的关键差异:

自建 Agent(如 z0):你控制 runtime,AAP 可以完整实现
编程助手(Claude Code/Cursor):你不控制 runtime,AAP 无法强制执行

以 MCP Server 为例——我曾经设想提供一个 get_secret 工具替代直接读 .env:

server.tool("get_secret", async ({ name, taskContext }) => {
  const capability = await aap.evaluate({ requested: name, intent: taskContext })
  if (!capability.allowed) return { error: "capability not granted" }
  return { value: await vault.getEphemeral(name, ttl: capability.ttl) }
})

但问题是:MCP 工具是加法,不是拦截。

你加了 get_secret,但 read_file(".env") 仍然存在。两个通道同时有效,Claude Code 可以绕过你的 MCP 直接读文件。

所以 AAP 在编程助手场景能做到:

✓ 提供标准的 secrets 请求协议
✓ 审计通过 MCP 通道的访问
✗ 无法阻止直接读 .env
✗ 无法审计绕过 MCP 的访问

image.png


五、撞上的那堵墙

推导到最后,我发现了一个更根本的问题。

AAP 要真正闭环,需要的不是协议设计,而是采用方

A 路径(x402):
  需要 API 厂商支持 402 响应
  需要 Agent 平台支持支付
  两边都是大公司,个人无法推动双边采用

B 路径(AAP 替代 API 逻辑):
  需要 API 厂商主动把 key 体系换掉
  等于让他们否定现有基础设施
  动机几乎为零

"无长期凭证"是一个需要供给侧和消费侧同时改变的问题。任何单边方案都只能做到部分保护,无法闭环。

OIDC 的成立不是因为某人设计得好,是因为 Google 和 Microsoft 同时采用了。Agent 时代的凭证标准也会是同样的路径——来自大厂平台内部推行,或监管压力迫使行业标准化。

AWS IAM Roles、Google Workload Identity 已经在各自生态内做到了"无长期凭证"。AI Agent 的版本,大概率也会以同样的方式出现。


六、那这些技术还有价值吗

有,只是场景不同:

SPIFFE / AAP:在你自己控制的 Agent 系统里,这是正确的架构方向
TEE:CI/CD 流水线、云端 Agent 部署,有真实的落地场景
x402:AI × Web3 交叉方向的长期赌注,ERC-8004 已上主网
UCAN:任何需要细粒度 capability 控制的系统

而对于编程助手场景,目前最有效的保护仍然是最朴素的那个:

让 .env 从文件系统彻底消失。 没有文件,就没有读取。


结语

我本来想找到一个漂亮的技术解法。最后发现,这不是一个技术问题,而是一个生态问题。

AI 时代需要新的身份与授权原语。技术路径已经清晰,工程障碍也可以克服。真正的障碍是:谁来推动整个生态同时转向。

这个问题的答案,大概不会来自某个独立开发者。