チケットの販売、数量限定商品の発売、あるいは需要の高い商品の販売などを行っているサイト運営者であれば、一度に多くの人が殺到するとどうなるかは、すでにご存じのことでしょう。
サイトがダウンし、本物の顧客にはエラーページが表示され、ボットがひっそりとセール品を次々と買い占めてしまう。
一般的な解決策として「仮想待合室」が挙げられます。需要が急増した際、CrowdHandlerは訪問者を整然とした順番待ちリストに収容し、インフラが実際に処理できるペースに合わせて順次サイトへ誘導します。これにより、サイトは安定して稼働し続け、すべての訪問者が公平にアクセスできるようになります。
待合室がサイト全体の入り口に位置している場合は、この方法は問題なく機能します。問題は、最近のアプリではそのような構造で構築されていないケースが増えており、その多くは一見堅牢に見えるものの、実際にはそうではない方法で保護されている点にあります。
ビープ音が鳴らない杖
あのセキュリティチェックの身体検査、ご存知でしょう。警備員が体をさっと触って確認し、お互いにうなずき合って、そのまま通り抜ける。実際には何もチェックされていないのです。ほとんどのウェブアプリもこれと同じで、動きは多いけれど、実質的な接触はないのです。

なんでみんなこんな風に作るんだろう?
つまり、現代のスタックはきっぱりと二つに分かれる。
- フロントエンドがあり、通常は静的、あるいはサーバーサイドでレンダリングされます。
- 脇にAPIが一つあり、多くの場合、独自のドメイン上にあり、時にはまったく別のクラウド上に配置されていることもあります。
これが現在のデフォルトとなっています。Next.js、Nuxt、Remix、SvelteKit、Astroはいずれもこの方式を推奨しています。ヘッドレスコマースプラットフォームでは、ストアフロントとパブリックAPIがすでに分離された状態で提供され、その間の接続処理はユーザー自身に委ねられています。
フロントエンドをVercel、Netlify、またはCloudflare Pagesでホストすれば、2026年のほぼすべてのECサイトやチケット販売サイトが採用しているモデルが完成します。つまり、高速でほぼ静的なフロントエンドと、実際の処理を別の場所で担うAPIという構成です。
開発者の体験向上に最適です。ページの読み込み速度の向上にも最適です。しかし、セキュリティモデルが機能しなくなるのがここです。
なぜフロントエンドは空っぽなのか
フロントエンドは極めて軽量です。マークアップ、スクリプト、そして少しのスタイル設定だけで構成されており、インターネット上のトラフィックの半分を投げつけても微動だにしないほどです。なぜなら、システムを圧迫するような要素がほとんどないからです。
高価で、壊れやすく、まさに「ここが弱点」と言えるような処理はすべてAPI上で実行されています。したがって、静的サイトを「待合室」として機能させ、APIが独自のアドレスでクロスドメイン呼び出しに応答している場合、そもそもダウンすることのない部分を保護しつつ、実際にダウンしやすい部分を無防備なまま放置していることになります。
客は警備の行き届いた正面入口から入ってくる。トラブルは、誰も見ていない裏口から忍び込んでくる。
こうしたケースには頻繁に遭遇します。まさにこの方法で構築されたSPAや、SPA風のアプリです。正直なところ、多くの人はその実態を知りたくないでしょうし、まだ不具合が発生していないのであれば、あえて掘り下げないのも一理あります。
それを望んでいるチームは、明らかに、無害な方の半分だけを護る盾ではなく、両半分にまたがる一つの待合室を望んでいる。
そのための、十分に検証済みの方法が2つあります。
戦略 1:メインドメインを経由して API をプロキシする
もし可能であれば、最もスマートな選択肢は、APIを独立したアドレスとして扱うのを完全にやめることです。APIへの呼び出しをメインドメイン経由でルーティングし、CrowdHandlerやCloudflare、あるいはすでに導入済みのものなど、何であれ、そのすべてを1つのシールドで保護するようにしましょう。
そうすれば、軽量なフロントエンドがついにシステム全体を代表する存在となります。DDoS攻撃の試みにもキューの順番が割り当てられます。正常な処理フローを外れたAPI呼び出しにも、同様にキューの順番が割り当てられます。攻撃者は、他のユーザーと同様に、実際の顧客の後ろに並んで待つことになります。もしアーキテクチャにこうした柔軟性があるなら、まずこの手法を採用すべきです。
戦略 2:重要なエンドポイントの前にエッジワーカーを配置する
曲がらない場合は、徹底的な処置が必要だ。エッジ作業員たちは、荷重がかかる1、2カ所でAPIの正面に降り立った。
このショップでは、ほぼ常に「カートに追加」という呼びかけが行われていますが、その理由については詳しく説明しておく価値があります。これなしではチェックアウトができないため、これが明らかなゲートとなるからです。しかし、それ自体が危険な側面も持っています。なぜなら、カートに追加することしかできないユーザーが、1点も購入することなく、真剣に買い物をしている顧客の体験を台無しにしてしまう可能性があるからです。
これはチケットボットによくある手口です。在庫をカートに詰め込んで本物の購入者が手に入れられないようにし、そのアクセス権を転売したり、一度解放してまた確保するということを繰り返し行うのです。
ワーカーは、CrowdHandler API にアクセスして商品 ID に対するヒット数を集計することでこれを処理します。この際、通常その呼び出しをトリガーするページ(通常は商品詳細ページ)にアクセスしたかのように扱います。そのページへの正当なキュー登録が行われていない場合は、API 呼び出しは実行されません。
その場所にワーカーを設置することには、目立たないが重要な利点があります。それは、静的サイトではなくAPIという真のボトルネックの真上に配置されるため、オートチューンが実際に負荷がかかっている箇所を正確に把握し、現実の状況に見合ったレートでユーザーを通過させることができるということです。
ホストサイトだけを見ていては、実質的に何もしないコンポーネントをじっと見つめているだけであり、それは目隠しをしたままチューニングをしているようなものです。さらに、そのホストサイトの処理はごくわずかであるため、統合におけるホストサイト側の作業はごく単純なものにとどまります。つまり、必要に応じてユーザーを脇へ移動させるためのわずかなJavaScriptを記述するだけで済み、実際の検証や処理のペース調整はすべてAPI側で行われるのです。
すべての部品がしっかりと固定されて初めて、この罠は機能する
絶対に省いてはいけないルールが一つあります。それは、多くの人が見落としがちな部分なのですが、誰かがチェックアウトした瞬間にセッションを終了させることです。
訪問者が支払いを完了すると、そのセッションは終了しなければなりません。そのため、そのセッションを再利用して2回目の取引を行うことはできません。セッションを存続させたままにしておくと、高度なボットはキューに正確に1回だけ登録した後、無限ループで取引を繰り返してしまいます。このルールを厳格に適用すれば、その選択肢を排除することになり、攻撃者は毎回、キューを経由し、商品ページを経由し、検証済みの呼び出しを経由して、ごく普通の「ハッピーパス」の購入者と同じように振る舞わざるを得なくなります。
この罠は、すべての部品がしっかりと固定されて初めて獲物を捕らえることができる。たった一つの部品が緩んでいるだけで、罠は空を捉えるだけになってしまう。
アプリを書き直す必要はありません
範囲を明確にするために申し上げますが、これは再構築ではありません。主に、私たちがすでに開発・保守しているエッジワーカーを読み込み、調整する作業であり、以下のバージョンに対応したものが用意されています:
- AWS CloudFront
- Cloudflare
- Netlify
- アカマイ
1つか2つのエンドポイントを保護するだけで、コアコードには一切手を加えません。私たちはこれまで、数多くのスタックを利用する数多くの顧客に対して、この手法を密かに実践してきました。そして、Shopifyとの統合機能の裏側でも、同じ仕組みが静かに稼働しています。
これについて話し合う価値があるとき
もし心のどこかで、「自分の環境は、口に出して言うほどには安全ではない」と囁き続けているなら、ぜひ私たちにご相談ください。従来のキュー方式が過剰に感じられる場合でも、この方法なら、アプリの本当に脆弱な部分にのみ、洗練されたレート制限やDDoS対策を組み込むことができます。決して動じることのない部分には、そのような対策を施す必要はありません。
セキュリティをさらに強化したいですか?CrowdHandlerに無料で登録しましょう。