使用此清单来判断哪些值属于运行时环境、哪些由系统生成到数据库中,以及哪些由插件存储。每个小节都说明了轮换会如何影响正在运行的站点。
在 Node.js 上,请将运行时机密放入托管平台的机密管理器,使其在进程启动时进入 process.env。对于 Worker,请使用 wrangler secret put。不要将机密值放入 astro.config.mjs、wrangler.jsonc 或 import.meta.env;Vite 可能会将构建时的值嵌入服务器包中。
概览
| 机密 | 来源 | 存储位置 | 密钥丢失的影响 |
|---|---|---|---|
EMDASH_ENCRYPTION_KEY | 运维人员(emdash secrets generate) | 仅限环境变量 / Worker 机密 | 在恢复匹配的密钥之前,无法读取已加密的插件设置 |
| 预览机密 | 自动生成(可用环境变量覆盖) | options 表(emdash:preview_secret) | 已发出的预览链接失效;新链接不受影响 |
| IP 盐 | 自动生成(可用环境变量覆盖) | options 表(emdash:ip_salt) | 过去的评论速率限制连续性被重置 |
| 会话与 API 令牌 | 每个会话/令牌各自生成 | 会话存储 / 数据库(仅哈希) | 无影响——明文从不存储 |
| OAuth 提供方凭证 | 你(Google、GitHub 或 Microsoft Entra 控制台) | 环境变量 | 通过该提供方登录会停止,直到替换 |
| Turnstile 机密 | 你(Cloudflare 仪表盘) | 环境变量 | 评论 CAPTCHA 验证失败 |
| S3 凭证 | 你(存储提供方) | 运行时环境 | 媒体上传/下载失败,直到替换 |
| 插件机密 | 你(管理端设置界面) | 加密的数据库设置 | 恢复匹配的加密密钥,或重新输入该值 |
| CLI 凭证 | emdash login 设备流程 | ~/.config/emdash/auth.json(权限 0600) | 再次运行设备流程 |
| 注册表 CLI 凭证 | emdash-plugin atproto OAuth | ~/.emdash/oauth/、~/.emdash/credentials.json(权限 0600) | 重新登录;身份保存在你的 PDS 上 |
加密密钥
EMDASH_ENCRYPTION_KEY 用于加密以 type: "secret" 声明的插件设置。EmDash 使用 AES-GCM,并以插件 ID 和设置键作为认证数据。格式错误的值会产生面向运维人员的启动消息,需要加密插件设置的操作会以关闭方式失败。与之无关的站点请求仍可正常工作。
以下命令会生成格式正确的值。若你的部署使用此变量,请将其存放在运行时环境中,或作为 Worker 机密存放。
npx emdash secrets generate
# emdash_enc_v1_<43 base64url chars>
# Cloudflare:
wrangler secret put EMDASH_ENCRYPTION_KEY
格式为 emdash_enc_v1_ 后跟 32 个随机字节,以无填充的 base64url 表示。该值由运维人员提供,不会存储在数据库中。请将其保存在机密管理器中,并另存一份用于恢复的备份。
要轮换密钥,请在前面添加新值,并在逗号后保留旧值:
EMDASH_ENCRYPTION_KEY=emdash_enc_v1_<new-key>,emdash_enc_v1_<old-key>
EmDash 使用第一个密钥加密新值和重新保存的值,并根据已存储的 kid 指纹选择较旧的密钥来读取。在移除旧密钥之前,请重新保存每个插件机密,然后在仅包含新密钥的部署中验证这些集成。EmDash 目前不会报告哪些密钥 ID 仍在使用,因此请为你重新保存的凭证维护一份清单,并在每个集成都通过验证之前不要移除旧密钥。
生成的站点机密
有两个机密会在首次使用时自动生成,并持久化在 options 表中,因此在请求、部署和隔离环境之间保持稳定。生成是原子性的——并发的冷启动会收敛到同一个值。
预览机密
用于对预览 URL 签名(HMAC)。存储为 emdash:preview_secret;32 个随机字节,base64url 编码。
- 覆盖: 如果需要在多个进程间使用同一机密,或出于审计原因想要固定它,请设置
EMDASH_PREVIEW_SECRET(旧版别名:PREVIEW_SECRET)。环境变量始终优先于存储的值。 - 轮换: 删除
emdash:preview_secret行(或更改环境变量)并重新部署。影响:先前签发的预览链接不再通过验证。其他一切不受影响——下一次预览请求时会生成新的机密(或从环境变量读取)。 - 如果丢失: 没有任何无法恢复的内容。预览链接按设计是短期有效的。
有关预览 URL 如何构建和验证,请参阅预览指南。
IP 盐
为评论者 IP 地址的 SHA-256 哈希(评论上的 ip_hash)加盐,用于评论速率限制。存储为 emdash:ip_salt。它因站点而异,因此各 EmDash 安装之间的哈希无法相互关联。
- 覆盖: 设置
EMDASH_IP_SALT。为保持向后兼容,也会参考EMDASH_AUTH_SECRET/AUTH_SECRET——过去由它们派生盐的安装会保持哈希稳定。 - 轮换: 更改环境变量或删除
emdash:ip_salt行,然后重新部署。影响:新的评论提交会哈希为不同的值,因此所有人的速率限制计数都会重新开始。现有评论及其已存储的哈希不受影响。 - 如果丢失: 不会丢失数据。只是速率限制的连续性被重置。
会话与 API 令牌
- 会话使用 Astro 的会话存储(Cloudflare 上为 Workers KV,Node 上为文件系统)。未配置存储的适配器(如 Vercel)需要在
astro.config.mjs中配置会话驱动;若没有,登录会失败,并给出说明需要会话驱动的错误。Cookie 携带的是不透明的会话 ID;没有需要管理的签名机密。退出登录可结束会话,或清空会话存储(例如 KV 命名空间)以强制所有人重新登录。 - API 令牌(前缀为
ec_pat_、ec_oat_、ec_ort_)是不透明的 256 位随机值;只存储其 SHA-256 哈希。明文仅在创建时显示一次。请通过在管理端撤销并重新创建来轮换。 - 邀请、魔法链接和恢复令牌用途单一,以 SHA-256 哈希的形式存储在
auth_tokens中,并有时间限制(邀请 7 天,魔法链接 15 分钟)。
无需主动备份或轮换任何内容:数据库泄露只会暴露哈希,且每个令牌都可以在管理端撤销或重新签发。
用户提供的服务凭证
外部服务的凭证从环境变量读取,绝不会写入数据库。请在提供方处轮换,更新变量,然后重新部署。
| 服务 | 变量 |
|---|---|
| Google 登录 | EMDASH_OAUTH_GOOGLE_CLIENT_ID、EMDASH_OAUTH_GOOGLE_CLIENT_SECRET(或无前缀别名) |
| GitHub 登录 | EMDASH_OAUTH_GITHUB_CLIENT_ID、EMDASH_OAUTH_GITHUB_CLIENT_SECRET(或无前缀别名) |
| Microsoft 登录 | EMDASH_OAUTH_MICROSOFT_CLIENT_ID、EMDASH_OAUTH_MICROSOFT_CLIENT_SECRET、EMDASH_OAUTH_MICROSOFT_TENANT_ID(或无前缀别名) |
| Turnstile(评论) | EMDASH_TURNSTILE_SECRET_KEY(或 TURNSTILE_SECRET_KEY) |
| 兼容 S3 的存储 | S3_ACCESS_KEY_ID、S3_SECRET_ACCESS_KEY、S3_ENDPOINT、S3_BUCKET、S3_REGION |
在 Cloudflare 上,请使用 wrangler secret put 设置这些变量;本地开发时,请将它们放入 .env。Wrangler 读取 .dev.vars 或 .env 其中之一,而不是同时读取两者,且存在 .dev.vars 时以其为准。通过绑定使用 R2 不需要访问密钥变量,因为绑定会授予运行时访问权限。参见媒体存储。
在 Node 上,EmDash 会在请求到达时从服务器的进程环境读取 Turnstile 密钥,而 astro dev 和构建后的服务器都不会将 .env 加载到其中。请在主机环境中设置该密钥,在运行 astro dev 的 shell 中导出它,或使用 node --env-file=.env ./dist/server/entry.mjs 启动构建后的服务器。
插件机密
插件以 type: "secret" 声明的设置(电子邮件提供商的 API 密钥、表单验证码等)在管理端界面中输入,并加密存储在 options 表的 plugin:<id>:settings:<key> 下。即使匹配的加密密钥不可用,管理端也只会收到该机密是否已设置,因此管理员可以替换无法读取的凭证。插件代码在其隔离的运行时内通过 ctx.settings 读取明文。存储在已声明的设置 schema 之外的值,包括任意插件 KV 和状态条目,不使用此加密路径。
- 凭证轮换: 在提供方处轮换凭证,并将新值粘贴到插件的设置页面。保存时会写入新的加密信封。
- 明文迁移: 由早期 EmDash 版本存储的机密仍可读取。请重新保存每个值以对其加密。
- 如果加密密钥丢失: 从单独的密钥备份中恢复匹配的
EMDASH_ENCRYPTION_KEY。如果没有任何副本,请在提供方处替换每个受影响的凭证,并在配置新的加密密钥后输入替换值。
CLI 凭证
emdash CLI 将站点令牌存储在 ~/.config/emdash/auth.json(遵循 XDG_CONFIG_HOME)中,并设置为仅所有者可访问的权限(0600)。emdash login 通过 OAuth 设备流程向你的 EmDash 实例认证,并以实例 URL 为键存储令牌。emdash logout 会将其删除;每次调用时,--token 或 EMDASH_TOKEN 会覆盖已存储的令牌。
丢失该文件无妨:再次运行 emdash login 即可。
插件注册表 CLI 凭证
独立的 emdash-plugin CLI(包 @emdash-cms/plugin-cli)面向实验性的 AT Protocol 注册表。在那里发布与你的 AT Protocol 身份(你的发布者 DID)绑定——站点本身不持有任何发布凭证,安装时会根据归属于该 DID 的发布记录中的校验和来验证产物。
- 它通过 atproto OAuth 认证。OAuth 会话/状态数据位于
~/.emdash/oauth/,发布者身份(DID、handle、PDS)缓存在~/.emdash/credentials.json中;两者都以仅所有者可访问的权限写入。 - 在 CI 中,通过
EMDASH_PUBLISHER_DID、EMDASH_PUBLISHER_HANDLE和EMDASH_PUBLISHER_PDS提供身份;EMDASH_REGISTRY_URL会覆盖注册表主机。在 CI 中自动执行publish仍需要运行器上~/.emdash/oauth/中的 OAuth 会话文件——仅靠环境变量并不携带 OAuth 会话。 - 轮换或撤销发布访问权限发生在你的 AT Protocol 账户处(例如应用密码),而不是 EmDash 中。参见 Atmosphere auth。
轮换速查
| 我想要…… | 这样做 |
|---|---|
| 轮换插件设置的加密 | 在前面添加新密钥,重新保存插件机密,然后移除旧密钥 |
| 使所有预览链接失效 | 删除 emdash:preview_secret 行(或更改环境变量覆盖),重新部署 |
| 重置评论速率限制的哈希 | 更改 EMDASH_IP_SALT(或删除 emdash:ip_salt 选项行),重新部署 |
| 撤销已泄露的 API 令牌 | Admin → Users → API tokens → 撤销,然后创建替代令牌 |
| 终止所有会话 | 清空会话存储(Workers KV 命名空间 / 会话目录) |
| 替换提供方凭证 | 在提供方处轮换,更新环境变量,重新部署 |
| 替换插件 API 密钥 | 在提供方处轮换,在插件的管理端设置中重新输入 |