摘要:2025 年秋季,npm(由 GitHub 运营)在认证与令牌管理上引入了一系列重大安全改进:禁用并将撤销“经典(classic)令牌”,细粒度(granular)令牌引入较短生命周期与强制 2FA/可选绕过 CI 的选项,并鼓励使用基于 OIDC 的“可信发布(Trusted Publishing)”。这些改动目标清晰:缩短失窃令牌的攻击窗口、减少长寿命凭证、并把 CI 发布推向临时性、可溯源的身份体系。本文从风险模型、迁移路径、CI 实战示例与运维落地检查表角度,给出可立刻落地的建议与代码片段,帮助团队在 2025-12-09(npm 公告的经典令牌撤销日)前平稳过渡。
一、到底发生了什么?
- 经典(Classic)令牌将被禁用并撤销:npm 网站已禁止创建新的经典令牌,并计划在 2025-12-09 撤销现有经典令牌——这意味着仍在使用经典令牌的自动化发布/脚本在那日之后会失败,必须迁移。
- 细粒度(Granular)访问令牌行为收紧:
- 新建写权限细粒度令牌默认到期为 7 天(早先为 30 天),最长允许 90 天(此前可无限期)。
- 写权限令牌现在与 2FA 关联(并提供“CI 绕过”选项供自动化使用)。
- 鼓励并推广 Trusted Publishing(OIDC):通过 OIDC 能在 CI 中使用临时、作业限定的凭证进行发布,彻底减少长期静态凭证的使用。npm 的 Trusted Publishing 功能已可用并被推荐作为首选路径。
- 2FA 策略演进:TOTP(基于时间的一次性密码)新配置被禁用,未来方向是 WebAuthn / passkeys(更强、更防钓鱼)。
二、为什么这些改动重要?(威胁模型与安全价值)
- 长期凭证是供应链攻击的高价值目标。 一旦暴露,攻击者能长期滥用发布权限注入恶意代码,影响下游使用者。缩短令牌寿命、移除宽权令牌能显著降低攻击窗口与损害面。
- 临时凭证 + OIDC = 更可控的溯源与审计。 OIDC 将发布权限绑定到 CI 作业上下文(仓库、分支、run id),减少凭证分发和人为错误。
- 更强 2FA(WebAuthn)抵抗钓鱼与共享密码场景,提升个人账号的整体安全性。
三、对你(团队/仓库/组织)的直接影响(快速自查)
- 你是否在 CI/CD(GitHub Actions、GitLab CI、CircleCI、Azure)里直接使用了 classic token?(例如把它存到 secrets 并用于
npm publish)——若有,必须尽快替换。 - 你是否依赖长期有效的 granular token(或没有自动轮换)?需要检查并计划更短周期的轮换或切换到 OIDC。
- 你的发布流程是否必须在无网络交互的本地机器上由开发者手动触发?若是,考虑是否需要对开发者凭证与 2FA 做更严格管理(并逐步迁移到 WebAuthn)。
四、迁移路径与实施步骤(优先级与示例)
路径 A(首选):改用 Trusted Publishing(OIDC) —— 推荐用于 CI 自动化
优点:无长期令牌、临时凭证、自动溯源、简化审计。适合 GitHub Actions、部分支持的 CI(npm 已支持 GH Actions、GitLab 等)。
GitHub Actions 示例(必备点):确保 workflow 有 id-token: write 权限,并在 npm 上配置受信任发布者(针对仓库/组织)。
# .github/workflows/publish.yml
name: Publish to npm via OIDC
on:
push:
tags:
- 'v*.*.*'
permissions:
contents: read
id-token: write # 必需:允许生成 OIDC id-token
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- name: Authenticate to npm using OIDC
run: |
# 使用 npm 的 trusted publishing 无需在 secrets 中存储令牌
# 该步骤将使用 GitHub Actions 提供的 OIDC id-token 完成临时认证
npm publish
# 如果需要,可以使用 npm@11.5+ 的内置支持进行更细粒度控制
(注:在 npm 管理页面上要为对应包/组织配置“Trusted publisher”,绑定仓库/分支等。)。
路径 B:使用 Granular Access Tokens(短期/兼容性方案)
当 OIDC 尚无法覆盖某些工作流(比如某些第三方 CI、特殊自动化),使用细粒度令牌并做到最小权限 + 自动轮换。
关键实践:
- 令牌权限仅限发布需要的 scope(包或组织),不要给账户级别或不必要权限。
- 设置合理到期(如 7/14/30 天,尽量不要放到 90 天上限),并自动化轮换。
- CI secrets 中存储的令牌要配合 CI 的根路径权限限制与审计。
生成并在 CI 中使用细粒度令牌(示例):
# 生成令牌(在 npm 网站或支持的 CLI 中)
# 以下为示意命令,具体以 npm docs 为准
# 注释:下面为伪命令,实际执行请参考 npm docs
npm token create --read-write --cidr=0.0.0.0/0 --expires=14d
# 将输出的 token 存入 GitHub Secrets:NPM_PUBLISH_TOKEN
在 GitHub Actions 中使用:
- name: Publish with granular token
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }} # npm CLI 会识别该 env 变量用于 publish
run: npm publish
(注意:新建写权限细粒度令牌的默认行为现在会包含更短的生命周期和 2FA 要求,可在创建流程中配置“允许 CI 绕过 2FA”的选项)。
路径 C:局部/临时过渡策略
- 开发者本地发布:在本地发布时仍可使用开发者账号,但要启用强 2FA(优先 WebAuthn),并限制使用场景。
- 多仓库多人共享发布凭证:尽量避免。若不可避免,使用短期 granular token 并设置严格的审计与轮换。
五、如何把“自动轮换”做到位(示例脚本)
下面给出一个简单的轮换策略示例(使用 npm CLI / API)。注意:具体命令与 API 路径请以 npm 官方文档为准;此处为示范流程与注释(中文注释)。
#!/usr/bin/env bash
# 脚本用途:示例性地展示如何周期性创建新 granular token 替换 CI secrets
# 注:请在安全的机器/流程中运行;此脚本示例假设你已有权限及必要的 npm CLI 版本。
# 1. 使用现有微粒令牌或本地登录来创建新 token(以下为示意)
# 实际:npm token create 命令或 npm REST API
new_token=$(npm token create --json --read-write --expires=14d | jq -r '.token')
# 2. 将生成的 token 推送到 CI 的 secrets(以 GitHub 为例,使用 gh cli)
# 需要 gh cli 已认证并有足够权限
echo "更新 GitHub Secrets(示例)..."
printf "%s" "$new_token" | gh secret set NPM_PUBLISH_TOKEN --body -
# 3. (可选)撤销旧的 token(确保新 token 生效后再撤销旧 token)
# old_token_id=...
# npm token revoke $old_token_id
六、运维检查表(可打印、分配负责人)
- 在组织/个人 npm 账户上列出所有 classic token 与 granular token,标注使用场景与到期日。
- 如果使用 classic token:优先转换到 OIDC,若短期不可行,创建 granular token 并限制 scope。
- 检查所有 CI workflow 是否有
id-token: write权限并且能与 npm 的 Trusted Publisher 配置对接(若采用 OIDC)。 - 为关键发布流程制定令牌轮换策略(自动化脚本 + 告警),并在 token 创建时使用最短可接受生命周期(默认 7 天)。
- 审计 npm 组织与包的成员权限,移除不必要的发布权限(最小权限原则)。
- 升级并鼓励开发者使用 WebAuthn / passkeys,替代 TOTP 长期依赖。
七、常见迁移与陷阱
- 陷阱:直接把 granular token 手动分发给很多仓库 —— 后果是管理成本高、轮换复杂。优先考虑 OIDC 或集中化的短期 token 发放与自动更新。
- 陷阱:忽略 CLI 与 npm 版本兼容性 —— 部分 npm CLI 版本对 OIDC/新策略支持有限,需升级到被推荐的 npm 版本(参考 npm 文档中的最低版本要求)。
- 陷阱:忘记更新本地开发者文档 —— 发布流程变更需要在团队内同步,避免“只有某个人知道如何手动发布”的单点风险。
- 经验:先在非关键包或私有包上做一次 OIDC 流程演练,确认 token 流程与审计链,然后逐步切换到生产级包。
八、决策建议(给不同规模团队的路线图)
- 小团队 / 个人维护者:优先采用 granular token + 最小权限 + 自动轮换;若使用 GitHub Actions 且包较重要,强烈建议迁移到 OIDC Trusted Publishing。
- 中大型团队 / 企业:尽快把所有 CI 发布迁移到 Trusted Publishing(OIDC),并建立集中化的 token 管理与轮换系统(用于不支持 OIDC 的特例)。并强制启用更强 2FA(WebAuthn)与审计。
- 开源组织:发布权限策略要更保守,避免给单一维护者过多权限,尽量采用 CI 触发的 OIDC 发布来去中心化发布权限。
九、结语 — 安全是工程,也是组织能力
npm 的这次改动不是为了给开发者制造麻烦,而是把生态系统推向更安全、可审计、以临时凭证为核心的发布模型。短期看会带来一定的迁移成本,但从长期供应链安全、审计与应急响应能力来看,这些改动是必要且有益的。把发布凭证的不可变性改造成可追踪、短期的凭证,需要工程上的投入、自动化工具链与组织流程的配合——这正是把“安全”工程化的体现。
附录:关键参考
- npm 改动公告 / changelog(细粒度 token 与 classic token 停用说明)。(The GitHub Blog)
- npm Trusted Publishing(OIDC)文档与配置指南。(docs.npmjs.com)
- npm 关于 access tokens 的官方文档(scope、限制与上限说明)。(docs.npmjs.com)
- 社区讨论与时间线(关于经典令牌撤销日期的更新)。(GitHub)
文章评论