年別アーカイブ 2026年5月27日

Vercel Sandboxの永続化機能が正式版に、環境構築の手間を大幅削減

Vercel Sandboxの永続化機能が正式版に、環境構築の手間を大幅削減

Vercelが提供するクラウド開発環境「Vercel Sandbox」において、filesystemの状態をセッション間で自動保存する永続化機能が正式版(GA)となった。2026年5月26日の発表だ。開発者はこれまで、Sandboxを再起動するたびに依存パッケージのインストールやファイル配置をやり直す必要があったが、今回のアップデートでその手間が大幅に削減される。

永続化はデフォルトで有効化されており、スナップショットの取得や状態管理を手動で行う必要はない。Sandboxに一意の名前を付与すれば、その名前をキーとして環境を再開できる仕組みだ。セッションの起動と停止はVercel側で自動的に処理されるため、開発者はワークフローを中断されることなく作業を継続できる。

Sandbox永続化が解決する課題

Sandbox永続化が解決する課題

クラウドベースの開発環境において、セッション終了後の状態消失は長年の課題だった。従来のVercel Sandboxでは、セッションが終了するたびにfilesystem上の全データが破棄されていた。このため、毎回の起動時に再度依存関係のインストールや環境設定を行う必要があり、開発開始までの待ち時間が大きな非効率を生んでいた。

永続化機能は、この問題に対する直接的な解決策だ。Sandboxのfilesystem状態が自動的にスナップショットとして保存され、次回セッション開始時に自動復元される。スナップショットはユーザーが明示的に操作する必要はなく、セッション終了時に自動取得される仕組みである。これにより、npmパッケージのインストールやプロジェクトファイルの配置といった繰り返し作業から開発者が解放される。

従来のSandbox(Before)
起動 npm install ファイル配置 開発開始

※毎回セッション開始時に環境構築が必要。待ち時間が発生し、開発効率が低下する

永続化対応後(After)
起動 自動復元 即座に開発開始

※前回の状態が自動的に復元される。セットアップ不要で作業を継続できる

この変化は、継続的な開発やCI/CDパイプラインでの自動テストなど、頻繁な環境再作成が発生するシナリオで特に効果を発揮する。

永続的Sandboxの作成と利用

永続的Sandboxの作成と利用

デフォルトで有効化される永続性

Sandbox.create()を呼び出す際、永続化は自動的に有効になる。特別な設定やオプションの指定は不要だ。作成時にnameパラメータで一意の名前を付与すれば、その名前がプロジェクト内での参照キーとなる。この名前は後から変更することも可能であり、プロジェクトの命名規則に合わせた管理ができる。

名前付きSandboxは単なる識別子以上の役割を持つ。チーム内で「staging-test」「feature-auth」といった意味のある名前を付けることで、目的に応じた環境の使い分けが容易になる。また、存在しない名前を指定した場合は新規作成、既存の名前を指定した場合は既存環境の復元と、名前ベースの直感的な操作が可能だ。

import { Sandbox } from "@vercel/sandbox";

// filesystemは自動的にスナップショット保存される
const sandbox = await Sandbox.create({ name: "my-sandbox" });

await sandbox.runCommand("npm", ["install"]);

await sandbox.stop();

上記のコードでは、npm installでインストールされた依存パッケージが自動的にスナップショットとして保存される。次回Sandbox.get({ name: "my-sandbox" })で取得した際には、インストール済みの状態から即座に作業を再開できる。

ステートレスSandboxとの使い分け

永続化は便利だが、すべてのユースケースで必要とは限らない。一時的な検証や使い捨てのテスト環境では、永続化を無効にすることでスナップショット保存にかかるストレージコストを節約できる。スナップショットストレージはコンピューティングリソースとは別の課金体系であり、不要な保存はコスト増につながるためだ。

import { Sandbox } from "@vercel/sandbox";

const sandbox = await Sandbox.create({ persistent: false });

// 既存のSandboxを後から変更することも可能
await sandbox.update({ persistent: false });

CLIを利用する場合は、sandbox createコマンドに--non-persistentフラグを付与する。非永続的Sandboxはセッション終了時にfilesystemが完全に破棄されるため、機密データを含む一時的なテストや、毎回クリーンな状態から始めたいCIジョブに適している。

永続的Sandboxと非永続的Sandboxの比較
永続的Sandbox
継続的な開発環境
チーム共有の検証環境
長期メンテナンスのテスト環境
非永続的Sandbox
使い捨てのコード検証
クリーン状態が必要なCIジョブ
機密データを含む一時テスト

この使い分けにより、必要な場面では永続化の利便性を享受しつつ、不要な場面ではコストを最適化できる。開発の初期段階で「この環境は使い続けるか、それとも一度限りか」を判断基準にするのが実践的なアプローチだ。

セッション再開の仕組み

セッション再開の仕組み

永続化されたSandboxの再開は完全に自動化されている。停止中のSandboxに対してrunCommand()writeFiles()などの操作を呼び出すと、最新のスナップショットから自動的に新しいセッションが開始される。開発者が明示的に「再開」を指示する必要はなく、操作の実行がトリガーとなって透過的に処理される。

import { Sandbox } from "@vercel/sandbox";

const resumedSandbox = await Sandbox.get({ name: "my-sandbox" });

// 自動的にSandboxが再開される
await resumedSandbox.runCommand("npm", ["test"]);

Sandbox.get()で取得した段階ではまだセッションは開始されておらず、実際にコマンドを実行するタイミングでバックグラウンドで復元処理が走る。この遅延実行モデルにより、不要なセッション起動を避け、リソースの効率的な利用が可能になる。復元にかかる時間はスナップショットのサイズに依存するが、一般的なプロジェクト規模であれば数秒から十数秒程度で完了する。

Sandbox再開の内部フロー
STEP 1 Sandbox.get({ name: “my-sandbox” }) で参照を取得(まだ起動しない)
STEP 2 runCommand() 等の操作が呼び出される
STEP 3 バックグラウンドでスナップショットからfilesystemを復元
STEP 4 コマンド実行・ファイル書き込みが通常通り処理される
※復元は透過的に行われ、開発者は「再開」を意識する必要はない

この設計の利点は、開発者が環境のライフサイクル管理から解放される点にある。「今このSandboxは起動しているか」「停止状態からどう再開するか」といった状態管理の認知負荷がなくなり、コードの記述やテストの実行といった本質的な作業に集中できる。

コスト管理とスナップショットストレージの最適化

コスト管理とスナップショットストレージの最適化

永続化機能の利用にあたって注意すべき点は、スナップショットストレージの課金だ。Vercel Sandboxの料金体系では、コンピューティングリソースとスナップショットストレージが別々に課金される。永続化を有効にしたSandboxが増えるほど、保存されるスナップショットの総容量も増加し、それに比例してコストが発生する。

では、どのようにコストを最適化すればよいのか。以下の方針が実践的だ。

スナップショットコスト最適化の判断基準
永続化すべきケース
同じ環境を週に3回以上起動する
npm install に30秒以上かかる大規模プロジェクト
チームメンバー間で共有する標準環境
非永続化が適切なケース
一度限りのバグ再現テスト
PRごとに自動生成されるCI環境
依存関係がほぼない小規模スクリプトの実行

実際の運用では、Sandbox.update({ persistent: false })を使って後から設定を切り替えられるため、最初は永続化ありで作成し、不要と判断した時点で無効化する柔軟な運用が可能だ。また、Sandbox.delete()を使えば不要になったSandboxとそのスナップショットを完全に削除でき、ストレージの無駄遣いを防げる。

スナップショットの保存間隔や保持数については、現時点ではセッション終了時に自動取得される仕組みのみが提供されている。将来的にはスナップショット取得のタイミングを制御するオプションが追加される可能性もあるが、現行バージョンではシンプルに「停止時保存」のモデルで統一されている。このシンプルさが、開発者の意思決定コストを下げている面もある。

その他の重要な改善点

その他の重要な改善点

今回のGAリリースでは、永続化機能に加えていくつかの重要なAPI拡張も同時に提供されている。これらは永続化機能と組み合わせることで、より柔軟なSandbox管理を実現する。

Sandbox.fork() による環境の複製

既存のSandboxから新しいSandboxを作成するSandbox.fork()が追加された。特定の時点の環境を複製し、そこから別の検証を分岐させたいケースで役立つ。たとえば、メインの開発環境から「機能Aの実験用」「機能Bの実験用」をそれぞれフォークし、独立してテストを進められる。

Sandbox.getOrCreate() の冪等性

Sandbox.getOrCreate()は、指定した名前のSandboxが存在すれば取得し、存在しなければ新規作成する冪等な操作を提供する。CI/CDパイプラインでの環境セットアップスクリプトなど、「あれば使う、なければ作る」というパターンが1行で完結する。エラーハンドリングの分岐を書く必要がなくなり、コードの可読性が向上する。

ライフサイクルフックとタグ機能

onCreateおよびonResumeフックが追加され、Sandboxの作成時や再開時に任意の処理を挿入できるようになった。環境変数の動的設定や、起動時チェックの自動実行など、プロジェクト固有の初期化処理を組み込める。また、Tags機能によりSandboxにカスタムプロパティを付与でき、マルチテナント環境での追跡や分類が容易になる。たとえば「environment: staging」「team: frontend」といったタグを付けてフィルタリングすることが可能だ。

実践的な活用シナリオ

実践的な活用シナリオ

永続化機能の登場により、Vercel Sandboxの適用範囲は大きく広がる。ここでは具体的な活用シナリオをいくつか挙げる。

チーム内の共通開発環境として

すべての依存パッケージがインストール済みのSandboxをSandbox.fork()でメンバーに配布。環境構築の時間をゼロにし、全員が同一条件で開発を始められる。新メンバーのオンボーディング時間も大幅に短縮される。

CI/CDパイプラインの高速化

テストスイートの実行環境を永続化し、依存パッケージのインストール時間を削減。PRごとにSandbox.getOrCreate()で専用環境を用意し、テスト実行後のクリーンアップもSandbox.delete()で自動化できる。

バグ再現と修正検証

報告されたバグの発生環境をSandboxで再現し、そのまま永続化。修正パッチの検証が完了するまで環境を保持し、必要に応じてSandbox.fork()で別の修正アプローチも並行テストできる。

これらのシナリオに共通する利点は、「環境の再現性」と「セットアップ時間のゼロ化」だ。特にマイクロサービスアーキテクチャのように複数の依存関係が絡むプロジェクトでは、個々の開発者がローカルで依存関係を解決するよりも、クラウド上の永続化環境を共有する方が圧倒的に効率的なケースが多い。

この記事のポイント

  • Vercel Sandboxの永続化機能が正式版となり、セッション間のfilesystem自動保存がデフォルトで有効化された
  • 名前ベースのSandbox管理で環境の作成・取得・再開が直感的に行え、スナップショット操作は完全自動化されている
  • 永続的Sandboxと非永続的Sandboxの使い分けにより、利便性とコスト最適化のバランスが取れる
  • forkやgetOrCreateなどのAPI拡張で、チーム開発やCI/CDパイプラインへの統合がより容易になった
Supabaseプロジェクトをnpmサプライチェーン攻撃から守る7つの防御策

Supabaseプロジェクトをnpmサプライチェーン攻撃から守る7つの防御策

npmエコシステムを狙ったサプライチェーン攻撃が2026年に相次いでいる。5月には、TanStackがGitHub Actionsのワークフローキャッシュを汚染され、正規リリースに悪意あるコードが混入する事件が発生した。Supabaseも同様に、supabase-javascriptというタイポスクワット(入力ミスを狙った偽装パッケージ)がnpm上に現れるなどの標的に遭っている。

同社はこの事態を受け、プロジェクトの保護に向けた社内横断の対応を開始し、誰もが参照できる公式ガイドを公開した。本記事では、そのガイドの中核を抜粋し、攻撃の構造と開発者が今すぐ実施すべき防御策を具体的に解説する。

npmサプライチェーン攻撃の3つの典型的な手口

npmサプライチェーン攻撃の3つの典型的な手口

サプライチェーン攻撃は、直接システムに侵入するのではなく、開発者が信頼しているパッケージに悪意あるコードを忍び込ませる。以下が最も一般的な三つの手口だ。

メンテナの認証情報を奪う「アカウント乗っ取り型」

攻撃者がnpmの公開トークンを盗むか、メンテナをフィッシングして乗っ取り、人気パッケージの新版に悪意あるコードを仕込んで公開する。次にnpm installを実行すると、その悪質なバージョンが導入されてしまう。

入力ミスを誘う「タイポスクワッティング型」

本物のパッケージ名から数文字だけ変えた類似名でパッケージを登録し、開発者やAIコーディングエージェントが誤ってインストールするのを待つ。Supabaseの例では、@supabase/supabase-js ではなく supabase-javascript というスコープなしの名前で公開された。AIエージェントがパッケージ名を幻覚(ハルシネーション)して提案することも多く、この手法は脆弱だ。

ビルドパイプラインを悪用する「CI/CD侵害型」

この手口は、GitHub ActionsなどのCI/CDパイプラインの脆弱なワークフローを突く。攻撃者はフォークしたプルリクエストからワークフローのキャッシュを汚染し、次回の正規リリース実行時にそのキャッシュを拾わせて、正規メンテナの署名で悪意あるコードを公開させる。TanStackを襲った攻撃がまさにこれで、セッションメッセンジャーネットワーク経由で機密情報が流出した。

アカウント乗っ取り型
攻撃者がメンテナ権限を奪い、正規パッケージに悪意あるコードを仕込んで公開
タイポスクワッティング型
類似名の偽パッケージを登録し、開発者の打ち間違いやAIの誤提案を誘う
CI/CD侵害型
ビルドパイプラインのキャッシュを汚染し、正規リリースに紛れて悪質なコードが配布される

いずれの手口も、npm install の完了までに環境変数やAWSメタデータ、SSH秘密鍵といった機密情報を根こそぎ奪われる危険がある。

Supabaseが実施するプロジェクト防御策

Supabaseが実施するプロジェクト防御策

Supabaseはこの問題に対し、全社的な対応を開始した。以下が現在進行中の主な取り組みである。

公式セキュリティガイドの公開

同社は、npmセキュリティに関する推奨事項をまとめた単一の正規ガイドページを公開した。エージェントが読み取り可能な形式で、具体的なアクションを指示している。

GitHub Actionsの安全性強化

組織全体で pull_request_target の使用を精査し、アクションのバージョン参照をコミットSHAに固定する強制ルールの適用が最終段階に入っている。

クレデンシャル関連APIへの警告注釈

createClient などの関数にTSDoc(TypeScript向けドキュメントコメント)を追加し、エディタ上でホバー時に機密情報を扱う旨の警告が表示されるようにした。

全チャネルでの啓蒙活動

顧客かどうかを問わず、できるだけ多くの開発者に防御策を届けるため、ブログやコミュニティを通じた情報発信を強化している。

依存関係管理の厳格化

依存関係管理の厳格化

以下に挙げる設定変更は、いずれも数分で完了する。どれか一つでは完全な防御にはならないが、複数積み重ねることで攻撃者が諦めるほどの障壁を築ける。

パッケージマネージャを最新にして公開遅延を設定する

pnpm 11(またはnpm v11相当)にアップグレードし、minimumReleaseAge をデフォルトの24時間より長く設定する。多くの悪意あるパッケージはリリース後24〜48時間以内に検出され削除されるため、3〜7日の遅延を設けると、被害を受ける確率を大幅に下げられる。

# pnpm-workspace.yaml または .npmrc
minimumReleaseAge: 4320  # 分単位、3日

依存バージョンを固定する

^~ による範囲指定は、npmに対して「次のマイナーやパッチを自動的に取り入れて問題ない」と伝えているに等しい。認証情報やネットワーク通信を扱うパッケージでは、必ず正確なバージョン番号を指定しよう。

従来のバージョン指定(Before)
"dependencies": {
  "@supabase/supabase-js": "^2.39.0",
  "axios": "~1.6.0"
}
防御策適用後(After)
"dependencies": {
  "@supabase/supabase-js": "2.39.0",
  "axios": "1.6.2"
}

ロックファイルをコミットし差分を精査する

pnpm-lock.yamlpackage-lock.json は、インストールされた正確なバージョンとハッシュを記録する。攻撃者が同じバージョン番号で悪意あるtarballを差し替えても、ハッシュが一致せずインストールが失敗する。ロックファイルをリポジトリにコミットし、プルリクエストの差分では目的不明な依存関係の変更がないか必ず確認する。

不用なインストールスクリプトを無効化する

サプライチェーン攻撃のペイロードの多くは、preinstall install postinstall といったライフサイクルスクリプトを通じて実行される。ネイティブコードを含むパッケージを必要としないプロジェクトでは、これらをグローバルに無効化する。npmでは npm config set ignore-scripts true または .npmrcignore-scripts=true を記述する。pnpmではAllow Buildsモデルを使って、実際に必要なパッケージだけを許可リストに登録する。

安全なパッケージ導入のための実践

安全なパッケージ導入のための実践

パッケージ名を毎回検証する

タイポスクワッティング対策として、以下の点をインストール前に必ず確認する。

  • スコープが正しいか。Supabase公式パッケージはすべて @supabase/ 配下にある。
  • メンテナの一覧が期待通りか。長年維持されてきたパッケージに新しいメンテナが突然加わっていれば警戒信号だ。
  • ダウンロード数とリンク先のGitHubリポジトリが、本物のパッケージとして妥当であること。

CI/CDワークフローを狙った攻撃への対策

CI/CDワークフローを狙った攻撃への対策

ActionsをコミットSHAで固定する

ワークフローで参照するサードパーティアクションは、タグではなくコミットの完全なSHAハッシュ(40文字)で固定する。タグは攻撃者が新しいコードで置き換えられるため安全でない。

- uses: actions/checkout@1f9a0c22da41e6ebfa534300ef656b67ce0c5b94 # v6.0.2

pull_request_target の危険な使い方を回避する

pull_request_target イベントは、プルリクエストのコードをチェックアウトして実行するコンテキストで使うと、攻撃者がリポジトリのシークレットやキャッシュにアクセスできてしまう。TanStackを襲った攻撃はまさにこのパターンだった。PRのコードに触れる処理は必ず pull_request を使用し、pull_request_target はラベリングやコメント投稿など、コードを実行しない信頼済み操作に限定する。

危険なワークフロー(Bad)
on:
  pull_request_target:
    types: [opened, synchronize]
jobs:
  build:
    - uses: actions/checkout@v4
      with:
        ref: ${{ github.event.pull_request.head.sha }}
安全なワークフロー(Good)
on:
  pull_request:
    types: [opened, synchronize]
jobs:
  build:
    - uses: actions/checkout@v4

インシデント発生時の即応策

インシデント発生時の即応策

クレデンシャルのローテーションと監査

もし疑わしいパッケージを含む環境で npm install を実行してしまったら、そのマシンを危殆化したと見なし、到達可能なすべての認証情報(AWS、GCP、Kubernetes、Vault、GitHub、npm、SSH、Supabaseのサービスロールキー)を直ちにローテーションする。Supabaseのダッシュボードでサービスロールキーの使用状況を監査し、不審なアクセスパターンがないかも確認する。半日はかかる作業だが、顧客への被害を防ぐ価値は十分にある。

スキャナの導入で第二の防御線を

Socket.devやnpq、Snykといったツールは、npmレジストリのパッケージをリアルタイムで監視し、怪しい挙動をフラグ付けしてくれる。これらは万能ではないが、基本的な対策をすでに実施しているチームにとって有効な第二の防御線となる。

AIコーディングエージェントに渡すセキュリティチェックリスト

AIコーディングエージェントに渡すセキュリティチェックリスト

以下は、Supabaseが推奨するリポジトリ監査プロンプトだ。Claude CodeやCursorなどに貼り付け、変更内容を必ず確認しながら適用する。プッシュやPR作成、依存関係の自動追加、クレデンシャルのローテーションは自動化せず、必ず人間が承認する。


このリポジトリのnpmサプライチェーン衛生状態を監査してください。以下の変更を適用し、何を行ったかを報告してください。明示的な承認なしにプッシュ、PR作成、新しい依存関係のインストール、クレデンシャルのローテーションは行わないでください。

パッケージマネージャ:
- 古いバージョンならpnpm 11+(または最新のyarn/npm/bun)にアップグレード
- 新バージョンに7日間の公開遅延を設定
  - pnpm: `minimumReleaseAge: 10080` を pnpm-workspace.yamlに
  - npm: `min-release-age=7` を .npmrcに
  - yarn (berry): `npmMinimalAgeGate: '7d'` を .yarnrc.ymlに
  - bun: `minimumReleaseAge = 604800` を bunfig.tomlの[install]セクションに
- ライフサイクルスクリプトをデフォルトで無効化。pnpmではallowBuildsで明示的に許可するパッケージをリスト。
- 非レジストリの透過的依存参照をブロック。pnpmでは`blockExoticSubdeps: true`等を設定。
- パッケージマネージャ自体を正確なバージョンとsha512ハッシュで固定

ロックファイルと依存関係:
- ロックファイルがコミットされていることを確認(gitignoreされていない)
- 認証、シークレット、通信、暗号、ユーザデータを扱う依存関係では^/~を正確なバージョンに置き換え
- Supabase関連のインポートがすべて`@supabase/`スコープか検証。スコープなしの類似名はタイポスクワットとしてフラグ

GitHub Actions(存在する場合):
- すべてのサードパーティアクションのusesを40文字のコミットSHAに固定し、元タグをコメントで残す
- pull_request_targetを使いPRコードをチェックアウトしているワークフローを抽出し、pull_requestへの書き換えを提案
- インストールワークフローに`npm audit signatures`の非ブロッキングステップを追加

人の確認が必要な項目:
- Dependabotアラートとシークレットスキャンが無効なら有効化を提案

レポート:
- ファイル変更ごとに1行の理由付きリスト
- 自動変更せずに人の判断が必要な項目の一覧

この記事のポイント

  • npmサプライチェーン攻撃は、アカウント乗っ取り、タイポスクワッティング、CI/CD侵害の3パターンに大別される
  • Supabaseは公式ガイド公開、GitHub Actions強化、API警告追加などで対策を推進中
  • 即効性のある防御策として、パッケージマネージャの更新と公開遅延設定、バージョン固定、ロックファイル精査、インストールスクリプト無効化、パッケージ名検証、ActionsのSHA固定、pull_request_targetの回避がある
  • 万が一侵害が疑われる場合はクレデンシャル全ローテーションとスキャナ導入で二次被害を防ぐ
  • AIエージェントには安全な監査プロンプトを組み込み、自動変更を人の目でレビューする体制を整える
View Transitions、大量要素スケーリングにview-transition-classが効く

View Transitions、大量要素スケーリングにview-transition-classが効く

クロスドキュメントビュートランジション(View Transitions)は、ページ間の遷移をアプリのように滑らかにする強力なAPIだ。しかし本番環境で数十、数百の要素を扱おうとすると、途端にスケーリングの問題に直面する。1つのヒーロー画像を動かすデモは簡単だが、48枚の商品カードを個別に遷移させるとなると話が違う。

本記事では、view-transition-classと動的な名前付けの手法を用いて、大量要素を効率よく扱う方法を解説する。CSS-Tricksで公開された連載Part 2の内容を基に、実践的なパターンとアクセシビリティへの配慮までカバーする。

view-transition-classがスケーリングの鍵

view-transition-classがスケーリングの鍵

多くのチュートリアルでは、1つの要素にview-transition-name: heroを付与し、ページ間でマッチさせる。しかし実際のプロダクトグリッドでは、48枚のカードには48の一意な名前が必要になる。CSSでこれに対応しようとすると、次のような悪夢が待っている。

::view-transition-group(card-1),
::view-transition-group(card-2),
::view-transition-group(card-3),
::view-transition-group(card-4),
::view-transition-group(card-5),
::view-transition-group(card-6),
::view-transition-group(card-7),
::view-transition-group(card-8)
/* ... さらに92個続く */ {
  animation-duration: 0.35s;
  animation-timing-function: ease-out;
}

この方法は、要素数が増えるほど管理不能になる。100個の商品があれば100個のセレクタを書かなければならず、保守は事実上不可能だ。

名前とクラスの決定的な違い

ここで重要になるのが、view-transition-nameview-transition-classの使い分けだ。両者は似ているようで役割がまったく異なる。

  • nameは「同一性」を表す。ページAのサムネールとページBのヒーロー画像が「同じもの」だとブラウザに伝える。nameはページ内で一意でなければならない。重複するとトランジションは破棄される。
  • classは「スタイルのフック」だ。50の要素がview-transition-class: cardを持てば、1つのCSSルールでそれらすべてのアニメーションを制御できる。通常のCSSクラスと同じ考え方で、特定の要素を指すものではなく「こう見せたい」をグループ化する。

データベースにたとえるなら、nameが主キー、classがカテゴリ列に相当する。主キーは一意に1行を特定し、カテゴリ列はまとめてクエリをかけるために使う。

クラスを使った共通スタイルの記述

実際のCSSはこうなる。6枚のカードに6つのユニークなnameを与えつつ、アニメーションのルールはたった3つで済む。

::view-transition-group(*.card) {
  animation-duration: 0.35s;
  animation-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
}

::view-transition-old(*.card),
::view-transition-new(*.card) {
  object-fit: cover;
}

セレクタの*.cardは「view-transition-classがcardであるすべてのビュートランジショングループ」を意味する。アスタリスクはnameのワイルドカードで、classにマッチする。これでカードが60枚でも600枚でもCSSは変わらない。

従来手法(各カードに個別セレクタ)
48個のカードそれぞれに固有のルールを記述する必要がある
::view-transition-group(card-1), ::view-transition-group(card-2), …
※ 100個を超えると事実上管理不能
view-transition-class を使った改善後
共通クラスに1つのルールを書くだけ
::view-transition-group(*.card) { animation-duration: 0.35s; }
※ 何枚でもCSSは変わらない
■ 要素数に依存せず、わずか数行で全カードのアニメーションを制御できる

このように、view-transition-classは大量要素のビュートランジションにおける、スケーリングの本質的な解決策だ。CSSのみで記述する理想形であるident("card-" sibling-index())のような自動生成はまだブラウザに実装されていないが、クラスを使えば十分なスケールを得られる。

動的名前付けでパフォーマンスを最適化

動的名前付けでパフォーマンスを最適化

view-transition-classでスタイルのスケーリングは解決した。しかし、nameをページロード時にすべて付与してしまうと、別の問題が発生する。ユーザーが1枚のカードをクリックするだけでも、ページ上の全カード(48枚)のスナップショットが撮られ、疑似要素ツリーが構築されてしまうのだ。これは余計なコストであり、特にミドルレンジのモバイル端末ではトランジションのカクつきやスキップを引き起こす。

pageswapとpagerevealのライフサイクル

正しいアプローチは、nameを「ジャストインタイム」で付与することだ。ユーザーが操作したその瞬間にだけnameを設定し、遷移が終われば削除する。これにより、実際に遷移する要素だけがキャプチャされ、無駄な処理が発生しない。

流れはこうだ。

  • ユーザーが一覧ページでカードをクリックする。
  • ブラウザがナビゲーションを開始し、旧ページでpageswapイベントが発火する。
  • pageswapハンドラがクリックされたカードを特定し、view-transition-name: product-42を動的にセットする。
  • ブラウザがその要素のスナップショットを撮る。
  • 新ページが読み込まれ、pagerevealイベントが発火する。
  • pagerevealハンドラがURLからIDを読み取り、ヒーロー要素に一致するnameを割り当てる。
  • ブラウザが新旧のスナップショットをマッチさせ、モーフィングアニメーションを再生。
  • トランジションが完了したら、viewTransition.finishedのPromise解決後にnameをクリアする。

この一連の流れで、名付けられるのはたった1つの要素だけだ。48枚のカードのうち47枚は何も関与せず、無駄なスナップショットはゼロになる。

商品一覧ページ(クリック前)
カード42 data-id=”product-42″(name未設定)
ページロード時は全カードが匿名
↓ クリック
pageswap イベント発火
JavaScriptが view-transition-name: product-42 を動的に付与
↓ スナップショット → 遷移
商品詳細ページ
ヒーロー画像 pagereveal で view-transition-name: product-42 を設定
名前が一致し、モーフィング開始
■ クリックされた1要素だけがトランジションに参加し、残りは無視される

このパターンは、Astroのtransition:nameディレクティブやNuxtのビュートランジションサポートが内部的に行っていることと本質的に同じだ。フレームワークが抽象化している処理を、pageswappagerevealで直接制御していると考えればよい。

名前のクリーンアップが重要な理由

トランジション完了後にnameを削除するステップは、単なるお片付けではない。もしユーザーが一覧ページに戻り、別のカードをクリックした場合、古いnameが残っていると重複によるエラー(トランジションが即時破棄される)か、誤った要素とのマッチングが起きる。必ずviewTransition.finishedの解決後にnameをクリアすること。

実践的なパターン集

実践的なパターン集

商品グリッド以外にも、いくつかの典型的なパターンが存在する。実際のサイトで遭遇する状況に合わせて応用できる。

アスペクト比混合のフォトギャラリー

サムネールと拡大画像でアスペクト比が異なるギャラリーは、object-fit: coverで歪みを防ぎつつ、クラスで統一的に制御する。ポイントは、view-transition-name<img>自身に付与し、カードの枠やキャプションを含めないことだ。画像だけをモーフィングさせ、背景や枠は別のトランジションとして扱う。

::view-transition-group(*.gallery-item) {
  animation-duration: 0.5s;
  animation-timing-function: cubic-bezier(0.2, 0, 0, 1);
}

::view-transition-old(*.gallery-item),
::view-transition-new(*.gallery-item) {
  object-fit: cover;
  overflow: hidden;
}

/* ライトボックス背景は別クラスでフェード */
::view-transition-group(*.lightbox-bg) {
  animation-duration: 0.3s;
}

ライトボックスの暗いオーバーレイには、別のnameとclassを与え、独立したフェードインアニメーションを適用する。画像のモーフィングと背景のフェードが並行して走り、洗練された印象になる。

タブやセクションの切り替え

ダッシュボードタブやマルチステップフォームなど、同一ページ内でのセクション遷移にも同じ手法が使える。固定ヘッダーにはanimation-duration: 0sを指定して「動かない」ようにし、コンテンツだけがスライドする感覚を出す。

::view-transition-group(*.persistent) {
  animation-duration: 0s; /* 動かさない */
}

::view-transition-group(*.tab-content) {
  animation-duration: 0.25s;
}

::view-transition-old(*.tab-content) {
  animation: slide-out-left 0.25s ease-in;
}

::view-transition-new(*.tab-content) {
  animation: slide-in-right 0.25s ease-out;
}

永続的な要素にアニメーションをかけないことで、UI全体に安定感が生まれる。

無限スクロールと動的コンテンツ

無限スクロールで後からDOMに追加された要素にも、特別な対応は不要だ。pageswapハンドラはナビゲーション発生時にDOMをクエリする。要素がその時点で存在していれば、問題なくnameを割り当てられる。唯一注意すべきは、data-idなどマッチングに使う識別子が動的に追加されたバッチ間でも一意であることだ。APIが返すIDを利用していれば問題ない。

アクセシビリティとprefers-reduced-motion

アクセシビリティとprefers-reduced-motion

アニメーションは、前庭障害を持つユーザーに吐き気やめまい、片頭痛を引き起こす可能性がある。prefers-reduced-motionメディアクエリは、OSレベルで「動きを減らしてほしい」と設定しているユーザーを検出する。ビュートランジションを導入するなら、この対応は必須だ。

@view-transition {
  navigation: auto;
}

/* アニメーションのカスタマイズはすべてこのメディアクエリ内に */
@media (prefers-reduced-motion: no-preference) {
  ::view-transition-group(*.card) {
    animation-duration: 0.35s;
    animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
  }

  ::view-transition-old(*.card),
  ::view-transition-new(*.card) {
    object-fit: cover;
  }

  ::view-transition-old(root) {
    animation: fade-out 0.2s ease-in;
  }

  ::view-transition-new(root) {
    animation: fade-in 0.3s ease-out;
  }
}

/* 動きを減らす設定の場合は0秒で即座に切り替え */
@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation-duration: 0s !important;
  }
}

根本的に安全を取るなら、@view-transitionの宣言自体をprefers-reduced-motion: no-preferenceで囲み、トランジションを完全に無効化する方法もある。どちらを選ぶにせよ、アニメーションを無配慮に提供することだけは避けなければならない。

prefers-reduced-motion: no-preference(通常)
カードA → 0.35sのスケール&移動アニメーション
スムーズなモーフィングが再生される
prefers-reduced-motion: reduce(設定ユーザー)
カードA → 0sで即座に切り替え
視覚的な負荷を回避し、安全に遷移する
■ 設定に応じてアニメーションの有無を切り替えるのが基本

なお、prefers-reduced-motion: reduceのユーザー向けに、完全に0秒にする代わりに短いクロスフェード(0.15秒)を提供する手法もある。動きそのものをゼロにするのが最も安全だが、穏やかなフェードなら許容できるユーザーもいる。ただし、実際にその設定に依存するユーザーでテストするまでは、0秒を選択しておく方が無難だ。

プログレッシブエンハンスメントとブラウザ対応

プログレッシブエンハンスメントとブラウザ対応

ビュートランジションは、プログレッシブエンハンスメントの理想的な例だ。ブラウザが@view-transitionルールを理解しなければ、単に無視され、通常のページ遷移が行われる。何も壊れない。エラーもレイアウトシフトも発生しない。Firefoxがまだサポートしていなくても問題はなく、Safari 18.2以降やChrome、Edgeではフル機能が使える。

唯一、@supports (view-transition-name: none)でガードする価値があるのは、トランジション専用のスタイル(スナップショット品質向上のためのcontain: paintなど)を適用する場合だけだ。それ以外は、古いブラウザでも何もせずにそのまま動く。

この記事のポイント

  • view-transition-nameは一意の識別子、view-transition-classはスタイルをグループ化するフック。クラスを使えば、数百要素でも数行のCSSでアニメーションを統制できる。
  • nameはページロード時に全要素に付与せず、pageswapとpagerevealを使ってクリック時に動的に設定する。これでパフォーマンスが大幅に向上する。
  • トランジション完了後は必ずnameをクリアし、古い名前の衝突を防ぐ。
  • prefers-reduced-motionの対応は必須。すべてのアニメーションカスタマイズをメディアクエリ内に閉じ込め、設定ユーザーには0秒または短いフェードを提供する。
  • ビュートランジションはプログレッシブエンハンスメント。未対応ブラウザでは何も起こらず、通常のページ遷移となる。
Stack Overflow質問数が激減、AI時代に問いをやめた開発者の未来

Stack Overflow質問数が激減、AI時代に問いをやめた開発者の未来

2026年5月現在、Stack Overflowの月間質問数は3,000件を下回る水準にまで落ち込んでいる。2014年のピーク時には月間20万件を超えていたことを考えると、この10年余りで実に98%以上が消失した計算だ。

CSS-Tricksに掲載された分析記事は、この急落が単にAIの台頭だけでは説明できないと指摘する。コミュニティのモデレーション方針や初心者への閉鎖性が、ChatGPT登場以前からすでに質問数の減少を招いていたという。本記事では同記事の考察を軸に、AI時代における開発者の「問う力」の行方を掘り下げる。

重要な問いはこうだ。開発者が質問をやめた世界で、AIの学習データはどう更新されるのか。次世代のコード職人は育つのか。これらの懸念はCSS-Tricksの記事全体を貫く核心でもある。

Stack Overflow質問数の急落が示すもの

Stack Overflow質問数の急落が示すもの

Stack Overflowは2008年の設立以来、開発者にとって最大級のQ&Aプラットフォームとして機能してきた。しかしData Stack Exchangeで公開されている統計は、驚くべき下落曲線を描いている。

2014年には月間20万件以上の新規質問が投稿されていた。ところが2026年には月間3,000件にも満たない状況だ。このグラフは、単なるプラットフォームの衰退を超えて、ソフトウェア開発における知識共有の在り方そのものが変質したことを物語る。

2014年のピーク時(Before)
200,000 件/月
新規質問が活発に投稿され、回答も即時についていた
初心者 熟練者 誰でも質問
2026年の現状(After)
3,000 件/月未満
98%以上の質問が消失、回答の蓄積も鈍化
AI回答 ナレッジ停滞

このグラフが示す事実は重い。Stack Overflowはソフトウェア開発の集合知として15年以上にわたり機能してきたが、その流入がほぼ止まったに等しい。CSS-Tricksの記事では、この減少を「大量のレンガが降ってくるような衝撃」と表現している。

減少の原因はAIだけではない

減少の原因はAIだけではない

ChatGPTが公開されたのは2022年11月だ。しかしStack Overflowの質問数減少は、それよりずっと前の2014年から始まっていた。CSS-Tricksの記事は、AIを「最後のとどめ」と位置づけつつ、真の要因は別にあると分析する。

厳格化するモデレーションと閉じたコミュニティ

2014年以降、Stack Overflowは質問の品質を保つためにクローズ・削除の基準を厳格化した。重複質問は容赦なく閉じられ、「すぐに回答できない質問」も排除される方針が取られた。同サイト自身が「社交的ではないが、驚くほどうまくスケールする」と述べていたほどだ。

この運用はGoogle検索経由で既存の回答に誘導するモデルとしては合理的だった。しかし初めて質問しようとする初心者にとっては、門前払いの壁にしか見えなかった。CSS-Tricksの記事は「学びたいという意欲に対して罰を与えられるようなものだ」と表現している。モデレーションの厳しさがコミュニティの新規参加を阻み、質問数の漸減を招いたのだ。

従来のStack Overflow質問フロー(Before)
質問投稿 重複チェックでクローズ ダウンボート
※ 初心者は萎縮し、質問そのものを諦めるケースが多かった
現在のAI活用フロー(After)
質問を入力 LLMが即座に回答 判断なし・即時
※ ただし回答の正確性・セキュリティリスクは未検証のまま

変化の流れははっきりしている。質問を歓迎しないコミュニティの空気がまず参加者を減らし、そこに24時間即答してくれるAIが登場したことで、残っていた質問需要も完全に吸収された形だ。

AIは問題解決の代替になるか

AIは問題解決の代替になるか

AIはコードを書ける。だが「問題を解決できる」かは別の問いだ。CSS-Tricksの記事は複数の研究を引用しながら、この点を丁寧に解きほぐしている。

AI生成コードの品質

DeepMindのAlphaCodeは競技プログラミングで人間レベルの成績を収めた。しかし実務のソフトウェア開発は競技とは異なる。コーネル大学の研究によれば、AI生成コードは「一般に単純で反復的であり、未使用の構造やハードコードされたデバッグ処理を含みやすい」という。一方で人間のコードは「構造的複雑性が高く、保守性の問題が集中する傾向がある」と報告されている。

セキュリティ面ではさらに深刻だ。VeraCodeが100のAIモデルを対象に脆弱性テストを実施したところ、AI生成コードの45%にセキュリティ上の欠陥が見つかった。CSS-Tricksの記事は「十分な検証なしにAIコードをコピー&ペーストするだけであれば、深刻なバグや脆弱性に必ず直面する」と警告する。

AI生成コードの特徴(Bad)
単純かつ反復的な構造
未使用の変数・関数が残る
ハードコードされたデバッグ処理
45%にセキュリティ脆弱性
出典: Cornell大調査 / VeraCode
人間のコードの特徴(Good)
構造的複雑性が高い
コンテキストを考慮した設計
テスト・エッジケースの考慮
保守性の問題は多いが、意図は明確
出典: Cornell大調査

MITの研究も、AIは「良いコードを書けるが、ソフトウェアエンジニアのように思考し判断することはできない」と結論づけている。GitHubが2024年8月に公開した調査では、開発者の97%以上が仕事またはプライベートでAIツールを利用しているという。AIは遍在しているが、それを使いこなす職人技は依然として人間の側にある。

生産性とモチベーションのトレードオフ

Harvard Business Reviewの研究によれば、生成AIは問題解決の生産性を高める一方で、作業者のモチベーションを低下させる副作用がある。CSS-Tricksの記事はこの点を「AIは問題解決を支援する道具としては有効だが、創造性と問題解決アプローチを代替することはできない」とまとめている。

職人はすべての道具を使いこなす。AIもその一つにすぎない。道具の有効性は、それを作った職人の技量と、それを使う工夫によって決まる。CSS-Tricksの記事が引用するCraig D. Lounsbroughの言葉が端的に示す通りだ。

AIを賢く使うための自問

AIを賢く使うための自問

CSS-Tricksの記事では、著者自身が開発作業でAIを使う際に実践している4つのチェック項目が紹介されている。このリストは、AIへの過剰依存を避けつつ生産性を高める実践知として参考になる。

STEP 1 小さく具体的な質問に分割しているか
システム全体をまとめて尋ねるのではなく、各ステップを個別に検証できる粒度にする
STEP 2 出力内容を評価し、理解しているか
生成されたコードを将来にわたって保守・修正できるか自問する
STEP 3 参照元・情報源を確認しているか
回答の根拠が架空の文献でないか、信頼できる最新手法かを確かめる
STEP 4 エッジケースまでテストしたか
ユーザーが実際にどう使うかを理解するのは人間の役割。AIには難しい領域

この4つの自問は、AIにすべてを任せるのではなく、開発者自身が主体的にコードの品質と安全性に責任を持つためのガイドラインだ。CSS-Tricksの記事は「AIにすべてを委ねるのは大きな間違いだ」と明言している。

問いをやめた先にあるもの

問いをやめた先にあるもの

記事の後半で提起される最も本質的な問いはこれだ。開発者が質問することをやめた世界で、AIの学習データはどう更新されるのか。

CSSを例に取れば、ここ数年でネスト、ビュートランジション、コンテナクエリといった仕様が急速に進化した。数年前のコードと現在のコードでは書き方が根本的に異なる。もし新たな質問と回答の蓄積が止まれば、LLMは古いプラクティスに基づいたコードを出力し続けることになる。CSS-Tricksの記事は「私たちが質問をやめ、回答をやめれば、LLMは時代遅れになるのではないか」という懸念を示している。

質問が生まれ続ける世界(Before)
開発者の質問 回答の蓄積 ナレッジ更新 AIの学習データ
※ 技術の進化に合わせて新しい質問と回答が継続的に生まれる健全なループ
質問が止まった世界(After)
質問の消失 回答の枯渇 ナレッジの停滞 LLMの陳腐化
※ CSSネストやコンテナクエリなど新技術に対応できないLLMが増えるリスク

Stack Overflowの共同創業者Jeff Atwoodはかつて「Stack Overflowはあなた自身だ」と述べた。同僚プログラマーを信頼することがプラットフォームの核心だった。CSS-Tricksの記事は読者に問いかける。「LLMも同じことをしてくれるだろうか」と。

人間はこれまでも新しい道具とのバランスを見つけてきた。AIも例外ではないだろう。しかし、問うことをやめたコミュニティからは、新しい知見も、次世代の職人も生まれにくい。その危惧がこの記事の底流にある。

この記事のポイント

  • Stack Overflowの月間質問数は2014年の20万件超から2026年には3,000件未満へと98%以上減少した
  • 減少の原因はAIだけではなく、2014年以降の厳格なモデレーションと初心者排除のコミュニティ構造が先行要因として存在する
  • AI生成コードの45%にセキュリティ脆弱性があり、コピー&ペーストだけでは深刻なリスクを招く
  • 開発者は小さな質問への分割、出力評価、参照元確認、テストの4ステップでAIと向き合うべきである
  • 質問と回答の蓄積が止まれば、LLMは新技術に対応できず陳腐化するという構造的リスクがある
84万超の検索分析が示すAI Overviewの行動変容

84万超の検索分析が示すAI Overviewの行動変容

GoogleがAI Overviewの表示を拡大するなか、検索結果上でのユーザー行動が大きく変わり始めている。Search Engine Journalが公開した最新の調査レポートでは、約84.6万件の米国ユーザーの検索セッションをもとに、クリック前の画面内行動を詳しく分析した。

同レポートの著者Eric Van Buskirk氏によれば、AI Overviewが表示されるとユーザーはSERP上に長く留まり、検索結果を何度も確認し、比較し、そしてクリックの判断を慎重に行うようになるという。この変化は、単にランキング上位を狙うだけであったこれまでのSEO戦略に再考を迫る。

今回は、同調査から明らかになった4つの核心的な発見と、それが自社サイトやブランドにとって何を意味するのかを、わかりやすく整理する。

1. AI Overviewは検索意図に関係なくSERP滞在時間を延ばす

1. AI Overviewは検索意図に関係なくSERP滞在時間を延ばす

調査データと分析手法の概要

今回の調査は、ClickStream SolutionsがSurfer SEOから提供された匿名化クリックストリームデータを解析したものだ。対象は2026年2〜3月の米国ユーザー約84.6万セッション。1秒間隔で取得されたカーソル位置情報を用いて、ユーザーが検索結果ページ上でどこを読み、どこで止まり、どの程度スクロールしたかを追跡した。

分析において特に重要なのが「残留率(滞留率)」だ。検索結果が表示されてから3秒後、6秒後…21秒後の各時点で、どれだけのユーザーがまだ同一のSERP上でアクティブな状態にあったかを、情報検索、ローカル、ナビゲーショナル(ブランド名検索)、トランザクショナル(購入意図)、動画の5つの検索タイプに分けて比較している。

AI Overviewが行動差を消し去る

AI Overviewが表示されていない場合、検索意図によってSERPからの離脱スピードは大きく異なっていた。最も早く離脱するナビゲーショナル検索では、21秒後にSERP上に残っているユーザーはわずか12%。反対に、地図や口コミ情報が豊富なローカル検索では、32%がまだアクティブだった。

ところがAI Overviewが表示された途端、この差がほとんどなくなる。同じ21秒後でみると、どの検索タイプでも42%〜49%のユーザーがSERP上に留まっており、全タイプがきわめて似た行動パターンを示すようになる。つまり、AI Overviewがある状況では、ユーザーはもともとの検索意図によらず、一様に時間をかけて情報を読み込むモードに切り替わっているのだ。

AI Overviewなし(Before)
情報検索 21.6%
ローカル 32.3%
ブランド名 12.0%
購入意図 24.9%
動画 23.4%
AI Overviewあり(After)
情報検索 45.4%
ローカル 41.9%
ブランド名 45.8%
購入意図 47.4%
動画 48.5%

※21秒経過時点でのSEPR残留率。AI Overviewの有無で行動差が縮小する。

2. ブランド名検索ユーザーが最も大きな影響を受ける

2. ブランド名検索ユーザーが最も大きな影響を受ける

勝手に来ると思われていたユーザーが変わる

最も顕著な変化が起きたのは、ナビゲーショナル検索、つまりブランド名やサイト名を直接入力して来るユーザー層だ。従来であれば、こうしたユーザーは迷いなく目的のサイトへクリックするため、SERPからの離脱は非常に早く、21秒後の残留率はわずか12%だった。

しかしAI Overviewが表示されたケースでは、同じブランド名検索でも21秒後に46%がまだSERP上に残っている。彼らは単にサイトのURLを見つけるだけでなく、AI Overviewの要約や周辺の情報を読んだり、検索結果を比較したりしながら、クリックするまでにより多くの時間をかけている。

カーソル移動範囲の拡大が示す「探る」行動

カーソル移動の分析でも同様の傾向が確認された。AI Overviewがない場合、ブランド名検索ユーザーのカーソルは非常に狭い範囲に集中し、画面全体に対する移動範囲はわずか8%だった。これは、目的のリンクだけを素早く探す行動パターンを示している。

一方、AI Overviewがあるとカーソルは画面の27.5%にまで広がる。彼らは結果のスニペットをあちこち読み返し、AI Overview内のテキストも追いながら、より広い視点で判断していることがわかる。ブランドにとっては、これまでほぼ確実に得られていた直接流入が、検索結果の質と情報の明快さによって左右されるフェーズに移行しつつあると言える。

3. ユーザーは素早くクリックせず、比較しながら熟読する

3. ユーザーは素早くクリックせず、比較しながら熟読する

静止時間と画面カバー率の相反する増加

AI Overviewが表示されると、一見矛盾する2つのカーソル行動が現れる。ひとつはカーソルが静止している時間の増加で、セッション全体の44%が静止状態になる(AI Overviewなしでは29%)。もうひとつは、カーソルがカバーする画面範囲の拡大で、ビューポートの83%にまで及ぶ(同66%)。

この組み合わせは、ユーザーが「走り読み」から「立ち止まって読む」モードに切り替わったことを示唆している。断片的に情報を拾うのではなく、ある箇所でじっくりテキストを読んだあと、別のエリアにカーソルを移動してまた読む、という行動が繰り返されているのだ。

逆スクロールの多発が証明する比較検討

さらに決定的なのがスクロールの逆走だ。調査では、ユーザーがSERPを下にスクロールしたあと、再び上に戻る「逆スクロール」の発生率と、全スクロール量に占める逆方向スクロールの割合を計測した。AI Overviewがない場合、逆スクロールを経験するユーザーは51%で、その際の戻り量は全スクロールの27%だった。

ところがAI Overviewがあると、逆スクロール発生率は59%に上昇し、さらに逆方向スクロールが全スクロールの47.5%を占めるまでになる。つまり画面を上下に行ったり来たりしながら、複数の検索結果やAI Overviewの情報を照合しているのだ。この行動は、単なる上から下への「眺め」ではなく、能動的な比較検討が行われている証拠と言える。

AI Overviewなし
↓ 下へスクロール (全体の73%)
↑ 逆スクロール (全体の27%)
逆スクロールを行うユーザー: 51%
AI Overviewあり
↓ 下へスクロール (約52.5%)
↑ 逆スクロール (約47.5%)
逆スクロールを行うユーザー: 59%

※逆スクロールの比率がほぼ半々になり、上下に行き来する比較行動が増えたことがわかる。

4. 検索結果スニペットに求められる「精査に耐える情報」

4. 検索結果スニペットに求められる「精査に耐える情報」

タイトルとメタディスクリプションの重みが増す

これまでの検索行動のモデルは「上位の結果をざっと見て、一番適当なものをクリックする」だった。しかしAI Overviewが登場したいま、ユーザーは複数の結果をじっくり読み比べ、ときにはスクロールを戻して再確認しながら、最も信頼できる情報を選ぼうとする。

この変化が意味するのは、単に上位表示されているだけでは不十分で、検索結果のスニペット(タイトルとメタディスクリプション)が極めて重要になるということだ。曖昧で具体性のないスニペットは、一瞬のスキャンならクリックを誘えても、比較検討の場面では競合の明確な説明に負けてしまう。

ブランドが今すぐ見直すべきポイント

調査レポートから導かれる実務上の示唆は明快だ。まず、自社の検索結果の表示内容を「パッと見の印象」だけでなく、「じっくり読んだときに納得感があるか」という視点で見直す必要がある。

具体的には、タイトルタグに検索意図を明確に反映させ、メタディスクリプションにはページの独自価値を端的に盛り込む。AI Overviewが表示されるクエリでは、ユーザーは15〜20秒かけて熟考してからクリックするケースも増えている。その時間を味方につけるために、スニペットを「選ばれる理由」を語る場として設計することが重要だ。

5. この記事のポイント

  • AI Overviewが表示されると、ユーザーは検索意図にかかわらずSERPに長く留まり、結果を比較検討する行動が顕著になる
  • ブランド名を直接入力するユーザーでも、AI OverviewがあるとSERPでの滞留時間が4倍近くに伸び、クリックの確実性が低下する
  • カーソルの静止時間増加と画面カバー率の拡大、逆スクロールの多発は、ユーザーが「走り読み」から「熟読比較」へ移行した証拠
  • 検索結果スニペット(タイトルとメタディスクリプション)の情報の明快さが、クリック獲得の成否を分ける最重要ファクターになる
CloudflareがClaude Managed Agentsと統合、エージェントの実行基盤を刷新

CloudflareがClaude Managed Agentsと統合、エージェントの実行基盤を刷新

CloudflareがAnthropicと連携し、Claude Managed AgentsをCloudflareのサンドボックス環境と統合した。この新たな統合により、エージェントのコード実行からブラウザ操作、プライベートサービスへの接続までを、Cloudflareのプラットフォーム上でより柔軟に制御できる。

従来、Claude Managed AgentsはAnthropic側のインフラに完全に依存していた。今回の発表で「頭脳」であるClaudeの推論ループと「手足」であるコード実行基盤が分離され、後者をCloudflare上で運用できるようになった。

開発者は数分でテンプレートをデプロイし、セキュリティ強化やミリ秒単位のサンドボックス起動、内部サービスへの安全な接続といったメリットを得られる。この記事では、統合の仕組みと実務への影響を具体的に掘り下げる。

Claude Managed AgentsとCloudflareが目指すもの

Claude Managed AgentsとCloudflareが目指すもの
従来の構成
Claude推論ループもコード実行も、すべてAnthropic側のインフラで処理されていた。
課題:インフラ選択の自由度が低く、自社サービスとの統合が難しい
今回の統合後
Claudeの推論ループはAnthropic側。コード実行基盤(サンドボックス)はCloudflareで動かせる。
効果:セキュリティ、スケール、観測性をすべてCloudflareでコントロール

この構成で得られるのは単なる「場所の変更」ではない。インフラをCloudflareに移すことで、エージェントの振る舞いを細かく監視し、内部サービスとの通信を暗号化し、必要なリソースだけを動的に割り当てられるようになる。

Cloudflare Blogの記事では、この仕組みを「頭脳から手足を切り離す」と表現している。開発者はClaudeの高い推論能力をそのまま活かしつつ、実行環境だけを自社ポリシーに合わせてカスタマイズできるわけだ。

Cloudflare環境の仕組み

Cloudflare環境の仕組み

統合をデプロイすると、Cloudflare上にWorkersベースのコントロールプレーンが立ち上がる。Claude Agentがセッションを開始するたび、このコントロールプレーンがサンドボックス環境を割り当て、コード実行やCLIツールの操作、ブラウザ操作などを代行する。

STEP 1
Claude Agentがタスクを開始し、コントロールプレーンへリクエストを送信
STEP 2
Workersがセッションごとに隔離されたサンドボックスを起動
STEP 3
コード実行やファイル操作を実施。セッション間で状態を保持
STEP 4
ダッシュボードやSSHで稼働状況をリアルタイムに確認可能

サンドボックスはセッションがスリープしても状態を自動的に保持する。コンテナイメージのカスタマイズやインスタンスサイズの調整もオプションで指定でき、既存の監視ツール(DatadogやSplunk)へのログ連携にも対応している。

特筆すべきは、Cloudflareのダッシュボードからエージェントの状態を可視化し、必要に応じてSSHでサンドボックス内部に入れる点だ。大規模なエージェント運用では、トラブルシューティングのしやすさが運用コストを大きく左右する。この設計は現場の要求をよく踏まえている。

インターネット規模のエージェント実行基盤

インターネット規模のエージェント実行基盤

エージェントが本格的に普及すると、企業は1人のユーザーに対して複数のエージェントを同時に動かす必要が出てくる。従来のマイクロVM方式では、エージェントの数だけVMを起動し続けるため、リソースとコストが線形に増加してしまう。

Cloudflareはこの課題に対し、V8 Isolateを使った軽量サンドボックスを提供する。Dynamic WorkersとCodemodeを組み合わせることで、ミリ秒単位でサンドボックスを起動し、フルVMよりはるかに少ないリソースで任意のコードを実行できる。

マイクロVMサンドボックス
Linuxベースのフル機能。アプリケーション開発やCLIツールの実行向け
起動時間:秒単位。リソース消費は比較的多い
vs
V8 Isolateサンドボックス
軽量な隔離環境。ファイルシステムも持つが、VMより遥かに小さなフットプリント
起動時間:ミリ秒単位。数万の同時実行も可能

エージェントのセットアップ時にバックエンドタイプとして「isolate」を選択するだけで、この軽量モードに切り替えられる。数万規模の同時エージェントを扱うユースケースでは、コスト効率が数十倍変わる可能性がある。

もちろん、Linuxツールをフル活用する開発エージェントには、引き続きマイクロVMベースのCloudflare Containersを使える。用途に応じて2種類の実行環境を選択できる点が、この統合の実用的な強みだ。

エージェントワークロードのセキュリティ

エージェントワークロードのセキュリティ

エージェントが組織の内部データやサービスにアクセスするとき、最大のリスクは認証情報の漏洩だ。Cloudflareの統合では、アウトバウンドプロキシを使い、サンドボックスから外部へ出る通信に対して動的に認証情報を注入する仕組みを備えている。

この設計のポイントは、エージェント自身はクレデンシャルを知らないことだ。プロキシがゼロトラストベースでリクエストに署名やトークンを付与するため、万が一サンドボックスが侵害されても、認証情報そのものが盗まれるリスクを抑えられる。

エージェント 外部サービスへリクエスト送信 プロキシ 認証情報を注入 内部API 安全に応答
エージェントはクレデンシャルを保持しない  プロキシがゼロトラスト認証を代行する

また、Cloudflare MeshとWorkers VPCを使えば、インターネットに一切公開していない内部サービスにも、ポスト量子暗号で保護されたトンネル経由で接続できる。VPNや踏み台サーバーなしでプライベートサービスと通信できる点は、インフラ担当者にとって大きな利点だろう。

プロキシはテナント単位やエージェント単位でポリシーを適用できる。特定のエンドポイントだけを許可リスト化し、それ以外の通信を遮断するといった細かな制御も、コード数行で実装可能だ。

エージェントに必要なツール群

エージェントに必要なツール群

ブラウザ操作の完全な制御

エージェントがウェブと対話する際、単純なHTTPリクエストでは不十分な場面が多い。JavaScriptを多用するモダンなウェブアプリケーションの操作や、QA用のスクリーンショット取得、フォーム入力の自動化には、実際のブラウザが必要になる。

CloudflareのBrowser Runは、エージェントにプログラム可能なブラウザを与える仕組みだ。検索、実行、スクリーンショット、ページのMarkdown変換など、複数のツールがデフォルトで利用できる。

セッションの録画機能も備わっており、エージェントがブラウザ上で何をしたかを後から完全に監査できる。許可リストや拒否リストを使ったアクセス制御も可能で、野放図なウェブアクセスを防げる。

メール送受信とプライベート接続

エージェントにメールアドレスを割り当て、送受信を自律的に行わせる機能も統合済みだ。Cloudflare Email Serviceと連携し、任意のドメインでエージェントがメールを送信できる。顧客対応の自動化や、転送されたメールへの返信といったユースケースに適している。

内部サービスへの接続にはcall_serviceツールが用意されており、Cloudflare MeshやWorkers VPC経由でプライベートAPIを安全に呼び出せる。Workers AIを使った画像生成ツールも標準で組み込まれており、Claudeのテキスト推論と組み合わせたマルチモーダルなワークフローを構築できる。

カスタムツールの追加

リポジトリをフォークし、独自のツールを追加するのも容易だ。例えばCloudflare R2にファイルをアップロードし、公開URLを返すツールを数行のコードで定義できる。以下はCloudflare Blogで示されたコード例を簡略化したものだ。

defineTool({
  name: "r2_host_file",
  description: "サンドボックスからR2にアップロードし公開URLを取得",
  inputSchema: z.object({
    key: z.string(),
    content: z.string(),
    contentType: z.string()
  }),
  run: async ({ key, content, contentType }, { env }) => {
    await env.PUBLIC_BUCKET.put(key, content, { httpMetadata: { contentType }});
    return `${env.PUB_R2_URL}/${encodeURI(key)}`;
  }
})

Workers AIを使ったエッジ推論や、Dynamic Workersによる動的なアプリケーションホスティング、Artifactsを使ったGit管理の追加など、Cloudflare Developer Platform全体をエージェントの拡張に活用できる。インフラ管理を意識せず、関数を書いてデプロイするだけで機能追加が完了する設計だ。

この記事のポイント

  • Claude Managed Agentsの実行基盤をCloudflare上に構築できるようになった
  • 「頭脳(Claude)」と「手足(Cloudflareサンドボックス)」の分離で、インフラ選択の自由度が向上した
  • V8 Isolateを使った軽量サンドボックスで、ミリ秒起動と低コストの大規模実行が可能
  • アウトバウンドプロキシによるゼロトラスト認証で、エージェントのセキュリティを強化
  • ブラウザ操作、メール送受信、内部サービス接続などのツールが標準装備されている
Prisma Next早期アクセス開始、型安全DBコントラクトとエージェント連携

Prisma Next早期アクセス開始、型安全DBコントラクトとエージェント連携

Prisma Nextの早期アクセスが2026年5月22日に開始された。PostgresとMongoDBを対象に、データベース定義をコントラクトとして記述すれば、マイグレーションや型チェックをフレームワークが自動処理する。エージェントと連携する開発ワークフローにより、データ層の構築速度が大幅に向上する見込みだ。

開発者がコントラクトを書くと、あとはPrisma Nextがデータベースマイグレーション、クエリの型検査、エラー時の意味のあるメッセージを生成する。エージェントがコードを提案し、型検査を通過することで、安全なクエリが担保される仕組みだ。

1行のコマンドで始まるオンボーディング

1行のコマンドで始まるオンボーディング

新しいフレームワークを習得するには、ドキュメントを読み、小さなプロジェクトで試行錯誤を重ねる。慣れるまでに数週間を要することも多い。Prisma Nextはその学習曲線を1行のコマンドで解消する。npm create prisma@next を実行すれば、プロジェクトの骨組みと、エージェントを即座に専門家にする多数のスキルが自動生成される。

npm create prisma@next

ドキュメントを熟読する代わりに、エージェントがフレームワークの慣用句をリアルタイムに提示する。質問があればエージェントに尋ねればよく、コマンドの意味や設計の意図をその場で説明してくれる。まるで熟練者が隣で教えてくれているような体験だ。

従来のフレームワーク学習
STEP 1 ドキュメントを通読する
STEP 2 小さなサンプルを作成する
STEP 3 エラーを修正しつつ慣用句を覚える
Prisma Nextのオンボーディング
STEP 1 npm create prisma@next を実行
STEP 2 エージェントがプロジェクトとスキルを構築
STEP 3 質問があればエージェントに聞くだけ
従来は3週間かかっていた学習が、数分で開発を始められる状態になる。

既存プロジェクトへの導入

既存のプロジェクトに追加する場合もnpx prisma-next@latest initで簡単にセットアップできる。その後、エージェントに「読んでいる本を追跡する小さなアプリを構築して」と指示するだけで、スキーマ定義からクエリ作成までを自律的に進める。

コントラクトを書けばデータベース管理はフレームワーク任せ

コントラクトを書けばデータベース管理はフレームワーク任せ

Prisma Nextの中心にあるのが、アプリケーションとデータベースの間の契約であるコントラクトだ。開発者はモデルを定義するだけで、クエリの型検査や自動補完、そしてデータベースマイグレーションの計画と実行をフレームワークに委ねられる。

// contract.prisma
model Book {
  id       String   @id @default(uuid())
  title    String
  author   String
  addedAt  DateTime @default(now())
}
コントラクト(contract.prisma)
アプリケーション 依存関係 データベース 契約に従ってデータを保管
自動化されるタスク
クエリの型検査
自動補完
マイグレーション計画の生成
データベースとの整合性維持
開発者はコントラクトを編集するだけで、データベースとの一貫性が保たれる。

このコントラクトは可読性が高く、更新も容易だ。Prisma Nextではこれが唯一の真実の情報源となる。モデルを変更すると、フレームワークが自動的にマイグレーションを計画し、データベースが常にコントラクトを満たすように調整する。

エージェントによる機能追加の流れ

「著者テーブルを追加し、名前と経歴を持たせ、書籍と紐付けてほしい」といった自然言語での指示をエージェントに与えるだけで、コントラクトが更新される。エージェントは型検査を通過するまで内部でクエリの検証を繰り返し、最終的に安全なコードを出力する。

型安全クエリと高速な反復開発

型安全クエリと高速な反復開発

Prisma Nextのクエリはすべてコントラクトに対して型検査される。開発者(あるいはエージェント)がクエリを書くと、型エラーが即座にフィードバックされる。このループが高速なため、アプリケーションの出荷速度が格段に上がる。

const books = await db.orm.Book
  .where({ addedThisWeek: true })
  .all();

このクエリは、コントラクトで定義されたBookモデルに基づいて型が決定される。エージェントが生成したクエリも同じ型検査を通過するため、人間が書いたコードと同等の安全性が保証される。

クエリ作成の反復ループ
1 エージェントがクエリを書く
2 型検査による即時フィードバック
3 型検査を通過したクエリが確定
4 データベースが対応可能な安全なクエリ
エージェントはツール呼び出し内でこのループを自律的に繰り返す。

マイグレーションを記述する必要がなくなる

マイグレーションを記述する必要がなくなる

データベースのマイグレーションは、多くの開発者にとって最も苦痛を伴う作業の一つだ。構文を正しく記述し、エラーをデバッグし、本番環境で失敗した場合にはさらに時間を費やす。Prisma Nextでは、この負荷から完全に開放される。

マイグレーション作業の変化
従来の方法(Before)
SQLマイグレーションファイルを手動で記述
構文ミスやデプロイ時のトラブルシューティング
本番障害発生時に復旧作業
Prisma Nextの方法(After)
エージェントがコントラクトを編集
フレームワークがTypeScriptマイグレーションを自動生成
トランザクションで安全に適用(Postgres)
エージェントは意図を伝えるだけで、実際のマイグレーションコードは書かずに済む。

TypeScriptで書かれたマイグレーションファイル

生成されるマイグレーションファイルはTypeScriptで記述され、人間が確認しやすい形式だ。prisma-next migration plan を実行すると、ops.json とともにレビュー可能なマイグレーションが出力される。エージェントがSQLを生成するのではなく、フレームワークが決定論的に生成するため、信頼性が高い。

// migrations/app/20260515T0900_add_book_published_at/migration.ts
export default class M extends Migration {
  override describe() {
    return { from: "sha256:…prev", to: "sha256:…next" };
  }

  override get operations() {
    return [
      addColumn("public", "book", {
        name: "publishedAt",
        typeSql: "timestamptz",
        defaultSql: "",
        nullable: true,
      }),
    ];
  }
}

Postgresでは、マイグレーション全体が単一のトランザクション内で実行される。どこかで問題が発生してもロールバックされ、データベースは元の状態を保つ。MongoDBの場合は段階的に安全な手順で計画される。こうした保護機構によって、エージェントに安全に作業を委任できる。

並行ブランチでのマイグレーション競合を自動解決

並行ブランチでのマイグレーション競合を自動解決

複数ブランチで同時にマイグレーションを作成すると、マージ時に順序の衝突が起きることがある。Prisma NextはGitのコミットグラフのようにマイグレーション履歴を扱い、この問題を解消する。

ダイヤモンド型マイグレーショングラフの例
main
branch A のマイグレーション
branch B のマイグレーション
main(両方マージ後)
フレームワークはこの形状を理解し、正しい適用順序を自動的に判断する。prisma-next migration graph で可視化できる。

prisma-next-migration-review スキルをエージェントが活用することで、新しいマイグレーションがmainに到達した場合も、グラフを読み取り、ブランチをリベースし、migration planを再実行する。結果として、衝突なくクリーンにマージできる。複数のエージェントが並行して作業しても、特別な手順を覚える必要はない。

定期的なアップグレードとフィードバックの簡便さ

定期的なアップグレードとフィードバックの簡便さ

Prisma Nextは日々アップデートされており、アップグレードも簡単だ。エージェントに「prisma nextをアップグレードして」と指示するだけで、最新バージョンに更新してくれる。問題が見つかった場合も、エージェントに「これはバグだ」「この機能が欲しい」と伝えれば、適切な報告チャンネルを選び、構造化されたフィードバックを提出してくれる。

コミュニティでの成果発表も歓迎されている。Prismaの公式アカウントで紹介されたり、Prisma NextのREADMEにリンクが掲載される可能性もある。本格的にデプロイする場合、Prisma Postgresの無料枠を活用できる。なお、Prisma Nextはまだ本番環境向けではない。プロダクションには引き続きPrisma 7を推奨するが、一般提供時にはPrisma 8となる予定だ。

この記事のポイント

  • Prisma NextはPostgresとMongoDBに対応し、データベース定義をコントラクトとして扱う
  • 1行のコマンドでプロジェクトをセットアップし、エージェントが即座に開発を支援する
  • 型安全クエリにより、人間とエージェントのどちらが書いたコードも信頼できる
  • マイグレーションはフレームワークが自動生成し、トランザクションで安全に適用される
  • 並行ブランチでの競合もグラフベースの履歴管理で自動解決される
中国語フィッシング即サービスの進化、リアルタイムOTP傍受とデジタルウォレット悪用の実態

中国語フィッシング即サービスの進化、リアルタイムOTP傍受とデジタルウォレット悪用の実態

フィッシングはもはや、偽のメールを大量にばらまくだけの手口ではない。中国語圏のアンダーグラウンドでは、フィッシングをサービス化したPhaaS(Phishing-as-a-Service)が急速に成熟している。2026年5月にGoogle脅威インテリジェンスグループが公開した分析によれば、これらのサービスは静的なパスワード収集から脱却し、リアルタイムでのワンタイムパスコード(OTP)傍受やデジタルウォレットの悪用へと移行している。

特に警戒すべきは、RCSやiMessageといった暗号化通信を配信経路に選び、多要素認証(MFA)をリアルタイムで突破する手口だ。AIによるフィッシングページの自動生成や、日本市場を狙った高度なローカライズも確認されている。もはや攻撃者のゴールはログイン情報の窃取にとどまらず、被害者の金融口座を直接掌握することにある。

中国語圏PhaaSエコシステムの独自性

中国語圏PhaaSエコシステムの独自性

これまでPhaaSといえばロシア語圏の攻撃者が主流だった。だが中国語圏のエコシステムは、単なる地域的な派生版ではなく、独自の文化とビジネスモデルを持つ市場として確立されている。Google脅威インテリジェンスグループが分析した12の現行PhaaSサービスは、いずれも成熟しており、多くが地域の犯罪エコシステムと密接に結びついている。

ロシア語圏との違い

最も大きな違いは標的の選び方だ。ロシア語圏の主要PhaaSは大企業の顧客を狙う傾向があるのに対し、中国語圏のサービスは一般市民を日和見的に攻撃するケースが多い。また、運用の透明さも対照的だ。ロシア語圏の攻撃者が厳格な運用セキュリティを保つのに対し、中国語圏の運営者はTelegramで高級な生活ぶりを公開するなど、オープンに活動する傾向がある。

もうひとつの特徴は、模倣対象となる正規組織のほぼすべてが中国国外の企業である点だ。つまり、これらのフィッシングサービスは自国市場を標的にしていない。広告や勧誘は中国で人気のWeChatやQQよりTelegramで行われることが多く、これは中国語圏のサイバー犯罪エコシステム全体に共通する傾向だ。

エコシステムの構造

PhaaSを中核としつつも、これらのサービス運営者は多岐にわたる付随サービスを提供している。個人識別情報(PII)の販売、ドメイン登録や仮想プライベートサーバー(VPS)の提供、マネーロンダリング支援、盗聴デバイスの販売、スパムメッセージ送信代行などだ。一部の業者は盗難支払いカード情報の取引にも関与している。フィッシング単体ではなく、犯罪の全工程をパッケージ化した総合サービスへと発展しているのである。

進化した攻撃手法

進化した攻撃手法

中国語圏PhaaSの技術的進化を理解するには、従来のフィッシングと現在の手口を比較するのが早い。下の図は、その変化を視覚化したものだ。

従来のフィッシング(Before)
被害者 偽サイトに認証情報を入力 攻撃者 後日ログイン試行
✕ OTPで失敗、MFA突破できず
新しいPhaaS(After)
被害者 偽サイトに認証情報とOTPを入力
管理パネル 情報がリアルタイム表示 攻撃者 OTPを即時使用
✓ MFAを突破、アカウント乗っ取り成功

従来型では攻撃者が認証情報を入手しても、OTPに阻まれてアカウントへ侵入できなかった。しかし現在のPhishingは、被害者がコードを入力する瞬間をリアルタイムで傍受し、数秒のうちに悪用する。MFAはもはや万能の防御策ではない。

RCSとiMessageを悪用した配信

攻撃の起点は、信頼できる通信手段の悪用だ。これらのPhishingサービスは従来のSMSではなく、RCS(リッチコミュニケーションサービス)やAppleのiMessageを多用する。両プロトコルはエンドツーエンド暗号化を採用しており、サーバーサイドで悪意あるリンクを検査・フィルタリングすることが難しい。つまり、キャリア側のセキュリティフィルターを素通りする。

さらに、開封確認やタイピングインジケーター、高解像度画像の送信といった機能が、メッセージの信憑性を高める。被害者にとっては正規の連絡と見分けがつかず、ソーシャルエンジニアリングの成功率を大幅に引き上げる要因となっている。

リアルタイムOTP傍受

被害者がフィッシングリンクをクリックして認証情報を入力すると、そのデータは攻撃者の管理パネルに即時表示される。攻撃者はこれを見ながら、被害者のアカウントでOTPリクエストを自らトリガーする。被害者は届いたコードを偽サイトに入力し、攻撃者はそれをコードの有効期限が切れる前に傍受して利用する。この一連の流れは数十秒で完結する。

デジタルウォレットトークン化

最終的な目的は、盗んだ支払いカード情報をデジタルウォレットに登録し、トークン化することだ。攻撃者は入手した認証情報とOTPを使い、被害者のカードを自分の管理するデバイスのウォレットにプロビジョニングする。トークン化されたカードは、高額決済や非接触支払い、ATM引き出しに利用可能になる。もはやログイン情報の窃取ではなく、金融口座への直接的な不正アクセスを実現する手口である。

AIによる自動化

複数の中国語圏PhaaS事業者がAIを運用に取り入れている。たとえば、UNC5814として追跡されている「Darcula」プラットフォームは、静的なテンプレートを廃止し、AI駆動のページ生成とPuppeteerのようなブラウザ自動化ツールを採用した。標的サイトのURLを入力するだけで、そのHTMLやCSS、JavaScript、ビジュアル要素を複製し、動的に偽ページを生成する。ページごとに構成が異なるため、シグネチャベースの検出はほぼ無力化される。

ローカライズのサービス化とYY来魚の事例

ローカライズのサービス化とYY来魚の事例

これらのPhishingサービスは、単に多言語対応するだけではない。地域ごとの消費者文化に深く入り込んだ、高度なローカライズを実現している。その代表例が「YY来魚」だ。

YY来魚の標的と戦術

2024年8月に広告が確認されたYY来魚は、119カ国をサポートするが、最大の注力先は日本だ。2025年11月以降、400以上のフィッシングテンプレートを顧客に提供してきた。対象は銀行や証券にとどまらず、AmazonやApple、PayPay、メルカリ、任天堂、東日本旅客鉄道(JR)、佐川急便など、日本の消費者生活に密着したブランドが並ぶ。

特筆すべきは、単なる偽ログインページの提供ではない点だ。日本の消費者が慣れ親しんだ「ポイント」や「報酬交換」の仕組みを悪用し、「有効期限切れのポイントを現金や商品に交換」といった偽の案内で被害者を誘導する。さらに、光熱費補助をかたるなど、足元の経済状況に乗じたルアーも展開している。

インフラと運営

YY来魚のフィッシングサイトには、人間による認証操作を求めるアンチボット画面が実装されていた。手動クリックがないと先に進めない仕組みで、セキュリティベンダーによる自動分析を妨害する。管理パネルでは、フィッシングで収集したデータの検索、カードのBIN番号に基づくブロックリスト管理、国別の配信制限、Alibabaのドメイン登録サービスを使った新規ドメインの登録と管理が可能だ。さらにシステム管理者はオペレーターユーザーを作成し、権限を細かく割り当てることができる。

YY来魚は日本に焦点を当てた一例だが、中国語圏PhaaSの網は米州、欧州、豪州、中東にも広がっている。特定の地域文化に合わせたローカライズを自動化できるインフラが、低スキルの攻撃者にも高精度なキャンペーンを可能にしている。

防御側の対策と展望

防御側の対策と展望

ユーザー教育は依然として重要な防御線だが、それだけでは不十分だ。中国語圏PhaaSの拡散は、人を介さない技術的な制御の必要性を強く示している。

FIDO2/WebAuthnへの移行

最も効果的な対策のひとつが、FIDO2/WebAuthnインフラへの移行だ。公開鍵暗号方式に基づくこの認証は、OTPのように通信経路上で傍受されるリスクがない。セキュリティキーは、ユーザーがフィッシングサイトに支払い情報を直接入力する行為そのものを防ぐことはできないが、盗まれた認証情報の悪用難易度を大幅に引き上げる。攻撃者がログインできない時点で、カード情報のトークン化も成立しない。

発行体側の検証強化

金融機関やカード発行体には、デジタルウォレットへのプロビジョニング時にリスクベース検証とデバイスフィンガープリントを組み合わせる対策が求められる。見慣れないデバイスや異常な利用パターンを検知し、トークン化の前に追加検証を挟む仕組みだ。

防御側の目標は「フィッシングの検知」から「盗まれた認証情報を技術的に無力化すること」へと移行しつつある。中国語圏のPhaaS事業者は現在もツールの改良を続けており、グローバルな影響力をさらに拡大しようとしている。対策もそれに合わせて進化させねばならない。

この記事のポイント

  • 中国語圏Phishing-as-a-Serviceは、OTPのリアルタイム傍受とデジタルウォレット悪用によりMFAを突破する
  • RCSやiMessageのエンドツーエンド暗号化が、キャリア側のフィルタリングを無効化し配信成功率を高めている
  • AIによる動的ページ生成で、シグネチャベースの検出回避が容易になった
  • 日本市場を狙うYY来魚のように、地域経済や消費者文化に深く適応したローカライズが進んでいる
  • 対策にはFIDO2/WebAuthnの採用と、カード発行体によるプロビジョニング時のリスク検証が有効
KnowledgeDeliver脆弱性、ViewState攻撃の実態と対策まとめ

KnowledgeDeliver脆弱性、ViewState攻撃の実態と対策まとめ

国内の教育機関や企業研修で広く使われるLMS(学習管理システム)のKnowledgeDeliverに、深刻な脆弱性が見つかった。サーバーに保存された共通の暗号鍵を悪用され、遠隔から不正なコードを実行される恐れがある。

Google Cloudの脅威インテリジェンスチームであるMandiantは、2025年後半に実際の攻撃を確認した。攻撃者はこの脆弱性を足がかりにWebシェルを設置し、サイト訪問者のPCにバックドアを感染させる手口を使っていた。本記事では、この脆弱性の仕組みと攻撃の流れ、具体的な検知方法と対策を整理する。

KnowledgeDeliverが見舞われた脆弱性の正体

KnowledgeDeliverが見舞われた脆弱性の正体

共有されたマシンキーが招く全インストール共通の弱点

問題の発端は、ASP.NETアプリケーションの設定ファイル web.config に書き込まれた machineKey の値だ。このキーは、画面の状態情報を保持するViewStateデータの暗号化と署名に使われる。

本来、このキーはサーバーごとに個別のランダムな値を生成すべきものだ。しかし、2026年2月24日より前に配布されたKnowledgeDeliverのパッケージでは、開発元が用意したテンプレートの中に固定のキーが埋め込まれていた。その結果、別々の組織で稼働するすべてのインスタンスが、まったく同じマシンキーを共有する状態になった。

これは、すべての家の玄関に同じ鍵が付いているようなものだ。攻撃者が一つの鍵束を入手すれば、インターネット上に公開された他のすべてのKnowledgeDeliverサーバーに侵入できることを意味する。

本来あるべき姿(安全)
組織Aのサーバー → 固有の machineKey_A
組織Bのサーバー → 固有の machineKey_B
それぞれ異なる鍵を使うため、1つの鍵が漏れても他は安全
KnowledgeDeliverの実態(危険)
組織Aのサーバー → 共通の machineKey
組織Bのサーバー → 共通の machineKey
鍵が共通のため、1つの鍵が漏れると全サーバーが危険に

ViewState Deserializationが悪用される仕組み

ASP.NETのViewStateは、ページの往復(ポストバック)の間、ユーザーが入力した値や画面の状態を維持するための仕組みだ。ブラウザとサーバーの間で、暗号化された文字列としてやり取りされる。

machineKey を知る攻撃者は、このViewStateの中に悪意あるコードを含んだ特殊なデータ(ペイロード)を埋め込める。サーバーは受け取ったViewStateを復号し、データをオブジェクトに戻す処理(デシリアライゼーション)を実行する。この過程で、埋め込まれたコードがサーバー上で実行されてしまう。

この手法は、以前にMandiantが報告したSitecoreのViewStateゼロデイ脆弱性や、Microsoftが警告したASP.NETマシンキーの悪用事例と同種のものだ。共通鍵を使う設計の危険性を、あらためて浮き彫りにしている。

攻撃者は侵入後に何をしたのか

攻撃者は侵入後に何をしたのか

メモリ内で動作するWebシェル「BLUEBEAM」の投入

Mandiantの調査によれば、攻撃者はまず.NETベースのWebシェル「BLUEBEAM」を展開した。このツールはGodzillaとも呼ばれ、Microsoftも以前に同種の活動を報告している。

BLUEBEAMの特徴は、ファイルとしてディスクに保存されず、IISのワーカープロセス(w3wp.exe)のメモリ空間上だけで動作する点だ。一般的なウイルス対策ソフトによるファイルスキャンをすり抜け、HTTP POSTリクエストのボディに暗号化したコマンドを忍ばせて、遠隔操作を受け付ける。

ファイル改ざんとCobalt Strikeによる端末感染

Webシェルを確保した攻撃者は、サーバー上のファイル権限を変更し、アプリケーションのJavaScriptファイルに細工を加えた。具体的には、次のような改ざんが確認されている。

  • 「セキュリティ認証プラグイン」のインストールを促す偽の警告を表示するスクリプトの追加
  • 攻撃者が管理する外部ドメインから、不正なスクリプトをひそかに読み込むコードの埋め込み

この偽警告に従って「プラグイン」をダウンロードしたユーザーのPCには、Cobalt StrikeのBEACONバックドアが仕込まれた。ペイロードの暗号化には、標的組織の名称が使われており、攻撃者が特定の組織を狙って準備を進めていたことがわかる。

攻撃の流れ(Before → After)
侵入前(通常状態)
LMSサーバー → 正規のJavaScript → ユーザーのブラウザ
※ユーザーは正規のLMSコンテンツのみを読み込む
侵入後(攻撃状態)
LMSサーバー → 改ざん済みJavaScript → 偽警告表示 → 不正ツールDL → 端末感染
※改ざんされたスクリプトが外部から追加のコードを読み込み、偽のインストーラへ誘導

侵害をいち早く検知するための調査ポイント

侵害をいち早く検知するための調査ポイント

イベントログとプロセスの異常を監視する

ViewStateの悪用を試みた痕跡は、Windowsのアプリケーションログに記録される。ソースが ASP.NET 4.0.30319.0 で、イベントID 1316のメッセージに注目する。

  • 整合性チェック失敗時は「Viewstate verification failed. Reason: The viewstate supplied failed integrity check.」と出る。誤った鍵が使われた可能性がある。
  • 整合性チェックを通過したものの、ペイロードが無効だった場合は「Viewstate verification failed. Reason: Viewstate was invalid.」と記録される。この場合、復号は成功しており、コード実行までは至らずとも攻撃の試行があったとみなせる。

Mandiantは、実際にこのログからBLUEBEAMに関連するペイロード文字列を復元できたとしている。

また w3wp.exe を親プロセスとする不自然な子プロセスにも警戒が必要だ。cmd.exe /c ... whoami powershell.exe といったコマンドが実行されていないか、継続的にモニタリングする。

ファイルの改ざんと異常なUser-Agentをつかむ

Webサーバーの公開ディレクトリ内にある .js .aspx .config ファイルについて、想定外の変更が加えられていないか定期的に確認する。特に、外部ドメインへのスクリプト読み込みや、業務と無関係なコードの追加がないかを重点的に調べる。

さらに、Webサーバーのアクセスログに現れるUser-Agent文字列にも特徴がある。Mandiantの調査では、2つの異なるブラウザ識別子が連結された異常な文字列が確認された。以下はその一例だ。

Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.2 (KHTML, like Gecko) Chrome/22.0.1216.0 Safari/537.2 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36

このような連結されたUser-Agentは、通常のブラウザでは生成されない。攻撃ツールによる通信の痕跡として、ログ監視の有効な指標になる。

再発を防ぐための具体的な対策

再発を防ぐための具体的な対策

この脆弱性の根本原因は、全インストールで鍵を共有していたことにある。したがって、最も重要な対策は、マシンキーを一意の値に切り替えることだ。

  • マシンキーの再生成:各KnowledgeDeliverインスタンスで、暗号的に安全なランダム値を生成し、設定ファイルに反映する。共通鍵を無効化するには、これ以外の方法はない。
  • アクセス制限の見直し:LMSがインターネット全体に公開されている必要がなければ、社内ネットワークや特定のIPアドレス範囲からのみ接続を許可する。
  • 徹底的なインシデント調査:ログ監視やファイル整合性チェックを実施し、少しでも疑わしい兆候があれば、外部の専門家も交えて深く調査する。

Vupointブログの分析でも指摘されているとおり、テンプレートに埋め込まれた共通シークレットは、一見すると設定の手間を省く便利な仕組みに見える。しかし、ひとたび鍵が流出すれば、世界中のすべてのサーバーが一瞬で危険にさらされる。利便性と引き換えに、きわめて大きなリスクを抱え込む設計だったわけだ。

今回の事例は、ASP.NETに限らず、あらゆるWebアプリケーションの展開時において「鍵や認証情報は必ず環境ごとにユニークに生成する」という原則を再認識させるものだ。テンプレートや初期設定のまま本番運用に臨むことの危うさを、開発者と運用者の双方が改めて肝に銘じる必要がある。

この記事のポイント

  • KnowledgeDeliverの全インストール共通のASP.NETマシンキーが、ViewState Deserialization攻撃の原因になった
  • 攻撃者はメモリ内WebシェルBLUEBEAMを使い、サイト改ざんとCobalt Strike感染を連鎖させた
  • イベントログやプロセス監視、異常なUser-Agentの検出が有効な調査指標になる
  • 最も重要な対策は、各サーバーでユニークなマシンキーを生成し、共通鍵の状態を完全に解消すること
AIが変えるのは顧客ロイヤルティではなく商品発見。EC事業者が持つべき3つの視点

AIが変えるのは顧客ロイヤルティではなく商品発見。EC事業者が持つべき3つの視点

AIがECサイトの顧客関係を根本から変えようとしている。しかし、変化の本質は多くのEC事業者が懸念する「顧客ロイヤルティの消滅」ではない。むしろ、商品が顧客に見つかるプロセス、つまり商品発見の構造が変わる点にこそ注目すべきだ。

2026年5月、GoogleはI/OでUniversal Cart構想を発表した。検索やYouTube上で複数店舗の商品を比較し、Googleがカートを「所有」したまま購入まで完結する仕組みだ。この流れは、AIエージェントが購買代理人として機能する「エージェンティックコマース」への移行を加速させる。

EC事業者にとって、これは「誰が顧客との関係を握るのか」という問いの新たな章に過ぎない。実際、ECの歴史は常に商品発見チャネルの変化とともにあった。AIによる変化もまた、その延長線上にある。

商品発見から購買までを握るAIエージェント

商品発見から購買までを握るAIエージェント

AIエージェントとは、ユーザーの購買意図を解釈し、商品を比較・推奨し、カートの構築から購入完了までを自律的に実行するシステムのことだ。単なるレコメンドエンジンとは異なり、購買プロセス全体を代行する点が新しい。

Practical Ecommerceの記事によると、この仕組みが普及すれば、EC事業者は在庫と物流を依然として担う一方で、顧客との関係構築の一部を中間AIに委ねることになる。サイト上で直接購入を促すのではなく、AIシステムに自社商品の優位性を「理解させる」必要が出てくるのだ。

Tools for Working WoodのJoel Moskowitz氏は、Practical Ecommerceの記事の中で次のように指摘している。「エージェンティックな注文の問題は、すべての商品をコモディティ化してしまうことだ。小売業者には販売促進やアップセル、関連商品の閲覧を促す機会がまったくなくなる」

従来のEC購買フロー(Before)
顧客 検索 サイト訪問 商品閲覧 購入
※各サイトでアップセルやブランド体験を提供できる
エージェンティックコマースの購買フロー(After)
顧客 意図伝達 AIエージェント 比較・選択・購入 商品到着
※AIが購買判断を代行。サイト訪問やアップセルの機会が減少

この図が示すように、顧客が直接サイトを訪れて商品を選ぶ従来型のフローから、AIが購買判断を仲介するフローへの移行が進んでいる。EC事業者が直接的に顧客へ訴求できる接点は、AIへの「説明」へと置き換わりつつある。

Google Universal Cartが示す未来

Googleが2026年のI/Oで発表したUniversal Cartは、この変化を象徴する構想だ。検索結果やYouTube上で複数のECサイトの商品を横断的に比較し、Googleがカートを保持したまま決済まで完結する。顧客は個々のECサイトを訪問する必要すらなくなる。

この仕組みでは、EC事業者は販売者であることに変わりはない。しかし、商品発見から比較、購入決定に至るまでの重要なタッチポイントをGoogleが握ることになる。これは単なる広告媒体の変化ではなく、顧客接点の所有権が移行する構造的な変化だ。

ECの流通チャネルは繰り返す。AIもその一幕に過ぎない

ECの流通チャネルは繰り返す。AIもその一幕に過ぎない

一見するとAIによる顧客接点の喪失は新しい脅威に思える。しかし、ECの歴史を振り返れば、同様の構造変化は繰り返し起きてきた。変化したのは常に「商品発見の入り口」であり、顧客ロイヤルティそのものではなかった。

検索エンジンの時代

かつて顧客との関係は検索エンジンから始まった。検索結果で上位表示されることが、集客と売上の生命線だった。EC事業者はSEOに投資し、検索エンジンのアルゴリズムに適応することで成長してきた。しかし、AI Overviewsの登場により、検索結果ページ上で情報が完結するケースが増え、サイトへのクリックは減少傾向にある。

マーケットプレイスの時代

Amazonに代表されるマーケットプレイスでは、顧客関係はプラットフォームが所有する。出店者は手数料を支払い、プラットフォーム内の顧客にアクセスする。価格競争は激化し、利益率は圧迫される。ここでも「誰が顧客を握るか」の主導権はプラットフォーム側にあった。

ソーシャルメディアの時代

SNSでは、アルゴリズムに好まれるコンテンツを作れる事業者がクリックと売上を得た。しかし、プラットフォームは外部リンクを嫌い、エンゲージメントはプラットフォーム内に留めようとする。ここでも顧客との直接的な関係構築は、チャネル運営者のルールに制約されてきた。

AIエージェントの時代

そして今、AIエージェントが商品発見の新たな入り口となる。検索が関連性を、マーケットプレイスが参加を、SNSが拡散を報酬としてきたように、AIショッピングはAIシステムが価値を置くシグナルに報酬を与えるだろう。

STEP 1 検索エンジンが商品発見の主役に。SEOが集客の鍵。
STEP 2 Amazonなどマーケットプレイスが顧客を囲い込み。価格競争が激化。
STEP 3 SNSが商品発見の場に。アルゴリズム次第でリーチが変動。
STEP 4 AIエージェントが購買を代行。商品発見の場がAIに移行。

この流れの中で一貫しているのは、顧客ロイヤルティを左右するのは常に「チャネル」ではなく「事業者自身の差別化」だという事実だ。チャネルが変わっても、最終的に選ばれる理由は商品力とブランド体験にある。

適応するEC事業者が持つべき3つの視点

適応するEC事業者が持つべき3つの視点

Practical Ecommerceの記事でMoskowitz氏は、自社のアプローチについて「私たちはすべての新しいAIプラットフォームを追いかけるつもりはない」と述べている。代わりに注力するのは「自社製品の製造と、ニッチでユニークなアイテムへの集中」だという。

この姿勢には、AI時代のECにおける重要な示唆が含まれている。AIが商品発見のプロセスを支配するほど、逆説的に「AIでは代替できない価値」の重要性が増すのだ。

視点1「チャネル最適化から自社の引力強化へ」

検索エンジン対策、マーケットプレイス出店、SNS運用。これらはすべて、外部チャネルに依存した集客手法だ。AIエージェント時代においては、これらのチャネルがさらにAIの判断に置き換わる可能性が高い。

必要なのは、顧客が能動的に「この店で買いたい」と思う理由を作ることだ。オンリーワンの商品、独自のブランド世界観、有益な情報コンテンツ、特別な購買体験。これらはAIが簡単に複製できるものではない。AIは顧客の代理人であっても、ブランドのファンにはなれない。

視点2「AIに理解されるデータ設計」

一方で、AIエージェントに自社商品を正しく推薦してもらうための施策も必要だ。これは従来のSEOに近いが、最適化の対象が「検索エンジンのクローラー」から「AIエージェントの判断ロジック」に変わる点が異なる。

具体的には、商品データの構造化、商品属性の詳細な記述、独自の差別化要素の明確化が重要になる。AIが商品を比較・評価する際、価格以外の判断材料をどれだけ提供できるかが鍵を握る。

視点3「直接関係を育む仕組みづくり」

AIが購買プロセスを仲介するほど、購入後の顧客との直接的な関係構築が重要になる。メールマガジン、会員限定コンテンツ、パーソナライズされたフォローアップなど、AIの関与しないコミュニケーション回路を太く育てることが、長期的な顧客ロイヤルティの源泉となる。

一度購入した顧客が「次もこの店から直接買いたい」と思える体験設計は、AIに奪われることのないEC事業者固有の武器だ。

チャネル最適化からの転換
外部チャネル依存から、自社の商品力・ブランド力という「引力」の強化へ。
AIに理解されるデータ設計
商品データの構造化と差別化要素の明示。AIが価格以外で判断できる材料を提供する。
直接関係の育成
購入後のメールや会員限定体験など、AIを介さない顧客接点を育てる。

これら3つの視点は、いずれも短期的なチャネル対策ではなく、中長期的な事業基盤の構築に関するものだ。AIが商品発見のプロセスを変える速度に振り回されるのではなく、自社の強みを深掘りする方向へリソースを振り向ける判断が求められる。

差別化こそがAI時代の顧客ロイヤルティを守る

差別化こそがAI時代の顧客ロイヤルティを守る

Practical Ecommerceの記事は、AIエージェントがECにもたらす変化の本質を「商品発見プロセスの変化」と喝破している。顧客ロイヤルティが消滅するわけではない。むしろ、商品発見の入り口がAIに置き換わることで、どの事業者が選ばれるかの基準がより明確になる。

Moskowitz氏が「有機的な検索流入は衰退しつつある」と述べる一方で、自社製品の製造とニッチな独自商品に活路を見出しているのは示唆的だ。AIがコモディティ商品の価格比較を自動化するほど、人間の関与による「唯一無二の価値」が際立つ。

強力な商品、記憶に残るブランド、有益なコンテンツ、直接的な顧客関係、独自の購買体験。これらはいつの時代も、他者が容易に複製できない差別化要因だった。AI時代においても、その本質は変わらない。変わったのは「見つけてもらう方法」だけだ。

AIが購買の代理人となっても、なぜ顧客が特定の店舗を選ぶのか、その理由まではコモディティ化できない。EC事業者が集中すべきは、AIのアルゴリズムを追いかけることではなく、顧客が自ら選びたくなる事業であり続けることだ。

この記事のポイント

  • AIエージェントが変えるのは顧客ロイヤルティではなく、商品発見のプロセスである
  • 検索エンジン、マーケットプレイス、SNSと続いたチャネル変化の延長線上にAIがある
  • Google Universal Cartは、顧客接点の所有権がプラットフォームへ移行する象徴的事例だ
  • 適応策は「自社の引力強化」「AI向けデータ設計」「直接関係の育成」の3軸で考える
  • 独自商品とブランド体験という差別化要因は、AI時代でも複製不可能な武器であり続ける