
Homebrew 安全与供应链防护指南信任模型、签名元数据与沙箱化设计【免费下载链接】brew The Package Manager for Everywhere项目地址: https://gitcode.com/GitHub_Trending/br/brewHomebrew 从开源生态的各个角落安装软件这使其将软件供应链安全视为核心关切。本文基于 Homebrew 官方安全文档及 brew 仓库源码系统讲解 Homebrew 与 npm/PyPI 在信任模型上的结构性差异、官方 Tap 的逐条人工审查流程、JWS 签名 JSON API、瓶装包bottle来源证明provenance attestation、沙箱化构建与 Cask 差异化信任模型。读者阅读后将理解 Homebrew 如何在上游发布与用户安装之间建立多层人工与自动化防线并能掌握brew trust、HOMEBREW_NO_INSTALL_FROM_API、HOMEBREW_VERIFY_ATTESTATIONS等关键开关的实战含义。其他生态系统中反复发生的供应链攻击模式npm 与 PyPI 生态一直饱受供应链攻击困扰反复出现的攻击模式包括维护者账号劫持Maintainer account takeover攻击者通过钓鱼或撞库获取某个软件包维护者账号然后发布一个恶意版本的可信软件包。2025 年 9 月chalk、debug等周下载量达数十亿的 npm 包的维护者被一封冒充 npm 双重认证重置的钓鱼邮件攻破恶意版本在线约两小时后才被清除期间向受害者投放了改写交易钱包地址的加密货币窃取器。自传播蠕虫Self-propagating wormsShai-Hulud npm 攻击活动利用被攻破的软件包从安装者机器上窃取凭据npm token、GitHub Personal Access Token、云密钥随后用这些凭据自动发布更多投毒软件包在无人干预的情况下蔓延到数百个包。抢注与垃圾蹲守Typosquatting and slopsquatting攻击者发布与热门包名称近似的恶意包或使用 LLM 生成的看似合理的名称让一次手误或过度信任的 AI Agent 安装到恶意软件。安装时执行恶意代码npmpreinstall/postinstall生命周期脚本与 PyPIsetup.py内任意代码从设计上就允许在安装机器上执行发布者控制的代码一次糟糕的发布会立刻在所有安装它的机器上运行。即时、无人审查的发布新版本一经推送便立即面向全世界生效没有人工环节与延迟被攻破的版本能在任何人察觉前触达海量机器。共同点在于这些注册中心面向单方即时发布设计——单个包作者即可发布、安装时执行代码、缺乏独立审查。于是一个被攻破的凭据就立即转化为自动化、全球化的代码执行。Homebrew 在结构上为何不同Homebrew 团队清楚其他包管理器的供应链问题。下面这些设计多数在最近一波供应链攻击之前就已存在是 Homebrew 打包软件的一贯核心原则而非针对某次事件的应急反应。所有变更都经人工审查对 Homebrew 仓库的每一次变更——包括全部官方 Tap如 homebrew/core 与 homebrew/cask——都必须通过 Pull Request 由人类维护者审查合并。上游作者不能直接向官方 Homebrew 仓库发布代码。上游发布与到达 Homebrew 用户之间始终存在人工环节。仓库中的 stale lead maintainer PR 自动批准流程是一个收得很窄的Homebrew/brew特例它只能批准非 fork、非草稿的 lead maintainer PR且需满足近期有维护者审查活动、Copilot 审查通过、CI 通过、打开超过 48 小时仍无人审查、工作日审批窗口、不修改敏感路径等条件。这种放宽在Homebrew/brew可以接受因为大多数用户运行的是 stable 分支且改动到达 stable 用户前仍须由人工执行一次Homebrew/brew发布。维护者是 Homebrew 维护者而非各包上游作者所有软件包维护者都是 Homebrew 维护者而不是各个包的上游作者。信任被集中在一个受过审查、横跨整个仓库审阅变更的团队而不是分散在成千上万各自成为单点故障的独立发布者手中。维护者权限与活跃度会被定期审查每季度须完成最低数量的有意义的贡献低于阈值者会收到私下警告持续不活跃会被移除。维护者还必须为 GitHub 账号开启双重认证2FA、避免使用短信作为第二因子、定期清理不再需要的 Personal Access Token——从而降低导致其他生态被攻破的账号劫持风险。精选的命名空间官方 Tap 中的名称由维护者精选而非先到先得。新的 formula 或 cask 名称必须与包定义本身走同一条被审查的 PR 流程因此抢注、AI 垃圾命名、误导性名称能在进入官方命名空间之前就被拒绝。被移除的 formula/cask 只能通过维护者审查的 PR 恢复且除非有充分理由否则一般不重用旧名陌生人无法单方面认领已移除的名称旧名通过官方仓库、重命名元数据与迁移元数据保持在 Homebrew 控制之下。这使官方命名空间从结构上抵御了开放注册中心的抢注与复活劫持攻击。不信任任何第三方仓库Homebrew 不信任、不推荐、也不自动从任何第三方非 Homebrew 仓库安装。默认只信任官方 Homebrew Tap 与内置命令。非官方 Tap 是可执行代码而非普通元数据——加载它可能以你的用户权限运行 Ruby。因此非官方 Tap 默认需要显式信任而brew trust允许你只信任单个 formula、cask 或命令而不是整个 Tap。具体用法参见 Tap 信任 中的brew trust、brew untrust及Brewfile的trusted: true选项。从源码结构看信任机制由 Library/Homebrew/trust.rb 实现信任记录以 JSON 形式保存在用户配置目录的trust.json中默认~/.homebrew/trust.json并细分为trustedtaps、trustedformulae、trustedcasks、trustedcommands四类键加载 formula/cask/命令时require_trusted_formula!、require_trusted_cask!、require_trusted_command!会按官方 Tap 隐式信任 → 显式信任 → 命令行显式允许的顺序判定未受信任则抛出UntrustedTapError拒绝加载。写入时会校验目录属主与权限拒绝组/世界可写路径trust.rb并以排他锁串行化并发写入防止并行brew bundle丢条目。Homebrew 的 Tap 迁移 只发生在 Homebrew 组织内部formula 或 cask 只会被迁入官方 Tap 或在官方 Tap 之间迁移绝不会迁出到第三方 Tap——因此重命名或移动不会悄悄把用户导向非 Homebrew 仓库。当 GitHub 因所有者/仓库改名而重定向 Tap 时Homebrew 跟随已验证的重定向、把本地 Tap 指向新 canonical remote并使旧 Tap 名对应的信任条目失效而不是默默把信任带过去——这正是 trust.rb 中invalidate_tap_references!的职责。不完全服从上游Homebrew 的首要责任是用户而非上游厂商。Homebrew 通常不会仅仅因为上游要求就弃用deprecate、禁用或移除某个包、或将其重定向到上游 Tap技术性损坏、违反策略或更广泛的项目需求权重更高。这本身就是对上游被攻破的一种防御攻击者即使拿下上游账号也无法借下架/重定向请求把 Homebrew 用户推向恶意替代品。详见 与上游项目协同工作。下载强校验审查元数据中的固定 sha256每个 formula 都把每个下载源固定为一个显式sha256校验和该值保存在 formula 文件中是人工审查变更的一部分。Homebrew 拒绝安装内容不匹配的下载——攻击者事后在服务器上换包会导致校验和失配、安装失败而不是被悄悄攻破。更新校验和需要另一次被审查的 PR且维护者会审查这类改动以确认其没有恶意。JWS 签名的 JSON API 元数据formula 与 cask 本质是 Ruby 包定义而 Ruby 代码不执行就无法安全检查。为兼顾这一点从官方 Tap 默认安装时Homebrew 直接消费预计算的 JSON API 元数据而不是在本地执行 core formula/cask 的 Ruby。默认 API 文件——包括formula.jws.json、cask.jws.json及安装所需的 internal package JSON 文件——均带 JWS 签名并在使用前由 Homebrew 验证。也就是说正常的瓶装包安装消费的是Homebrew 生成的、已签名的结构化包数据而非本地机器上可执行的包定义。签名文件经由独立的 Homebrew/formulae.brew.sh 将其描述为安装 homebrew/core 与 homebrew/cask 时不再走 API而是使用庞大而缓慢的本地仓库检出例如在本地编辑 formula 或走不受支持的源码构建路径时。源码层面的验证细节位于 Library/Homebrew/api.rb凡以.jws.json结尾的端点下载后会先经verify_and_parse_jws再解析api.rb验证失败会明确报告无法确认其完整性。底层verify_jws_signatureapi.rb用 Homebrew 内置的 RSA 公钥jws_public_key_pemapi.rb以 RSA-PSS/SHA512 验签签名不匹配则报 signature mismatch。此外对packages.*.jws.json等文件还维护了基于源文件指纹stat 元数据的 payload 侧车缓存读取缓存前同样会重新验签防止缓存被替换api.rb。瓶装包由 Homebrew 自己构建绝大多数用户安装的是 bottle——Homebrew 在 BrewTestBot 上依据被审查的 formula 自行编译的预编译二进制包——而不是在自己机器上跑上游构建脚本。homebrew/core的 formula 由 Homebrew 自己的沙箱化 CI 从源码构建而非上游上传的预构建物每次构建运行在用完即弃的临时 CI runner上被攻破的构建无法在包之间持久存在也无法外泄长期密钥。产出的二进制同样在 formula 中被记录校验和。即便是不同的打包阶段之间也不会盲目互信彼此的输入输出。测试机器人脚本 Library/Homebrew/test_bot/formulae.rb 会跟踪 bottle JSON 与 tarball 的 SHA256bottle_checksums拒绝缺失、被改动或意外的 bottle 工件Bottle checksum mismatch只有当 bottle JSON 指向formula 及其相关依赖均未变化的 tap revision 时才复用缓存 bottle。部分工件处理步骤以HOMEBREW_DISABLE_LOAD_FORMULA1运行formulae.rb即拉取与校验缓存 bottle 工件时不执行 formula Ruby。从源码构建已经实实在在保护过用户在 2026 年的 Trivy 事件中上游公告指出homebrew/core的 formula 未受影响正是因为它从源码构建、而不是来自被重新打 tag 的发布二进制。Homebrew 只为homebrew/core构建并支持 bottle、为homebrew/cask构建 cask第三方 Tap 属于 不受支持。当你偏离这些受支持路径例如从源码构建或从未受信任的 Tap 安装时Homebrew 会大声警告该配置不受支持。Bottle 来源证明provenance attestations校验和证明下载到的字节与被审查的元数据一致bottle 来源证明则回答另一个问题这些字节是谁、从什么源码构建的。bottle 证明验证逻辑随 Homebrew 发布位于 Library/Homebrew/attestation.rb 与 Library/Homebrew/utils/attestation.rb。当设置了HOMEBREW_VERIFY_ATTESTATIONSenv_config.rb时Homebrew 用 GitHub 的 attestation 工具链在安装前校验homebrew/corebottle 的构建来源。CI 侧则用actions/attest签发 bottle 证明把 bottle 工件绑定到产生它的 GitHub Actions 身份与构建上下文。验证实现值得展开check_attestation调用gh attestation verify并携带GH_TOKEN/GH_HOSTattestation.rb随后在返回的 JSON 结果中按 subjectbottle 文件名精确定位匹配的证明。check_core_attestation是面向 homebrew-core 的专化版本attestation.rb优先验证正式签发找不到时回退到backfill证明并对回填证明设置截止日期BACKFILL_CUTOFF 2024-03-14——即使攻击者攻破了回填签发流程也无法让校验器接受其新的恶意回填签名。验证失败会按指数退避最多重试 5 次。gh太旧、凭据缺失/无效分别对应不同的明确报错如提示brew update brew upgrade gh或gh auth login见 utils/attestation.rb。Homebrew 希望未来以纯 Ruby 实现证明验证、摆脱对gh工具的依赖后将证明验证设为默认。这些证明依托 Sigstore 的公开透明度日志——这是整条流水线中唯一不由 GitHub 托管的交叉校验点能上传 bottle、篡改 GitHub 托管元数据的攻击者仍必须为预期的 Homebrew 构建身份产出一份匹配的、公开记录的来源证明。带交叉校验的分层基础设施Homebrew 的流水线分布在多个组件绝大多数用户从 tagged stable release而非最新 commit运行的Homebrew/brew客户端含 formula/cask 的homebrew-core与homebrew-cask仓库托管于 GitHub Pages、由 formulae.brew.sh 生成并服务的 JSON API以及托管在 GitHub Packages 上的homebrew/corebottles。这些全部由 GitHub 托管而非完全独立的基础设施因此它们并不是完全独立的信任边界但它们会相互交叉校验。例如一个被滥用的、可访问 GitHub Packages 的 token 能上传恶意 bottle但该 bottle 无法匹配 GitHub 托管仓库中记录的sha256校验和而修改该校验和需要经维护者人工审查的 PR。JWS 签名 API 与 bottle 证明进一步增加交叉校验API 元数据必须能通过 Homebrew 的 JWS 签名密钥验证bottle 来源必须能通过预期构建身份与公开透明度日志验证。攻击者必须同时攻破多个组件才能触达用户。由于 GitHub 支撑了其中大部分Homebrew 会尽可能快地启用每项新安全特性强制双重认证、禁止短信作为第二因子、所有 Homebrew 仓库的强制分支保护、不可变的 GitHub Release。Dependabot 更新通过带冷却期的 PR 在 Homebrew 各仓库间推进包管理器自身的自动化不会立刻摄入刚发布的上游依赖。提交入库的 Dependabot 配置 与 新维护者清单 中记录的人员与团队。高权限 PR 事件被谨慎使用pull request checker 是此仓库唯一使用pull_request_target的 workflowcheckout 后拒绝运行、只通过 GitHub API 读取可信的基分支文件大多数 workflow 除非需要 checkout 否则避免actions/checkout使用时也固定版本且通常设置persist-credentials: false。Homebrew 自身的供应链Homebrew 本身是从Homebrew/brew仓库分发的 Ruby 代码。多数用户运行 tagged stable release开发者模式可追踪main最新 commit但这并非默认用户路径。Homebrew 的运行时 Ruby 依赖内置vendored在树中并锁定在 Library/Homebrew/Gemfile.lock而不是在常规brew执行时实时从 RubyGems 解析。依赖更新与其他 Homebrew 变更一样被审查Dependabot 冷却期又给新发布的 gem 增加了延迟。这把包管理器自身的依赖链从攻击面中剔除——这正是其他生态中包管理器插件/运行时库在运行时动态解析的反复弱点。静态分析与静态检查Homebrew 宁多勿缺地开启各类 lint因为机械审查能在人眼发现之前消除整类供应链错误Rubybrew style在可行时优先启用 RuboCop 默认 cops再叠加 Library/Homebrew/rubocops 中 Homebrew 特有的 RuboCops覆盖通用 Ruby 工具无法知道的包管理规则。Shell 与 workflowCI 运行 ShellCheck、actionlint与zizmorzizmor为 GitHub Actions workflow 上传 SARIF 安全结果共享.github的zizmor策略保证 Homebrew 各仓库的 action 固定策略一致。类型brew typecheck使用 SorbetHomebrew 尽可能在所有非测试 Ruby 文件上推行# typed: strict少量在常规运行时支持加载前运行的引导文件用 RBI 类型声明与静态检查覆盖。brew lgtm把类型检查、改动文件风格修复与相关测试合并起来让本地与 CI 反馈使用同一套护栏。安全、负责任地使用 AIAI 辅助变更被视为不可信贡献而不是绕过审查模型的捷径。负责任 AI 使用指南 要求贡献者在请维护者审查前自行审阅、理解、测试并披露 AI 辅助工作使用 Agent 的贡献者被鼓励用沙箱化 git worktree、受限凭据与独立分支来隔离。本文件中的全部防线同样适用于 AI 辅助工作小 diff、人工审查、brew lgtm、CI、Tap 信任与沙箱化包执行。默认不在安装时执行任意代码安装 bottle 是解包受审查的预构建文件从源码构建在沙箱内运行见下运行 formula 的post_install步骤无论来自 bottle 还是源码构建或源码构建前的fetch步骤可能运行上游提供的软件——但同样在沙箱内执行。沙箱化Sandboxing构建、fetch步骤、post_install步骤与测试都在限制文件系统与网络访问的沙箱内运行macOS 沙箱长期以来一直约束 formula 构建Linux 沙箱把同样保护扩展到 Linux 上的 Homebrewenv_config.rb 中还为 Linux 沙箱提供显式开关与网络访问控制变量敏感位置读取的沙箱化阻止构建与测试代码读取主目录中的敏感部分如凭据、SSH 密钥限制恶意构建可外泄的数据范围。环境过滤Homebrew 构建运行在被过滤、净化后的环境中而不是你的完整 shell 环境因此你环境里的密钥与意外配置不会暴露给构建与测试代码。Cask 拥有不同的信任模型formula 与 cask 共享 Homebrew 被审查的包元数据与 JWS 签名 API但不共享同一套工件安全模型homebrew/coreformula 是基于带校验和源码的开源构建配方。Homebrew 在自己受控的临时 CI 中为 formula 构建 bottle 并对结果记校验和因此用户信任的是 Homebrew 被审查的源码→bottle流水线而非上游开发者提供并签名的二进制。Cask 安装的是上游开发者直接提供的预构建应用与安装器。这对原生 macOS 应用与专有软件是必要的但 Homebrew 通常无法从源码复现这些二进制或与独立构建比对。cask 的sha256只能证明下载字节与包元数据一致不能证明字节的产者可信或内部程序可信部分 cask 必须用sha256 :no_check其下载 URL 原地更换内容自更新应用甚至可以完全绕过 Homebrew 自我替换。因此在 macOS 上代码签名、公证notarisation与 Gatekeeper提供了独立校验弥补 cask 较弱的工件模型Developer ID 签名把工件绑定到 Apple 向注册开发者签发的证书并让 macOS 能检测签名后发生的改动Apple 公证服务自动扫描提交软件中的已知恶意内容与签名问题、记录结果并签发日后可被吊销的票据Gatekeeper在受隔离quarantined软件首次打开或安装时校验开发者身份、公证票据与签名。Homebrew 对 Cask 下载施加 macOS 隔离属性让 Gatekeeper 执行这些检查而不是绕过它同时审计官方 macOS cask 中 Gatekeeper 可评估的应用、安装器与其他可执行工件并要求它们在默认 macOS 配置下通过。这些控制并非应用一定无害的保证——公证是自动化恶意软件检查不是源码审查或 App Store 审查——但它们是在上游下载服务器与 Homebrew 元数据之外一个有意义的信任层有可归属的开发者、篡改检测与事后发现恶意软件时的吊销路径。对sha256 :no_check的 cask这往往是对不断变化的下载内容独立于上游服务器的主要校验。正因如此较旧的 cask 可能变得不合规即使有用户运行过早期版本无事故——那段历史既不能认证下一次下载、也不能检测后续篡改、更不能提供可吊销身份保留这种 cask 等于要求用户关闭 Homebrew 赖以校验厂商构建工件的同一道 macOS 保护。Homebrew 于是会 弃用、禁用并最终移除 未通过 Gatekeeper 检查的 cask而不是把安全绕过正常化。移除不等于Homebrew 认定该软件是恶意软件只是上游工件不再达到通过homebrew/cask分发的安全基线当上游提供通过检查的工件后cask 可以重新合格。高风险生态的冷却期Cooldowns对快速供应链攻击有前科的语言生态Homebrew 施加下载冷却期新发布的上游版本不会立即被采纳给社区时间在 Homebrew 用户暴露前检测并报告恶意版本。冷却期已加入BundlerRubyGems livechecknpm 与 pip 默认值PyPI resource 解析bump中的 npm 与 PyPI冷却期被收窄地施加在确实发生过快速供应链攻击的语言生态上而不是对所有包一刀切延迟。全量冷却会拿对供应链风险小而投机性的降低换安全修复发布的真实全局延迟当 OpenSSL 这类零日漏洞正被野外利用时Homebrew 会尽快把修复带给用户而 Homebrew 的设计决定了升级一个包常牵连其他包。纵观历史因快速发布零日修复而受到保护的 Homebrew 用户远多于因 npm 式 token 盗窃或挖矿攻击而暴露的用户。更深层的原因在于与语言包管理器不同Homebrew已经把发布与分发分离——上游发布要经过人工审查、CI 与校验和验证才能触达用户这正是语言生态冷却期试图重建的审查窗口。同时 Homebrew 是滚动发布rolling-release包管理器需要在两件事之间权衡立即交付协调的零日修复如 OpenSSL Heartbleed与为钝化供应链攻击而延迟更新。基于其信任模型、风险画像与所支持生态的广度Homebrew 倾向于在 bump 上游包时施加冷却期而不是在用户升级时再叠一层 Homebrew 专用冷却期——两者都做等于双重冷却对微小收益双重延迟安全修复。安全优先于向后兼容当二者冲突时Homebrew 把安全置于向后兼容之上。弃用/禁用/移除策略 与常规的大版本/小版本发布允许在连续若干版本中先弃用、再禁用、最终彻底移除危险行为或默认值通常在约六到九个月内完成。愿意在该时间尺度上破坏兼容性是 Homebrew 能比必须无限期保留旧行为的生态更快应对新供应链威胁的重要原因。信任模型对比Homebrew vs npm / PyPI维度Homebrewnpm / PyPI谁可以发布变更Homebrew 维护者经 Pull Request任意包所有者直接发布每个发布是否经人工审查始终是无从上游发布到用户的时间经审查风险生态另加冷却期即时下载完整性审查元数据中固定的sha256安装时信任注册中心多数用户安装什么Homebrew CI 构建的 bottle发布者上传的工件安装时是否执行代码少数包有沙箱化的post_installpreinstall/postinstall或setup.py构建与安装隔离macOS/Linux 沙箱、敏感路径与环境过滤默认无信任集中度受审查、强制 2FA 的维护者团队每包所有者的凭据展望这不是已解决的问题Homebrew 也不声称自己免疫。针对用户已经采取的措施中一部分由来已久macOS 沙箱、所有变更经人工审查、环境过滤、全部包维护者均为 Homebrew 维护者一部分较新Linux 沙箱、敏感位置读取沙箱化、风险生态冷却期。Homebrew 会持续监控供应链安全态势并按需采取进一步措施。延伸阅读若想继续深挖本文涉及的机制仓库内可对照的资源包括Tap 信任brew trust/brew untrust/Brewfiletrusted: truebottle 构建与分发机制 与 BrewTestBotCask 编写与工件审查要求弃用、禁用与移除策略负责的 AI 使用指南关键源码JWS 验签 Library/Homebrew/api.rb、信任存储 Library/Homebrew/trust.rb、bottle 证明 Library/Homebrew/attestation.rb、环境变量定义 Library/Homebrew/env_config.rb、打包校验 Library/Homebrew/test_bot/formulae.rb【免费下载链接】brew The Package Manager for Everywhere项目地址: https://gitcode.com/GitHub_Trending/br/brew创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考