WordPress 7.2 引入 Secrets API,用于把 API Key 、 OAuth 客户端密钥等凭据以加密方式存储,并保留”上一版本”以便平滑轮换。它解决了长期困扰插件作者的一个问题:敏感凭据要么明文存进 options 表,要么自己造轮子加密。现在核心提供了一套统一的、经过安全评审的方案。
它解决了什么
过去插件要存密钥,常见做法是塞进 wp_options,或者塞进 wp-config.php 的常量。前者明文风险高,后者不好版本化与轮换。 Secrets API 把凭据用 libsodium(XChaCha20-Poly1305) 加密后存入 options 表,根密钥再由 WP_SECRETS_KEY 加密保存;写入新值时会把当前值移到 WP_Secret_Version::PREVIOUS,轮换期间可回退。
核心函数
插件用下面这组函数读写密钥:
wp_set_secret( 'plugin-slug/secret-name', $value ):写入;wp_get_secret( 'plugin-slug/secret-name' ):读取,返回WP_Secret实例、null或WP_Error;wp_delete_secret():删除;wp_list_secrets():只返回名称与元数据,绝不返回值;wp_retire_secret_version():轮换完成后删掉上一版本;wp_import_option_as_secret():把已有 option 复制成 secret(标记需轮换);wp_set_network_secret()等*_network_secret():多站点网络级存储。
WP_Secret 在被打印、记录日志、 JSON 编码或 var_dump() 时只显示 [secret:plugin-slug/secret-name] 占位;序列化或克隆它会抛异常。只有 reveal() 返回值,且不要在别处缓存该对象。命名规则与读取语义
密钥名形如 plugin-slug/secret-name,只能包含小写字母、数字、连字符与下划线;带斜杠的前缀防止插件互相覆盖,但它不是访问控制——站点上任何能运行的代码都能读任意密钥。不带斜杠也能用,但会触发 _doing_it_wrong()。注意斜杠只能在中间出现一次,且不能以下划线或连字符开头或结尾。
读取时要区分三种情况:wp_get_secret() 仅在”从未存储”时返回 null;若密钥存在但当前因密钥或数据库不可用而无法读取,返回 WP_Error。两者别混:出错时去重新索要凭据,可能覆盖掉一个仍然有效的密钥。
步骤一:写入前先用
wp_is_secrets_api_available() 判断环境是否可用(缺 WP_SECRETS_KEY 、 drop-in 加载失败、或密钥无法解密根密钥都会返回 false)。步骤二:用
wp_set_secret( 'my-plugin/api-key', $api_key ) 写入;用 is_wp_error() 判断失败,失败时保留旧存储,不要落到 option 。步骤三:读取时用
wp_get_secret(),对 WP_Secret 调 reveal() 取值;对 null 才向用户索取,对 WP_Error 则保持现状。步骤四:若主机以只读方式提供密钥,先
wp_secrets_provider_is_writable() 判断,不可写就显示提示而非输入框。步骤五:写完在 Site Health 的安全项确认 Secrets API key source 健康,再上线。
配置 WP_SECRETS_KEY
没有可用的 WP_SECRETS_KEY 时 API 什么都不存,任何读写都返回 secret_key_unavailable 错误。新安装会在安装阶段和盐值一起自动写入;已有站点需手动在 wp-config.php 的盐值下方添加:
define( 'WP_SECRETS_KEY', '…一段 base64 编码的 32 字节随机密钥…' );
生成方式:php -r 'echo base64_encode( random_bytes( 32 ) ), "\n";'。 Site Health 会给出可直接复制的行。注意:密钥不像盐值——一旦已存密钥后再改或删它,所有密钥都会读不出来,直到找回原值。
主机可托管密钥(drop-in)
主机可通过 wp-content/secrets.php 替换 API 的某一部分:WP_Secrets_Keyring(把根密钥放进 KMS 或 HSM)、WP_Secrets_Store(把加密记录存到 options 表之外)、WP_Secrets_Provider(整库交给外部密钥管理器)。 drop-in 里用 #[\SensitiveParameter] 标注接收密钥或值的参数,并在加载失败时由 Site Health 报出——API 不会回退到默认实现,避免”配置错误的后端”伪装成”空存储”。
同批 7.2 的其它安全与开发者改动,可看 WordPress 输入校验的保守策略 与 WordPress 7.2 Beta 4。
常见问题
options 明文存储、任何人可读;transients 用于缓存且同样不加密。 Secrets API 专为敏感凭据设计:加密落库、保留上一版本便于轮换、读写语义明确区分未存与存在但不可读,且对象不会在日志里泄漏明文。
只要已存过密钥,改掉或删除 WP_SECRETS_KEY 会让所有密钥暂时不可解密。需要先把它加回原值,或按官方替换密钥环、存储、提供方流程用 WP_SECRETS_KEY_PREVIOUS 平滑迁移。
能。站点级与网络级函数各自独立,不会互相回退;一次网络级轮换即可覆盖整个多站点网络。
Beta 阶段若没有 WP_SECRETS_KEY,密钥是用旧的回退密钥加密的,升级后 Site Health 会提示无法解密。按官方步骤:生成新密钥并临时用 WP_SECRETS_KEY_PREVIOUS 指向旧值,重加密根密钥后再移除旧行即可,无需重写任何已存密钥。
「延伸:Beta
自 Beta 1 起:WP_SECRETS_KEY 改为必填(不再用 LOGGED_IN_KEY 与 SALT 派生);keyring 、 store 、 provider 由接口改为抽象类(drop-in 需把 implements 改成 extends 并在 7.2 同时部署,否则每次请求都致命错误);另有多处细节修复,如 secrets.php 进入 Plugins 与 Site Health 列表、拒绝尾部换行命名、数据库读取失败不再覆盖根密钥等。










评论 (0)