ℹ️ このページについて

このページはプラグイン開発者向けの技術的なセキュリティ実装ガイドです。

一般ユーザー向けのWordPressセキュリティ対策は以下をご覧ください:

⚠️ プラグインの主な脆弱性

WordPressプラグインで特に注意が必要な脆弱性を理解しましょう。多くのハッキング被害はプラグインの脆弱性を突いたものです。

脆弱性概要主な対策
SQLインジェクション悪意あるSQL文をクエリに注入してDBを不正操作$wpdb->prepare()
XSS(クロスサイトスクリプティング)悪意あるスクリプトをページに埋め込み訪問者を攻撃エスケープ関数群
CSRF(クロスサイトリクエストフォージェリ)ログイン済みユーザーに意図しない操作をさせるnonce検証
ファイルインクルード外部ファイルをPHPに読み込ませてコードを実行ABSPATHチェック
権限昇格本来できない操作を一般ユーザーが実行できてしまうcurrent_user_can()

🛡️ SQLインジェクション対策

データベースへのクエリは必ず $wpdb->prepare() を使います。絶対に文字列を直接結合しないでください。

// ❌ 危険:$_GETの値を直接SQL文字列に結合(攻撃者に ' OR 1=1 -- を入れられると全件取得される) $results = $wpdb->get_results( "SELECT * FROM {$wpdb->posts} WHERE post_title = '" . $_GET['title'] . "'" ); // ✅ 安全:prepare()でプレースホルダーを使う $title = sanitize_text_field( $_GET['title'] ); $results = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->posts} WHERE post_title = %s AND post_status = %s", $title, 'publish' ) ); // プレースホルダーの種類 // %s 文字列(自動的にクォートされる) // %d 整数 // %f 浮動小数点数 // %i 識別子(テーブル名・カラム名 - WordPress 6.2以降)

🛡️ XSS対策 — コンテキスト別エスケープ関数

出力先の「コンテキスト」によって使う関数が変わります。間違った関数を使うと XSS を防げません。

// ① HTMLの本文テキスト → esc_html() echo '<p>' . esc_html( $user_input ) . '</p>'; // ② HTML属性値 → esc_attr() echo '<input value="' . esc_attr( $value ) . '">'; // ③ href / src などのURL → esc_url() echo '<a href="' . esc_url( $url ) . '">'; // ④ JavaScript内の値 → esc_js() echo '<script>var name = "' . esc_js( $name ) . '";</script>'; // ⑤ テキストエリア → esc_textarea() echo '<textarea>' . esc_textarea( $text ) . '</textarea>'; // ⑥ CSSのプロパティ値 → sanitize_hex_color() + esc_attr() $color = sanitize_hex_color( $_POST['color'] ); echo 'style="color:' . esc_attr( $color ) . '"'; // ⑦ 翻訳テキストを出力 → esc_html_e() または esc_html__() esc_html_e( 'Settings saved.', 'my-plugin' ); // echo + translate + escape $text = esc_html__( 'Settings saved.', 'my-plugin' ); // translate + escape(返り値)

🎯 覚え方: 「遅延エスケープ」原則

データは「保存する直前にサニタイズ」、「出力する直前にエスケープ」します。早めにエスケープしてしまうと、エスケープ済みのデータがさらにエスケープされる「二重エスケープ」が起きます。

🛡️ 入力値のサニタイズ関数一覧

フォームから受け取ったデータを保存・処理する前に清浄化します。

関数用途動作
sanitize_text_field()一行テキストHTMLタグ・余分な空白・改行を除去
sanitize_textarea_field()複数行テキストHTMLタグ除去、改行は保持
sanitize_email()メールアドレスメール形式の文字のみ残す
sanitize_url()URLURLとして無効な文字を除去
absint()正の整数絶対値に変換(常に0以上)
sanitize_hex_color()カラーコード#RRGGBB 形式のみ許可
sanitize_file_name()ファイル名安全な文字のみ残す
wp_kses_post()投稿内のHTMLWordPress許可リストのタグのみ残す
wp_kses()カスタム許可HTML許可タグ・属性を自分で定義

💡 バリデーション・サニタイズ・エスケープの違い

バリデーション:値が正しい形式か確認する(不正ならエラー返す)
サニタイズ:不正な部分を除去・変換して保存可能な状態にする(保存前)
エスケープ:出力先のコンテキストに合わせて特殊文字を変換する(出力時)
3つすべてを組み合わせるのが最も安全です。

🔒 nonce によるCSRF対策

nonce(Number Used Once)はフォーム送信が正規ユーザーによる操作かを検証するワンタイムトークンです。

// ─── フォーム出力側 ─── function mfp_render_settings_form() { echo '<form method="post">'; wp_nonce_field( 'mfp_save_settings', 'mfp_nonce' ); // hidden input を自動生成 echo '<input type="text" name="mfp_title" value="' . esc_attr( get_option('mfp_title') ) . '">'; submit_button( '保存' ); echo '</form>'; } // ─── フォーム受信側 ─── function mfp_handle_settings_form() { if ( ! isset( $_POST['mfp_nonce'] ) ) return; // ① nonce を検証(改ざん・CSRF を防ぐ) if ( ! wp_verify_nonce( $_POST['mfp_nonce'], 'mfp_save_settings' ) ) { wp_die( 'セキュリティチェックに失敗しました。' ); } // ② 権限を確認 if ( ! current_user_can( 'manage_options' ) ) { wp_die( 'この操作を行う権限がありません。' ); } // ③ サニタイズして保存 $title = sanitize_text_field( $_POST['mfp_title'] ?? '' ); update_option( 'mfp_title', $title ); add_settings_error( 'mfp_settings', 'saved', '設定を保存しました。', 'updated' ); } add_action( 'admin_init', 'mfp_handle_settings_form' );

⚠️ セキュリティの3点セット(必ず全部実装する)

  1. nonce の検証 — CSRF攻撃(第三者サイトからの偽リクエスト)を防ぐ
  2. 権限の確認 — 権限のないユーザーの操作を防ぐ
  3. 入力値のサニタイズ — 不正なデータの保存を防ぐ

🔐 その他のセキュリティ対策

直接アクセスを防ぐ

すべてのPHPファイルの先頭に記述します。WordPressを経由せず直接ファイルにアクセスされることを防ぎます。

<?php if ( ! defined( 'ABSPATH' ) ) { exit; }

パスワード・APIキーの安全な管理

APIキーなどの機密情報は update_option() でDBに保存します。ファイルに直書きすると、GitやSVNで誤って公開してしまう危険があります。

パスワードのハッシュ化

独自のパスワード機能を作る場合は必ずハッシュ化します。

$hash = wp_hash_password( $plain ); $ok = wp_check_password( $input, $hash );

✏️ 演習:安全なフォーム処理を実装しよう

📝 課題

  1. 名前・メール・本文を受け取るフォームを管理画面に作成する
  2. nonce検証・権限チェック・サニタイズを3点セットで実装する
  3. フィールドに応じたサニタイズ関数を使い分ける
  4. 出力時に esc_html() と esc_attr() を使い分ける
  5. (発展)$wpdb->prepare() を使ってカスタムテーブルに安全に保存する

✅ この章のチェックリスト

  • $wpdb->prepare()でSQLインジェクションを防げた
  • コンテキストに合ったエスケープ関数を7種類使い分けられた
  • サニタイズ関数で入力値を清浄化できた
  • nonce・権限チェック・サニタイズの3点セットを実装できた
  • 全PHPファイルの先頭にABSPATHチェックを追加した
  • 「遅延エスケープ」の原則を理解した

🔗 関連ページ・次のステップ

📚 一般ユーザー向けセキュリティ対策

プラグイン開発だけでなく、サイト運用全般のセキュリティ対策も重要です:

📘 前提知識

🚀 あわせて学ぶ

📚 補足