大多数允许用户部署代码的平台处理机密的方式都是一样的:把它们放在环境变量中,然后祝大家好运。我正在构建一个用于发布和重混可运行网页应用的小型社交平台(Vibecodr),当人们能够部署服务器端代码时,第一个请求是可以预见的:“让我用我的秘密调用一个外部API。”
环境变量的方法一直让我感到困扰。一旦你将明文交给用户代码,它就会存在于内存中,可能被记录、意外地在响应中回显,或者通过某个你没有审计的依赖悄悄泄露。当出现问题时,祝你好运找出秘密泄露的地方。
因此,我尝试设计一个更严格的约束:明文秘密绝不应存在于用户的工作内存中。无论是作为环境变量、帮助函数的返回值,还是在日志中。理想情况下,甚至连毫秒都不应存在。
以下是它的工作原理。
**调度层**
一个由平台控制的代理位于用户代码和外部世界之间。用户代码不会直接获取秘密。相反,它调用一个像fetch-with-secret的包装器,并传递:
- 使用哪个秘密(密钥名称,而不是值)
- 出站请求的详细信息
- 在哪里注入秘密(头部、查询参数、正文)
调度层负责敏感的工作:在服务器端解密秘密,验证出站URL(仅限HTTPS、可选的每个秘密的白名单、基础设施主机阻止、基于DNS的SSRF检查),以严格的超时发起上游请求,手动处理重定向并在每个跳转时重新验证,从文本响应中删除秘密,并强制执行配额。
**不透明令牌模式**
显式的fetch-with-secret API是安全的,但有时会显得笨拙——开发者喜欢正常地组合请求。因此还有第二种模式:用户代码请求一个短期的不透明令牌,用于给定的秘密密钥(仍然从未看到实际值)。如果该令牌出现在fetch的URL、头部或正文中,包装器会拦截它并通过调度进行真实的注入。令牌是每个请求的、短期的,只有在同一请求上下文中铸造的情况下才会解析。其他情况则会失败并关闭。
**密钥管理**
我对加密秘密负载格式进行版本控制,以便未来的迁移和密钥轮换不会产生歧义。支持多个候选解密密钥同时存在——可以在不破坏现有加密值的情况下进行轮换,并保持跨组件共享的加密逻辑,以避免实现之间的漂移。
**我实际遇到的陷阱**
重定向是一个安全陷阱。大多数HTTP客户端默认会跟随重定向,这可能会悄悄地将“允许的主机”转变为重定向到内部IP。每个跳转都必须手动处理重定向并重新验证,这是不可谈判的。如果我发布了天真的版本,这将会给我带来严重的问题。
删除机密比听起来要复杂得多。秘密可能以原始、URL编码或base64编码的形式出现在响应中。你希望实现深度防御,而不是让每个响应变得一团糟。短秘密会导致误报的删除——我选择了删除并发出警告,而不是跳过它们,因为“哎呀,泄露了”比“哎呀,损坏了”要糟糕得多。
你需要对所有内容设定严格的上限。请求正文大小、扫描的响应正文大小、超时上限。没有它们,每个“有用的功能”都可能成为拒绝服务攻击的向量。
**我希望得到的反馈**
我发布这个是因为我希望得到那些构建过类似系统或发现其漏洞的人的批评:
- 你在安全处理二进制响应时,注入秘密的请求有什么首选策略?
- 你是否在边缘/无服务器环境中见过与基于DNS的SSRF验证相关的失败模式?
- 对于删除机密与如果可能包含秘密就完全阻止响应,你有什么强烈的看法?
如果你想在真实产品上下文中看到这个项目,可以访问 https://Vibecodr.space——但我在这里是为了获取关于架构和威胁模型的反馈,而不是进行发布。
返回首页
一周热榜
我花了几天时间实验OpenClaw,并调整了代理使用的SOUL.md。我发现这些工具是多么强大!我得到了许多不同个性和特征的角色。我甚至创建了“熊”,我的日本老师,直到我提交每周的作业,他才会按照我的要求行事!
因此,我决定创建一个SOUL.md,供大家复制、分叉并提交新的版本。
所有内容都是开源的(MIT许可证)。
GitHub: [https://github.com/thedaviddias/souls-directory]
在线网站: [https://souls.directory]
我非常希望能收到关于格式本身的反馈——我仍在不断迭代,确定哪些字段是必需的,哪些是可选的。