AIチャットボット、LINE通知、決済連携。最近のWordPressサイトでは、プラグインの設定画面に「APIキーを貼り付ける」作業が当たり前になりました。ところで、そのキーがWordPressのどこに、どんな形で保存されているか、考えたことはあるでしょうか。
結論からお伝えします。WordPress 7.2に向けて「Secrets API」という、APIキーなどの機密情報を暗号化して保存する仕組みが提案されています。現状のWordPressには「秘密情報」という概念がなく、ほとんどのプラグインはAPIキーをデータベースの設定テーブルに平文のまま保存しています。Secrets APIはこの状況を変える可能性がありますが、まだ提案・議論の段階で、内容は今後変わり得ます。
前半はサイト運営者向けに「今どうなっているのか」を、後半はプラグイン開発者向けに提案の設計と今できる実装を解説します。
WordPressのSecrets APIとは?
Secrets APIは、2026年8月25日にMake WordPress Coreで公開された提案で、著者はPHP 8.3/8.4のリリースマネージャーも務めるEric Mann氏です。APIキー・アクセストークン・外部サービスの認証情報といった「秘密情報」を、WordPress本体の機能として暗号化して保存・取得できるようにすることが目的です。
提案の要点を整理すると次のとおりです。
- WordPress 7.2では保存と取得の仕組み(ストレージ層)とWP-CLI対応のみを入れ、管理画面のUIは7.3以降に回す
- 暗号化にはlibsodiumを使い、平文で保存するモードは用意しない
- 既存プラグインが保存している設定値を、明示的に秘密情報へ取り込む移行用の関数を用意する
- 保存先や鍵の管理はドロップインで差し替え可能にし、外部の鍵管理サービスにも対応できるようにする
スケジュール面では、WordPress 7.2はBeta 1が2026年10月20日〜22日、正式リリースが12月8日〜10日の予定です。提案へのフィードバック募集は9月中旬までとされているため、この記事の公開時点では「入るかどうか」も含めて確定していません。最新状況は「WordPress Secrets API」で検索して、Make WordPress Coreの続報を確認してください。
なぜ今、APIキーの保存方法が問題なのか
理由は単純で、WordPressには秘密情報を安全に保存するための公式な仕組みがこれまで存在しなかったからです。プラグイン開発者が使えるのは設定値を保存するOptions APIだけなので、APIキーも他の設定と同じようにwp_optionsテーブルへ平文で保存されてきました。
これは他社のプラグインだけの話ではありません。実際に、当社が無料で公開しているプラグイン「Edel Alt AI」のソースを確認してみました。OpenAIとGeminiのAPIキーは、register_settingで登録したオプションをget_optionで読み出す、ごく一般的な作りです。設定画面の入力欄はパスワード型にしていますが、データベースの中身は平文のままです。150個以上のプラグインを作ってきた中で、これが「標準的な書き方」でした。安全にしたければ暗号化処理を自分で組むしかなく、多くのプラグインはそこまでしていません。

平文のAPIキーはどこから漏れるのか
ここで大切なのは、「仕様」と「リスク」を分けて考えることです。wp_optionsに平文で保存されること自体はこれまでのWordPressでは仕様であり、プラグインの欠陥ではありません。問題は、データベースが人の手に渡る場面すべてがAPIキーの流出経路になる点です。
| キーが人の手に渡る場面 | 起きうること |
|---|---|
| バックアップファイルの流出 | DBダンプの中にAPIキーがそのまま含まれる。古いバックアップを公開領域に置いたままにする事故が典型 |
| ステージング環境・サーバー移転 | 本番のDBを複製した先にも本番のキーがコピーされ、管理が甘い環境から漏れる |
| 制作会社・外注先の交代 | DBを閲覧できた人がキーを知り得る。退職や契約終了後もキーは有効なまま |
| SQLインジェクション等の脆弱性 | 攻撃者がwp_optionsを読み出せた時点で、外部サービスのキーまで持っていかれる |
APIキーが漏れると、そのサービスの利用料金を勝手に使われたり、LINEや決済の連携先から情報を引き出されたりします。当社が対応したマルウェア駆除の現場でも、復旧そのものより「どこまで見られたか」の切り分けに時間がかかることは珍しくありません。
サイト運営者が今できることは?
Secrets APIが導入されるまでの間も、運営者側でできることはあります。難しい設定は不要です。
- 使っていないプラグインのAPIキーは削除する。停止しても設定値はDBに残ることが多いため、削除前に設定画面でキーを空にしておく
- バックアップの保管場所を見直す。公開領域や誰でも入れる共有フォルダに置かない(バックアップの考え方は別記事で解説)
- 担当者の交代やサーバー移転のあとはキーを再発行する。外部サービス側で新しいキーを発行し、古いキーを無効化する
- 管理画面に入れる人を絞り、不正ログイン対策を済ませておく。キーは設定画面から見えることが多く、ログインを守ることがそのままキーを守ることになる
要するに、今のWordPressではAPIキーは「見えるもの」として扱い、見える人と場所を減らすのが現実的な対策です。ここから先は、プラグインを作る側の話になります。
開発者向け:提案されているSecrets APIの設計
提案文書によると、公開される関数は次の4つが中心です。名前は提案時点のもので、コアに入る際に変わる可能性があります。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// 秘密情報の保存・取得・削除(提案時点の関数名) wp_set_secret( 'my-plugin/openai-key', $value ); $secret = wp_get_secret( 'my-plugin/openai-key' ); wp_delete_secret( 'my-plugin/openai-key' ); // 既存オプションを秘密情報として取り込む(自動移行はしない) wp_import_option_as_secret( 'my_plugin_openai_key', 'my-plugin/openai-key' ); // 取得結果は文字列ではなく WP_Secret オブジェクト if ( $secret instanceof WP_Secret ) { $plain = $secret->reveal(); // 平文が必要な瞬間だけ取り出す $fp = $secret->fingerprint(); // 画面表示やログには指紋を使う } |
設計上のポイントを整理します。
- 取得結果はWP_Secretという値オブジェクトで返り、平文はrevealメソッドを呼んだときだけ得られる。ログや画面に誤って平文を出しにくくする狙い
- 保存先の既定はwp_optionsの暗号化ブロブで、autoloadは無効。options.phpの一覧やRESTの設定エンドポイントからは除外される
- 暗号化はlibsodiumを使い、鍵はwp-config.phpで定義する専用の定数を推奨、未定義なら既存のソルトから派生させる案
- 鍵のローテーションは「現在」と「ひとつ前」の2スロットのみ。自動ローテーションは行わず、運用者が明示的に削除する
- 取得時にフィルターフックを設けない。フィルターがあると、すべての秘密情報が平文で通過する「公認の横取りポイント」になってしまうため
- ドロップインのsecrets.phpで、保存先(Vault、AWS Secrets Manager等)や鍵管理(KMS、HSM)を差し替えられる
「プラグイン名/キー名」という名前空間は整理のためのもので、他のプラグインからの読み取りを防ぐアクセス制御ではありません。サイト内で動くPHPコードはすべて信頼される前提は、これまでと変わりません。
Secrets APIを待たずに今できる実装
正式導入は早くても2026年12月で、しかもUIは7.3以降です。当社のようにメジャー更新は公開後しばらく様子を見る方針のサイトなら、実際に使えるのは2027年に入ってからでしょう。今のプラグインで安全性を上げるなら、次の2段階が現実的です。
第一段階は、wp-config.phpの定数や環境変数でキーを渡せるようにすることです。定数があればそちらを優先し、なければ従来どおりオプションを読む形にすると、互換性を保ったままDBにキーを置かない選択肢を提供できます。
|
1 2 3 4 5 6 7 8 9 10 11 |
function my_plugin_get_api_key() { if ( defined( 'MY_PLUGIN_API_KEY' ) && MY_PLUGIN_API_KEY ) { return MY_PLUGIN_API_KEY; // wp-config.php で定義された値を優先 } $env = getenv( 'MY_PLUGIN_API_KEY' ); // 環境変数(コンテナ運用向け) if ( $env ) { return $env; } return get_option( 'my_plugin_api_key', '' ); // 従来の保存先 } |
第二段階は、DBに保存する値そのものをlibsodiumで暗号化することです。鍵はwp-config.phpの定数に置き、DBだけが漏れてもキーは読めない状態にします。PHP 7.4以降ならsodium拡張は標準で、WordPress本体にもフォールバック用のsodium_compatが同梱されています。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
function my_plugin_encrypt( $plain ) { $key = sodium_crypto_generichash( MY_PLUGIN_SECRET_KEY, '', SODIUM_CRYPTO_SECRETBOX_KEYBYTES ); $nonce = random_bytes( SODIUM_CRYPTO_SECRETBOX_NONCEBYTES ); return base64_encode( $nonce . sodium_crypto_secretbox( $plain, $nonce, $key ) ); } function my_plugin_decrypt( $stored ) { $key = sodium_crypto_generichash( MY_PLUGIN_SECRET_KEY, '', SODIUM_CRYPTO_SECRETBOX_KEYBYTES ); $raw = base64_decode( $stored ); $nonce = substr( $raw, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES ); $cipher = substr( $raw, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES ); return sodium_crypto_secretbox_open( $cipher, $nonce, $key ); } |
注意点として、鍵の定数をwp-config.phpに置く以上、wp-config.phpが読まれれば復号できます。それでも「バックアップのDBだけ流出した」「ステージングのDBを見られた」という実際に多い事故には効果があります。提案中のSecrets APIもこの延長線上にあり、鍵の階層化やローテーションを本体側が面倒を見てくれる、と捉えると分かりやすいでしょう。当社のEdel Alt AIも、動向を見ながらまず第一段階の定数対応から進める予定です。今後プラグインを作るなら、キーの読み出し処理を一つの関数にまとめておくと、Secrets APIが入ったときの差し替えが1箇所で済みます。
まだ議論中の論点
提案へのコメントでは、ホスティング事業者や大規模サイトの運用者から重要な指摘が出ています。HSMやAWS Parameter StoreのようにWordPress側から書き込ませない「読み取り専用」の保存先を扱えるようにすべきという要望、プラットフォーム側で暗号化済みの値をさらに暗号化する「二重暗号化」への懸念、鍵の履歴を2世代に限定する設計で足りるのかという疑問などです。この記事の内容は2026年9月上旬時点の提案に基づくもので、正式版では関数名や仕様が変わる可能性があります。WordPress 7.2のBeta公開後に、あらためて確認することをおすすめします。
まとめ:APIキーの扱いは「見えて当然」から「隠して当然」へ
Secrets APIは、WordPressが長年抱えてきた「秘密情報を安全に保存する仕組みがない」という課題への、はじめての本体側の回答です。導入されればプラグイン開発者は暗号化処理を自前で組む必要がなくなり、サイト運営者はバックアップや移転のたびにAPIキーの漏えいを心配しなくて済むようになります。ただし、それは早くても年末以降の話です。今できるのは、運営者なら「キーを見られる人と場所を減らす」こと、開発者なら「キーの読み出しを1箇所にまとめ、定数や暗号化で逃げ道を作る」ことです。
AI連携やLINE連携など、外部サービスのAPIキーを扱うプラグインの開発・改修は、カスタマイズ・プラグイン開発サービスで承っています。制作会社の方で「セキュリティ面まで含めて設計を任せたい」という場合は、顧問エンジニアサービス(制作会社向けパートナー開発支援)もご検討ください。自社サイトのプラグイン設定に不安がある方は、無料相談からお気軽にどうぞ。プラグイン開発を体系的に学びたい方には、Udemyの講座もご用意しています。