クライアントが同じ話の変種を持ってくる回数を数えるのをやめました:「WordPressサイトがハッキングされました。きれいに掃除しました。またハッキングされました。終わりです。」最後のケースは、WooCommerceストアに正当そうに見えるプラグイン更新内に埋め込まれたクレジットカードスキマーが挿入されていた中堅eコマース企業でした。彼らは3週間の間、顧客の支払いデータをリークしていました。これは極端なケースではありません。これはWordPressエコシステムにおける日常的な出来事です。

この記事はWordPressを批判するものではありません。正当な理由で膨大なウェブを支えていました。しかし、2005年にそれをアクセスしやすくした設計が、2025年に自動化された攻撃の磁石になっているのと同じ設計なのです。ハッキングされたか、あるいは自体が攻撃ベクトルであるセキュリティプラグインにお金を使うのに疲れているのであれば、根本的により安全なものへ移行するためのプレイブックはここにあります。

目次

WordPress Hacked? Why Migration to Next.js + Supabase Is Your Best Fix

WordPressセキュリティ問題は設計的なものです

はっきりさせておきましょう:WordPressコアチームは堅牢なセキュリティ作業をしています。WordPressコアは最新に保たれていれば、かなり安全です。しかし、誰もWordPressコアだけを実行していません。平均的なWordPressサイトには20~30個のプラグインがインストールされています。それぞれ、あなたが書かなかった依存関係であり、あなたが知らない誰かによって保守され、あなたのデータベース、ファイルシステム、ユーザーのデータにアクセスできます。

「WordPressセキュリティベストプラクティス」の記事で常に見落とされていることがあります:問題はWordPressサイトの所有者が怠惰であることではありません。問題は、WordPressの設計が、基本的な機能を取得するために、サードパーティから直接サーバーに実行可能なPHPコードをインストールするよう要求することです。それはあなたの家で働くすべての請負業者に永続的にあなたの家の鍵のコピーを与えるのと同じです。

WPScanの脆弱性データベースは2024年にWordPressの7,900以上の新しい脆弱性を追跡しており、プラグインがそのうち約96%を占めています。Sucuriの2024年脅威レポートは、WordPressが彼らがクリーンアップしたすべてのCMS感染症の約95%を占めていることを示唆しています。Patchstackは2024年の重大なWordPress脆弱性の33%が開示時にパッチがなかったと報告しました。

これらはより良いコーディングプラクティスで修正できるバグではありません。それらは設計自体の新興特性です。

2025年における一般的なWordPress攻撃ベクトル

修正について話す前に、あなたが実際に防いでいることをカタログ化しましょう。私は個人的に何十ものコンプロマイズされたWordPressサイトをトリアージしており、攻撃は予測可能なパターンに陥ります。

プラグイン経由のSQLインジェクション

WordPressはよく文書化されたスキーマを持つMySQLデータベースを使用しています。ユーザー入力を受け入れ、データベースに触れるすべてのプラグインは、潜在的なSQLインジェクションポイントです。$wpdb->prepare()関数は存在しますが、それはオプトインです。プラグイン開発者はそれを忘れたり、誤用したり、「シンプルな」クエリのためにスキップしたりします。

18ヶ月間放棄されていたコンタクトフォームプラグインへのインジェクションを追跡したことがありますが、それは200,000以上のサイトにまだインストールされていました。攻撃者はUNIONベースのインジェクションを使用してwp_usersテーブルをダンプし、管理者パスワードハッシュを取得し、弱いものをオフラインでクラックしていました。

-- ログに見られる典型的なWordPress SQLインジェクション
GET /wp-content/plugins/vulnerable-plugin/ajax.php?id=1%20UNION%20SELECT%201,user_login,user_pass,4,5%20FROM%20wp_users--

PHPオブジェクトインジェクションとリモートコード実行

WordPressのserialize()unserialize()の大量の使用は、PHPオブジェクトインジェクションの機会を作成しています。プラグインがユーザー制御データをアンシリアライズする場合(そして多くのプラグインはそうします)、攻撃者はアンシリアライズプロセス中に任意のコードを実行するペイロードを作成できます。

2024年、人気のあるバックアッププラグイン(500万以上のサイトにインストール)の重大なRCE脆弱性により、認証されていない攻撃者が任意のPHPコードを実行できるようになりました。修正は配布されるのに11日かかりました。11日間、そのプラグインを実行しているすべてのサイトが標的でした。

プラグインサプライチェーン攻撃

これが私を最も恐れさせるものです。攻撃者は大規模なインストールベースを持つ放棄されたプラグインを購入し、バックドアを含む「セキュリティ更新」をプッシュし、WordPressの自動更新メカニズムはマルウェアをそのプラグインを実行しているすべてのサイトに配信します。Display Widgets(300,000インストール)とSocial Warfare(70,000インストール)で起こりました、そして逃亡したのはそれらだけです。

wp-login.phpに対するブルートフォース攻撃

すべてのWordPressサイトはデフォルトで/wp-login.php/xmlrpc.phpを公開しています。自動ボットネットは常にこれらのエンドポイントを攻撃します。Wordfenceは2024年にネットワーク全体で月平均30億の悪意のあるリクエストをブロックしていることを報告しました。レート制限とツーファクタ認証を使用しても、あなたはこれらの攻撃を処理するためにサーバーリソースを費やしています。

テーマとプラグイン経由のクロスサイトスクリプティング(XSS)

WordPressの格納型XSSは特に危険です。なぜなら、管理ダッシュボードとパブリックフェーシングサイトが同じセッションコンテキストを共有しているからです。コメント、フォーム送信、または脆弱なプラグイン設定を通じて注入されたXSSペイロードは、完全な管理者アクセスにエスカレートできます。

ヘッドレスアーキテクチャが攻撃カテゴリ全体を排除する理由

ここで物事が興味深くなります。ヘッドレスアーキテクチャは単に攻撃対象領域を削減するだけではなく、それをそれらを可能にする条件を削除することで攻撃カテゴリ全体を排除します。

従来のWordPressセットアップでは、HTMLをレンダリングする同じサーバーが:

  • 20以上のサードパーティプラグインからPHPコードを実行します
  • ユーザー認証を管理します
  • データベースに接続します
  • 管理インターフェースを提供します
  • ファイルアップロードを処理します
  • フォーム送信を処理します

それは単一のアプリケーションにとって多くの責任です。Next.jsとSupabaseを使用したヘッドレスセットアップでは、これらの責任は分離されたサービス全体に分散しています:

  • フロントエンド(Vercel/NetlifyのNext.js): CDNから提供される静的HTML/JS。ほとんどの場合、パブリックインターネットに公開されるサーバー側ランタイムはありません。
  • データベース+認証(Supabase): Row Level Securityを備えた管理Postgres、エンドユーザーに直接公開されることはありません。
  • APIレイヤー: 明示的で最小限のエンドポイントを持つサーバーレス関数。
  • CMS(必要な場合): 独自の分離されたインフラストラクチャで実行するヘッドレスCMS。

PHPを注入する対象はありません。書き込みアクセス権を持つプラグインディレクトリはありません。管理とパブリックサイト間の共有セッションはありません。bots がたたくためのwp-login.phpはありません。

存在しない攻撃対象領域を保護するためにWAFは必要ありません。

WordPress Hacked? Why Migration to Next.js + Supabase Is Your Best Fix - architecture

Next.js + Supabase:セキュリティファーストスタック

このセキュリティの観点から、この特定の組み合わせが機能する理由について具体的に説明しましょう。

Next.js:コードを実行しないフロントエンド

静的生成(SSG)または増分静的再生成(ISR)を使用してNext.jsサイトを構築する場合、配置されるのはCDN上のHTML、CSS、およびJavaScriptファイルです。リアルタイムでリクエストを処理するアプリケーションサーバーはありません。CDNをSQLインジェクションしることはできません。

動的機能の場合、Next.js Server ActionsとRoute Handlersはサーバーレス関数として実行されます。各関数は:

  • 独自の実行コンテキストで分離されています
  • ステートレス(リクエスト間で共有メモリなし)
  • 短期間(コールドスタート、実行、終了)
  • 明示的に定義されています(エンドポイントの自動発見なし)
// Next.js Route Handler -- 明示的、型付き、最小限
import { createClient } from '@/lib/supabase/server'
import { NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'

const ContactSchema = z.object({
  name: z.string().min(1).max(100),
  email: z.string().email(),
  message: z.string().min(10).max(5000),
})

export async function POST(request: NextRequest) {
  const body = await request.json()
  const parsed = ContactSchema.safeParse(body)
  
  if (!parsed.success) {
    return NextResponse.json({ error: 'Invalid input' }, { status: 400 })
  }
  
  const supabase = await createClient()
  const { error } = await supabase
    .from('contact_submissions')
    .insert(parsed.data)
  
  if (error) {
    return NextResponse.json({ error: 'Submission failed' }, { status: 500 })
  }
  
  return NextResponse.json({ success: true })
}

WordPressコンタクトフォームプラグインと比較してください。このプラグインはWordPressのアクションシステムにフックする必要があり、独自のAJAXハンドラーを含め、独自のnonce検証を管理し、独自のSQLクエリを構築します。Next.jsバージョンの方が移動する部分が少なく、Zodを介して検証された入力があり、Supabaseクライアントを通じてパラメータ化されたクエリを持っています。

Supabase:Row Level Securityを備えたPostgres

Supabaseは、1つの重大なセキュリティ機能を備えた管理PostgreSQLデータベースを提供します:Row Level Security(RLS)。あなたのアプリケーションコードがアクセス制御を実装するのを信頼する(WordPressモデル)代わりに、データベースレベルでセキュリティポリシーを定義します。

-- 認証されたユーザーは独自のデータのみを読むことができます
CREATE POLICY "Users can view own profile"
  ON profiles
  FOR SELECT
  USING (auth.uid() = user_id);

-- 公開はcontact_submissionsに挿入できますが、読むことはできません
CREATE POLICY "Anyone can submit contact form"
  ON contact_submissions
  FOR INSERT
  WITH CHECK (true);

CREATE POLICY "Only admins can read submissions"
  ON contact_submissions
  FOR SELECT
  USING (auth.jwt() ->> 'role' = 'admin');

攻撃者がSupabase クエリを恣意的に作成する方法を見つけたとしても(PHPの実行コンテキストなしで既に非常に難しい)、RLSポリシーは、彼らが見るべきではないデータへのアクセスを防ぎます。これは、WordPressがPHPコードで実装された権限システムを持っているため、根本的に提供できない層状防御です。データベースレベルではなく。

Supabaseはまた、メール/パスワード、マジックリンク、OAuthプロバイダー、多要素認証を含む組み込みサポートで認証を処理します。プラグインは必要ありません。サーバーで実行しているサードパーティコードはありません。

攻撃対象領域の比較:WordPressとヘッドレス

これを並べて置きましょう。

攻撃ベクトル WordPress Next.js + Supabase
SQLインジェクション 高リスク -- プラグインは生クエリを構築します ほぼゼロ -- Supabaseクライアント、バックアップとしてのRLSを通じてパラメータ化されたクエリ
PHP/リモートコード実行 高リスク -- プラグインはサーバー側PHPを実行します 該当なし -- PHPランタイムなし
プラグインサプライチェーン 重大なリスク -- 自動更新はマルウェアを配信します 該当なし -- プラグインエコシステムなし
ブルートフォース(ログイン) 常に公開(wp-login.phpxmlrpc.php Supabase Authまたは別個のダッシュボード経由の管理者アクセス、公開ログインエンドポイント不要
XSS(格納型) 高リスク -- 共有管理者/パブリックコンテキスト 低リスク -- Reactはデフォルトで出力をエスケープし、管理とパブリックは別のアプリ
ファイルアップロード悪用 高リスク -- アップロードされたPHPファイルは実行できます 低リスク -- アップロードはオブジェクトストレージ(Supabase Storage/S3)に進み、コードとして実行されることはありません
データベース公開 サーバーが侵害されている場合の直接MySQLアクセス Supabaseのインフラストラクチャの背後にあるデータベース、RLSポリシーが最終警備員として
原点に対するDDoS サーバーはすべてのリクエストを処理する必要があります CDN上の静的資産、原点はめったに当たりません
既知パス列挙 wp-adminwp-contentwp-includesすべてスキャン可能 予測可能なパス、公開された管理ルートなし

移行プレイブック:WordPressからNext.js + Supabaseへ

さて、あなたは説得されています(またはあなたのハッキングされたサイトはあなたを説得しました)。実際にこれを行う方法は次のとおりです。Social Animalでこの移行を十分に実行して、繰り返すことができるプロセスを持っています。

フェーズ1:トリアージとコンテンツ監査(1週目)

コードに触れる前に、実際に何を持っているかを理解する必要があります。

  1. WP-CLIまたはREST APIを使用してすべてのWordPressコンテンツをエクスポートします。XML エクスポートに頼らないでください -- それらはメタフィールドとカスタム投稿タイプを逃します。
  2. プラグインが提供するすべての機能をカタログ化します。スプレッドシートを作成します:プラグイン名、その役割、実際に必要かどうか、それが何に置き換わるか。
  3. SEO保存のためのURL構造をマップします。既存のすべてのURLにはNext.jsでのリダイレクトまたは一致するルートが必要です。
  4. 動的機能を特定します -- フォーム、検索、ユーザーアカウント、eコマース -- APIエンドポイントが必要です。
# REST API経由のWordPressコンテンツエクスポート
curl -s "https://yoursite.com/wp-json/wp/v2/posts?per_page=100&page=1" | jq '.' > posts_page1.json
curl -s "https://yoursite.com/wp-json/wp/v2/pages?per_page=100" | jq '.' > pages.json
curl -s "https://yoursite.com/wp-json/wp/v2/media?per_page=100" | jq '.' > media.json

フェーズ2:Supabaseスキーマとデータ移行(2週目)

コンテンツ監査に基づいてSupabaseデータベーススキーマを設計します。WordPressスキーマを単に複製しないでください -- メタデータテーブルと型化されたデータブロブが肥大化しています。

-- クリーン、目的に応じて設計されたスキーマ
CREATE TABLE posts (
  id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
  title TEXT NOT NULL,
  slug TEXT UNIQUE NOT NULL,
  content TEXT,
  excerpt TEXT,
  featured_image TEXT,
  status TEXT DEFAULT 'draft' CHECK (status IN ('draft', 'published', 'archived')),
  published_at TIMESTAMPTZ,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW(),
  author_id UUID REFERENCES auth.users(id)
);

-- すぐにRLSを有効にします
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;

CREATE POLICY "Published posts are public"
  ON posts FOR SELECT
  USING (status = 'published');

CREATE POLICY "Authors can manage own posts"
  ON posts FOR ALL
  USING (auth.uid() = author_id);

WordPress JSONエクスポートを新しいスキーマに変換し、それらをSupabaseに挿入するミグレーション スクリプト(Node.jsまたはPython)を作成します。

フェーズ3:Next.jsビルド(3~5週目)

Next.jsフロントエンドを構築します。スタックを知っているチームと協力している場合、これは高速に進みます。ヘルプが必要な場合は、弊社のNext.js開発チームがこの移行を十分に行っており、正しいパターンについて強い意見を持っています。

主なアーキテクチャの決定:

  • コンテンツページの静的生成 -- ブログ記事、ランディングページ、ページについて。これらはCDN上のHTMLファイルになります。
  • 動的データのサーバーコンポーネント -- リクエスト時にSupabaseからフェッチ、キャッシング付き。
  • フォーム送信のRoute Handlers -- コンタクトフォーム、ニュースレターサインアップなど。
  • リダイレクトのミドルウェア -- すべての古いWordPress URLを処理します。
// next.config.ts -- WordPress URLリダイレクトを処理
const nextConfig = {
  async redirects() {
    return [
      {
        source: '/category/:slug',
        destination: '/blog/category/:slug',
        permanent: true,
      },
      {
        source: '/:year(\\d{4})/:month(\\d{2})/:slug',
        destination: '/blog/:slug',
        permanent: true,
      },
      // wp-login.php -- bots を410に送信
      {
        source: '/wp-login.php',
        destination: '/gone',
        permanent: true,
      },
      {
        source: '/wp-admin/:path*',
        destination: '/gone',
        permanent: true,
      },
    ]
  },
}

フェーズ4:テストとSEO検証(6週目)

  • Screaming Frogで新しいサイトに対して実行し、すべての古いURLが解決するか、リダイレクトするかを確認します。
  • すべてのページで構造化データ(JSON-LD)が存在することを検証します。
  • すべてのフォームと動的機能をテストします。
  • Lighthouse とCore Web Vitals チェックを実行します -- CDNから配信しているため、ほぼ確実に改善が見られます。
  • Vercel Analyticsまたはお好みのツールを使用して監視を設定します。

フェーズ5:起動とDNSカットオーバー(6~7週目)

Vercel または Netlify にデプロイし、DNS を更新し、監視を設定します。古いWordPressインスタンスをオフラインに保ちますが、30日間アクセス可能なままにしておき、念のため参照する必要がある場合に備えます。

サイトのトラフィックが多い場合、またはeコマース機能が重要な場合は、ヘッドレスCMS統合を検討し、Astroについて コンテンツヘビーサイトでビルドのパフォーマンスが重要である場合、代替フロントエンドについて弊社のチームに相談してください。

移行後のセキュリティ強化

新しいスタックに移動したら、セキュリティチェックリストは次のとおりです:

  1. すべてのテーブルでSupabase RLSを有効にします。 例外はありません。テーブルにポリシーがない場合、それはアクセス不可(良いデフォルト)または広く開いている(悪い)です。
  2. すべてのシークレットに環境変数を使用します。 VercelとNetlifyの両方がこれをよく処理します。APIキーをコミットしないでください。
  3. Supabaseデータベースバックアップを設定します。 ポイントインタイムリカバリはProプラン(月額$25)で利用できます。
  4. Next.jsミドルウェアでContent Security Policyヘッダーを構成します。
  5. Vercelの DDoS保護を有効にします(すべてのプランに含まれます)。
  6. アップタイム監視を設定します -- Better Uptimeを使用していますが、ChecklyとVercelの組み込み監視も機能します。
  7. 四半期ごとにSupabase RLSポリシーを監査します。 Supabaseの SQL エディタを使用して、異なるユーザーコンテキストでポリシーをテストします。
// middleware.ts -- セキュリティヘッダー
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
  const response = NextResponse.next()
  
  response.headers.set('X-Frame-Options', 'DENY')
  response.headers.set('X-Content-Type-Options', 'nosniff')
  response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin')
  response.headers.set(
    'Content-Security-Policy',
    "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';"
  )
  response.headers.set(
    'Permissions-Policy',
    'camera=(), microphone=(), geolocation=()'
  )
  
  return response
}

WordPressセキュリティの実コスト対移行

お金について話しましょう。実は、これが決定を左右するものです。

コストカテゴリ WordPress(年間) Next.js + Supabase(年間)
ホスティング $300-1,200(管理WP) $0-240(Vercel Pro)
セキュリティプラグイン(Wordfence/Sucuri) $200-500 $0(不要)
SSL/CDN $0-200 $0(含まれる)
マルウェアクリーンアップ(ハッキングされている場合) インシデントごと$500-2,500 N/A
セキュリティパッチ上の開発者時間 $2,000-5,000 $500-1,000
データベース(Supabase) ホスティングに含まれる $0-300(フリーティアからPro)
合計 $3,000-9,400 $500-1,540

そして、ダウンタイム、失われた顧客信頼、データ侵害が報告可能である場合の潜在的な規制ペナルティのコストを考慮する前に。単一のGDPR報告可能な違反は、法的および規制遵守のオーバーヘッドで数万ドルのコストがかかる可能性があります。

移行自体は通常、サイトの複雑さに応じて$10,000-40,000の費用がかかります。ほとんどの企業では、それは削減されたセキュリティ支出だけで1~2年以内に元が取れます -- そして、あなたはより高速で保守しやすいサイトも得られます。料金ページで移行プロジェクトの詳細を確認してください。

よくある質問

WordPressは本当にそれほど不安全なのか、それともこれは誇張されているのか? WordPressコアは上手く保守されています。問題は、実際には誰もコアだけを実行しないということです。プラグインエコシステムは脆弱性の96%が存在する場所であり、プラグインなしで有用なWordPressサイトを実行することはできません。誇張ではありません -- Sucuriは2024年だけで60,000以上のWordPressサイトからマルウェアをクリーンアップしました。アーキテクチャはあなたがサーバーでサードパーティのPHPコードを信頼する必要があり、その信頼は常に悪用されています。

移行の代わりに、より良いセキュリティプラグインを使用することはできませんか? セキュリティプラグイン自体はサーバー上で実行されるPHPコードであり、深刻なシステムアクセス権を持っています。WordfenceとSucuriはよく保守されていますが、設計上の問題に対するバンドエイドです。また、サーバー負荷を追加でき、他のプラグインと競合でき、長年で独自の脆弱性を持っていました。複雑な問題を解決するための複雑さを追加しています。

WordPressからNext.jsへのマイグレーションは通常どのくらい時間がかかりますか? 標準的なビジネスサイト(10~50ページ、ブログ、コンタクトフォーム)の場合、通常5~7週間でマイグレーションを完了します。WooCommerceを使用したeコマースサイトはより複雑で、製品カタログサイズとカスタム機能に応じて8~14週間かかることができます。より単純なサイトがある場合は、弊社にお気軽にお問い合わせください。より具体的なタイムラインを提供できます。

WordPressから移行する際にSEOランキングは失われますか? 正しく行えば、そうではありません。重要なステップは:すべてのURL構造を保存するか、適切な301リダイレクトを設定する、構造化データマークアップを保持する、コンテンツをそのままにする、そして更新されたサイトマップをGoogle Search Consoleに送信することです。ほとんどの移行クライアントはCore Web Vitalsスコアが向上するため、2~3ヶ月以内にランキングの改善が見られます。

コンテンツ編集についてはどうですか?WordPressはユーザーフレンドリーです。 これは正当な懸念です。選択肢があります:Supabaseとカスタム管理ダッシュボード、またはSanity、Contentful、Payload CMSなどのヘッドレスCMS。WordPressに似た視覚的編集体験をコンテンツエディターに提供します。弊社はヘッドレスCMS統合を定期的に処理でき、チームのニーズに合った適切なフィットをお勧めできます。

Supabaseは本番環境のセキュリティとして十分ですか? Supabaseはaws インフラストラクチャで実行されており、SOC 2 Type II準拠です。基盤となるデータベースはPostgreSQLであり、セキュリティの実績が強いです。Row Level Securityポリシーはデータベースレベルでアクセス制御を実装しており、実際にはPHPベースの権限システムであるWordPressより安全です。Supabaseはまた、ポイントインタイムリカバリ、暗号化された接続、有料プランのネットワーク制限も提供しています。

WordPressサイトがハッキングされていて、すぐにヘルプが必要な場合はどうすればいいですか? まず、サイトをすぐにオフラインにして、さらなる損害とデータリークを停止します。次に、法医学的証拠を保存します(データベースダンプ、アクセスログ、ファイルシステムスナップショット)。第三に、単にそれをクリーンアップして戻さないでください -- あなたは数週間以内に再び感染する可能性があります。インシデントを移行の触媒として使用します。弊社に連絡してください。直近のトリアージと移行計画の両方で支援できます。

すべてを一度に移行する必要がありますか、それともゆっくり移行できますか? 段階的な移行は可能ですが、複雑さが増します。Next.jsを一時的にフロントエンドとして実行でき、WordPressをヘッドレスCMSバックエンドとして保持できます。その後、WordPressを完全に廃止します。ただし、これはWordPressが実行中で、移行中もセキュリティ保守が必要なことを意味します。ほとんどのサイトでは、クリーンなカットオーバーの方が高速で安価であり、セキュリティリスクをより早く排除します。