Qiita のセキュリティチェックリスト 10 を AI とのペアプロで一気にツブした記録

WordPress セキュリティの定番チェックリスト記事を読んで「よし全部やろう」と思ったら、AI(Claude Code)とペアプロして 1 日で全項目達成できた。AI 時代の個人ブログ運用の実例として、何をどう判断して進めたかの記録を残す。

ベースにした記事は Qiita の「WordPressセキュリティ 最低限やることチェックリスト10(今日できるコピペ設定つき)」。記事自体に各項目のコピペ設定が載っているので、それを自分の環境に合わせて反映していく流れ。

対象環境

  • Web サーバ: nginx 1.30 + php-fpm(Apache ではない点が重要)
  • WordPress: 7
  • インフラ: AWS EC2 + Amazon Linux 2023
  • デプロイ: GitHub Actions が code/rsync --delete で本番にミラーする repo 駆動型

Qiita 記事は Apache 向けと nginx 向けの両方を載せてくれているので、自分の構成を把握してから着手するのが必須。最初に AI に「うちは nginx だよ」と伝えたら、その後の提案がすべて nginx 向けに最適化された。

始める前にやった現状把握

いきなり手を動かす前に、AI に既存設定を全部読ませた。「読み取り専用で現状を把握する」フェーズ。

  • 本番 nginx 設定(/etc/nginx/conf.d/*.confincludes.d/*
  • ローカル Docker 環境の構成
  • GitHub Actions の workflow(.github/workflows/deploy-wordpress.yml
  • wp-config.php の構造(vlucas/phpdotenv で env から読む独自実装あり)
  • 既存の WordPress プラグイン一覧

これをやらないと、AI が「ベストプラクティスはこう」と言ってきても、自分の環境では既にやってある or 別の方法でやっている、というズレが起きる。

把握した結果、チェックリスト 10 項目のうち約半分はすでに対応済みだった。具体的には IP 制限、server_tokens offautoindex off、wp-config 拒否、xmlrpc の IP 制限など、過去に自分で設定したものが含まれていた。

全 10 項目のスコアと判断

#項目着手前結果
1コア/プラグイン更新・不要削除一部完了
2ログイン保護(2FA 等)強い既存対策あり、2FA なし完了
3ファイル編集無効化完了(自作編集ページとの両立)
4wp-config 保護・uploads PHP 禁止ほぼ完了
5HTTPS 強制 + セキュリティヘッダHTTPS のみ完了
6XML-RPC/REST 制限XML-RPC のみ完了
7バージョン/ユーザー名露出バージョンのみ完了
8権限最小化管理者 1 名完了
9バックアップ完備確認のみ
10監視一部完了

スコアの良し悪しじゃなく「現状を可視化したら次にやることが見えた」のが大きい。

印象に残ったハマりどころ・判断

項目 3 を「機能を削らずに」達成した話

DISALLOW_FILE_EDIT=true を入れると、管理画面のテーマファイルエディター・プラグインエディターが消える。最初は「IP 制限と 2FA で守ってるから、エディターは便利なので残したい」と判断して、項目 3 はスキップ予定だった。

そこで AI が指摘してくれたのが「DISALLOW_FILE_EDIT は汎用エディターだけ封鎖するもので、自作の管理画面ページが file_put_contents する処理は止めない」という事実。

自分のサイトには Amazon PA-API がエラーの時に手動で ASIN.json を編集する運用があった。これを「自作の専用管理画面ページ」として実装すれば、汎用エディターは封鎖しつつ運用は維持できる。

実装したのは以下のような専用ページ:

  • add_submenu_page で「Amazon商品」メニューに「ASIN 編集」を追加
  • amazon_products ディレクトリの JSON ファイル一覧をドロップダウンで選択
  • テキストエリアで読み込み・編集・保存
  • 権限チェック(current_user_can('manage_options')
  • nonce で CSRF 対策
  • パストラバーサル防止(basename() で固定)
  • 保存前に json_decode で構文検証

これで DISALLOW_FILE_EDIT=true を入れても運用が壊れない状態を作れた。「機能を削るか、セキュリティを諦めるか」の二者択一を回避できたのが今回の最大の収穫。

項目 5 のセキュリティヘッダで CSP を入れなかった理由

Content-Security-Policy は最強の防御策の 1 つだけど、自分のサイトは AdSense・Amazon・ValueCommerce・A8.net など複数のアフィリエイトウィジェットを使っている。CSP を厳格に設定するとほぼ確実にウィジェットが動かなくなる。

判断としては「収益を生むコードが動かなくなるリスク > CSP で得られる追加防御」と評価して見送り。代わりに:

  • Strict-Transport-Security: max-age=31536000
  • X-Content-Type-Options: nosniff
  • X-Frame-Options: SAMEORIGIN
  • Referrer-Policy: strict-origin-when-cross-origin
  • Permissions-Policy: geolocation=(), camera=(), microphone=()

の 5 つを入れた。Mozilla Observatory のスコアは B/70。CSP なしならこれが現実的な最大値。

項目 7 でプラグイン側 readme.html を nginx でブロック

WordPress 本体の <meta name="generator">remove_action('wp_head', 'wp_generator') で消せるが、AdSense Site Kit や AIOSEO などのプラグインが独自に generator メタを出してくるケースがある。AIOSEO に至っては view ファイル直書きでフィルタも用意されていないので、プラグイン本体を fork しない限り消せない。

これをコード側で頑張るのは諦めて、別経路の「プラグインのバージョン露出」を塞ぐ方を選んだ。具体的には:

location ~* ^/wp-content/(plugins|themes)/.+/(readme|license|changelog)\.(txt|md)$ {
    deny all;
    return 403;
}

プラグインの readme.txt には Stable tag: x.y.z が書かれているので、これが公開されているとそのままバージョンが漏れる。リバースエンジニアリングしたい攻撃者が最初に見る場所。

generator メタを残しても readme.txt を塞げば、バージョン特定の難易度は実質同じになる。塞ぎやすい所から塞ぐ判断。

項目 9 のバックアップは「設定したつもりで止まっていないか」の確認が大事

最初の調査で crontab -l が空だったので「バックアップ未設定」と判定しかけたが、深掘りすると WP-DBManager プラグインが wp-cron 駆動で動いていて、毎日 S3 にアップしていた。

つまり「システム cron じゃなく wp-cron で動く仕組み」を見落としていた。

wp cron event list --fields=hook --allow-root --path=/var/www/blog
# → dbmanager_cron_backup などが出てくる

「設定したつもり」と「実際に動いている」は別物。バックアップは取れていることを実物で確認するのがセキュリティ運用の基本。今回は S3 バケットに当日のバックアップが上がっていることを確認できて安心した。

項目 2 で 2FA は WordPress 公式の Two Factor プラグインを選択

主要な 2FA プラグインを WordPress.org API で評価データ含めて比較した。

プラグイン評価作者特徴
Two Factor96/100WordPress.org 公式フィーチャープラグイン、軽量、広告なし
WP 2FA94/100Melapressウィザード形式、SMS は有料
Wordfence Login Security78/100WordfenceWordfence の 2FA 部分のみ
miniOrange 2FA90/100miniOrange多機能、無料版は1方式制限

公式 = 開発が突然止まらない」という長期視点で Two Factor を選択。実際の運用では認証アプリ(TOTP)+ リカバリコードの構成にした。

設定中に「Two-Factor Options を変更するには Revalidate now が必要」という UI の罠があったが、これは「設定変更時に再度本人確認を強制する」セキュリティ機能。むしろ正しい挙動。

やってみての所感

AI 時代のセキュリティ強化の進め方

セキュリティ強化は「項目をリストアップする → 1 個ずつ調べて実装する → 検証する」というプロセスを繰り返す作業。これが AI とのペアプロにめちゃくちゃ向いている。

  • AI が「うちの環境ではこうなる」と現状を読みながら提案してくれる
  • 「これは入れない方がいい」も明示的に判断材料を出してくれる
  • コピペで貼った設定が壊れていないかすぐ検証できる
  • ハマっても「過去にこの問題でこう解決した人がいる」を即引いてくれる

1 人でやると半日かかる調査が 5 分で終わる。

ただし AI に任せきりにできないところ

  • 「機能を削るか」の判断は人間がする。今回の ASIN.json 編集運用みたいに、業務固有の制約は AI が察知しきれない
  • AWS Console や DNS など外部 UI 操作は人間が手を動かす必要がある(IAM 権限の都合)
  • 「これはやらない」判断の根拠を人間が言語化することで、AI が後続作業をズレた方向に進めるのを防げる

一発でやり切れた理由

  • 朝から夜まで 1 日まるごと使えた
  • AI(Claude Code)の長文脈モデルでセッションが途切れなかった
  • 1 項目ごとに「ローカルで検証 → 本番に反映 → 動作確認」を厳守した

「翌日に持ち越し」にすると、絶対に翌日には情熱が冷めているか他の用事が入る。勢いがある時に全部やるのがセキュリティ強化の正解だと思う。

結果

Mozilla ObservatoryGrade B / Score 70
残存リスクDMARC(後日対応で解決)
動作影響なし
所要時間約 1 日

「全部終わった」ことで、これ以降は書く方に集中できる精神状態になれた。これが実は一番大きい収穫かもしれない。

Home » 未分類 » Qiita のセキュリティチェックリスト 10 を AI とのペアプロで一気にツブした記録