世界を動かす技術を、日本語で。

サブスクリプションボンバリングとその対策方法

概要

  • Suga で新規ユーザーの不審なサインアップを発見
  • Subscription bombing (サブスクリプションボミング)という攻撃手法の説明
  • 攻撃の発見から調査、対応策の実施までの流れ
  • Cloudflare Turnstile や認証フローの改善による対策
  • 今後の教訓と再発防止策

Sugaで発生した不審な新規ユーザー登録

  • 数週間前、 新規ユーザー が登録後に何も操作せず放置される事例を複数発見
  • 通常は登録後すぐに 組織やプロジェクト作成 などのアクションがあるため、異常値として目立つ
  • 新規ユーザー名が ランダム文字列 (例: PfVQXvYTXjwSbEeJBjXYy)で構成されていた
  • Resend (メールサービス)で確認すると、実在するメールアドレス宛にウェルカムメールが正常に送信
  • 怪しいと感じ、攻撃の可能性を調査開始

サブスクリプションボミングとは

  • Subscription bombing は、ボットが被害者のメールアドレスを使い、無数のウェブサイトでサインアップを行う攻撃手法
  • 目的はアカウント乗っ取りではなく、 被害者の受信箱を大量のノイズメールで埋め尽くすこと
  • 攻撃者はその隙に、 銀行口座のパスワードリセットクレジットカード申込 などを実行
  • 本当に重要な通知メールがノイズに埋もれ、被害者が気づきにくくなる
  • 大量のサイトが メールアドレス検証なしでメール送信 していることが原因

攻撃パターンと検知の経緯

  • 3月12日に 最初の異常なサインアップ を検知、その後2日間でさらに2〜3件/日発生
  • 当初は ペンテスト(脆弱性検証) の可能性を疑うも、同様のパターンが継続
  • PostHog で「パスワードを忘れた」ページへのアクセスが異常に多いことを確認
  • ボットは本物のメールアドレス+ランダム名で登録し、60秒以内にパスワードリセットを要求
  • 被害者には「メールアドレス確認」「ウェルカム」「パスワードリセット」の3通が1分以内に届く
  • ボットはフォーム入力時に 一文字ずつ不自然な間隔でタイプ、人間らしさを装うが挙動が均一
  • アクセス元国と時間帯に相関がなく、 世界中から均等にアクセス されていた

サブスクリプションボミングの特徴

  • 一度に大量リクエストやサーバー負荷増加はなし、 1〜2件/時の低頻度
  • 国や時間帯の分布が不自然、通常ユーザーとは異なるトラフィックパターン
  • レートリミット (一定時間あたりのリクエスト制限)が無効、しきい値以下で活動
  • サイト運営者側への直接的な被害は少なく、 被害は主にメールアドレスの持ち主

被害の実態とサイト運営者の責任

  • 被害者は 一晩で200通以上 の不要メールを受信し、重要な通知を見逃すリスク
  • サインアップフォームが 未検証のメールアドレスにメールを送る仕様 は攻撃の温床
  • サイト運営者が被害を認識しづらく、 対応が後回しになりがち
  • 実際には ユーザーデータの汚染 や、サービスがハラスメントの片棒を担ぐことになる

実施した対策

  • ファイアウォール強化 でボット検知を厳格化、ただしAPIの正規トラフィックも考慮し調整
  • 6時間運用で2件のすり抜けを確認、 完全な防御には至らず
  • Cloudflare Turnstile (CAPTCHA代替)を導入し、ユーザー体験を損なわずにボット排除
    • Better Auth のCAPTCHAプラグインで簡単に実装
    • サインアップ・サインイン・パスワードリセット全ページに @marsidev/react-turnstile を追加
    • トークン取得まで送信ボタンを非活性化
  • Turnstile導入後、 ボットのサインアップは完全に停止
  • 今後のダメージ最小化のため、 メールは認証済みユーザーのみに送信
    • 検証前は 確認メールのみ 送信、ウェルカムやアップデート通知は認証後
    • GoogleやGitHub認証の場合は即時ウェルカムメール送信(メールアドレスが既に検証済み)

今後の教訓とまとめ

  • 1〜2件/時の異常サインアップでも 見逃さず、迅速に対応
  • 被害者への直接連絡は控え、 根本的な再発防止策 を優先
  • 攻撃パターンの早期検知のためのレポート強化 を追加
  • 今回の対応は妥当かつ迅速だったが、 初めから対策を講じるべきだった と反省
  • サービス運営者は ユーザーの安全と信頼性 を最優先に考えるべき教訓

Hackerたちの意見

問題はあるけど、その解決策は本当に嫌だな。セキュリティに問題があるウェブサイトをCloudflareのTurnstileの後ろに置くのは、コード署名を強制するのと同じだよ。うまくいく時もあれば、そうでない時もあるし、その間に一つの法的な実体に権力が集中して、正当なユーザーをイライラさせるだけだ。インターネットは核戦争にも耐えられるように設計されているけど、こういうアプローチが広まると、少しずつその姿を失っていく。去年のus-east1やCloudflareの複数の障害があったにもかかわらず、私たちはこれを見て見ぬふりをしているか、むしろ良いことだと合理化している。だって、もしダウンしたら、競合も同じようにダウンするからね…。

正直、CloudFlareのビジネスはすごく好きだよ。ベンダーロックインもないし、本当に良い製品だと思う。もし彼らが後で悪いことをし始めたら、私がやるべきことは、ネームサーバーを競合に変えるだけで、私のウェブサイトのユーザーも気づかないだろうね。

じゃあ、何もしないのが解決策なの?Cloudflareは多くのことに対して素晴らしい解決策だよ。インターネットは核戦争に耐えられるように設計されているけど、今のインターネットの敵意のレベルには対応していないんだ。

それで、あなたの解決策は「インターネットの全員が善人だと思う」ってこと?これを大規模にどう解決するつもりなの?

これを「既知のセキュリティ問題」とは呼ばないかな。サインアップやパスワード再設定ページに固有の問題だと思う。あと、Turnstileを目に見えないモードで追加したから、ユーザーがイライラすることはないと思うよ。認証フローの特定のページにだけ適用されるし、すでにサインインしてるユーザーには影響ないから。Redditみたいにサイト全体のボット保護を使って、インタースティシャルキャプチャページを作るのとは全然違う。

未確認ユーザーには1通のメールしか送らないようにフローが更新されたから、キャプチャを導入する前にできる限りの対策はされてると思うよ。

私も似たような問題があって、代替案を評価したけど、残念ながら十分に機能するものはなかったよ。信頼性のあるボット防止をどう実装するのがいいと思う?今のところ、LLMはCAPTCHAを解くのが人間よりも得意だからね。

あなたのコメントに完全に同意だわ。ユーザーが何かしら製品に関わるまで、ウェルカムメールを送るのを待つってのはどう? それで、3ヶ月以上何のアクションもないアカウントは「誤って作成された」として削除しちゃえばいいんじゃない?

私は絶対にビッグテックのゲートキーパーや無駄なCAPTCHAを使うのは拒否するよ(どんなに高度なボットでも、CAPTCHAを回避できるからね)。私たちのスタートアップでは、名前をシンプルなLLMフィルターに通して解決したんだ。もし名前が「Px2846skxojw」みたいな意味不明なものであれば、サインアップをブロックするだけ。意外と効果があったよ。もちろん、ボットが何をしているか分かっていれば簡単に回避できるけど、ボットは簡単なターゲットを探しているから、インターネット上に十分な「雰囲気コードされたクソターゲット」があれば、わざわざ注意深く設計されたアプリを回避しようとはしないよ。

いいね。

高エントロピー文字列を検出するための確立されたアルゴリズムがあるのに、LLMを使うのは過剰な気がする。

それだと、追跡されたくない正当なユーザーもブロックしちゃうよね。iCloudの「メールを隠す」サービスを使ってる人たちとか。

それで、君の解決策は、単一のフィールドに対して基本的なルックアップテーブルを使って回避できるブラックボックスを導入することなの?CAPTCHAは、すべての状況で100%機能することを目的にしてないし、唯一のセキュリティソリューションでもないんだ。怠け者のスパマーや低レベルの攻撃をブロックするためのものだけど、興味とリソースがあれば誰でもCAPTCHAを回避できる。確かに「AI」の普及で、これが安くてアクセスしやすくなってきてるけど、CAPTCHAが本質的に無駄だってわけじゃない。これは永遠のいたちごっこの一部なんだよ。LLMのように、特定の信号が疑わしい行動を示す確率に依存してる。Turnstileのような洗練されたものは、多くのデータを分析して、擬似ランダムなキーボード入力を検出するためにLLMを使ってるから、君の特注の解決策よりもずっと効果的だと思う。完璧ではないし、誤検知もあるけど、これは残念ながら現代のインターネットで正当なユーザーにサービスを提供するためにみんなが支払わなきゃいけない代償なんだ。これらのサービスに多くのセンシティブなデータが与えられて、ユーザーの追跡や広告に悪用される可能性があるのは心配だけど、自己ホスティングできるOSSの代替案もあるから、それを使うのもいいかもね。

正直、これってあんまり良い解決策じゃない気がする。なんでこれにLLMを使うの?正当なランダムな文字列をユーザー名にしたい場合はどうするの?

無駄なCAPTCHA(十分に高度なボットはどんなCAPTCHAでも回避できるしね)。うちのスタートアップではこれを(…)で解決したよ。もちろん、ボットが何をしてるか分かってれば簡単に回避できるから、君自身が認めてる通り、その解決策は「十分に高度なボット」の問題を解決してないよね。

うちのスタートアップでは、名前をシンプルなLLMフィルターに通して解決したよ - 名前がPx2846skxojwみたいな意味不明なものであれば、サインアップをブロックするんだ。「LLMが君の名前を意味不明だと思ってる」ってのが新しい「君の名前には無効な文字が含まれてはいけない」にならないことを願ってる。

2ヶ月前にこんな攻撃を受けたことがあるんだ。アカウントごとに異なるメールアドレスを使っていて(例えば product@example.com)、Gitのコミット用には別のアドレス(git@example.com)を使ってる。攻撃を受けたのは後者で、12時間以内に500通のメールが来たよ。幸い、Gitのアドレスには誰からもメールが来るとは思ってなかったから、フィルターをかけて別のフォルダーに送るようにした。12時間後にはメールのペースが止まって、その後は同じドメインの架空のアドレスにアメリカの政治に関するメールが届くようになった(ワイルドカードエイリアスが有効になってる)。誰かがフラストレーションを発散しようとしてたのかもしれない。これが続いたのは約30分だけで、攻撃者は諦めたみたい。奇妙なことに、攻撃中に攻撃者が隠そうとしていたかもしれないメールは一通も受け取らなかった。最初にこの攻撃の目的が何だったのか、混乱してる。

最近、私も同じことがあったよ。メールの活動を隠してるわけじゃなくて、3000通以上のスパムメールをチェックした。受信トレイに転送ルールが追加されてないか確認して、SIMスワップに対する保護も追加した方がいいよ。私の場合、アカウントは侵害されなかったけど、新しいクレジットカードを開設しようとされたから、クレジットレポートを確認する価値はあると思う。

最近、別のタイプのサブスクリプションボム攻撃を受けたんだ。ハッカーが私たちの「クレジットカードを変更する」フォームを使って、何千ものクレジットカードのリストを「クリーニング」して、どれが通るかを確認してた。攻撃は真夜中から朝の7時まで行われたから、人間は見てなかった。IPはリクエストごとに回転してたから、レートリミッターも捕まえられなかった。サインアップフォームとすべてのクレジットカードフォームにCloudflareのTurnstileをインストールしてたけど、すべてのリクエストはTurnstileで検証されてた。私たちは「見えない」設定で運用していて、事件の後に「推奨」設定に戻したから、もしかしたらこの緩い設定が原因かもしれない。OPと同じように、私たちのウェブサイトはユーザーの手間を減らすためにメールの検証を必要としなかったし、特にメールをほとんど送らないからね。こんな形でやられるとは思ってもみなかった。彼が試したクレジットカードはすべて、CCが有効であることの確認として$1が請求され、その後すぐに返金された。もしCCがこの$1の取引を承認しなかったらエラーになったんだけど、それを使ってた。約2000件のリクエストのうち10%が通ったよ。確認メールを追加するだけじゃダメだね。ハッカーは、必要なかったのに、使い捨てのメールアドレスサービスを使ってた。これは大問題だよ。決済処理業者は、こんなことを許すとあなたを禁止することがあるからね。

痛いね。一つのアカウントにつき、クレジットカードの変更は一回だけ?これは、そういうイベントがあった後にしか導入されない監視レベルの一つだよね。例えば、全システムの分析 - 7時間でカード変更機能が何千回も使われるのは、ものすごい赤信号だよ。

そうですね、やるべきことは、通過したカードについてカード発行会社に通知することです。そうすれば、盗まれたカードとしてマークしてもらえます。それは確かにハッカーを喜ばせるでしょうし、再度やる気を失わせるでしょうね :)

$1の認証チャージパターンは、カードテスト攻撃にはすごく一般的だよ。Turnstileを超えて役立つのは、Stripe Radarのルールだね。成功した支払いがないIPからの$2未満のチャージをブロックしたり、短時間に複数のカード試行があったアカウントをフラグすることができる。完璧ではないけど、人間のレビューが始まる前に一層の防御ができるよ。

Cloudflareや他のアンチボットサービスは、回避する意志や知識がない人には効果的だけど、JSは逆コンパイルできるし、検出に使われるデータポイントも見えるからね。何でも偽装できるし、人間の行動に見えるようにできる。もし全てが失敗したら、AIにアウトソースするだけだよ - いつもインディアンだね :D

うちはサイレントブロックを導入してこれを解決したよ。システムが異常な行動(例えば、ユーザーごとの支払い試行が多すぎる場合)に気づくと、その支払い試行をプロバイダーに送らなくなるんだ。代わりに1、2秒待ってから、単に「支払いが拒否されました」と表示するだけ。ほとんどの攻撃者はブロックされてることに気づかず、全てのクレジットカードがダメだと思ってる。

$1の認証チャージパターンがあるから、支払いプロセッサーは君をカードテストを助長してると見なすんだよ、たとえ君が被害者でも。実際、Stripeはこれでアカウントを停止したこともある。Turnstileのインビジブルモードは、基本的にログを取るだけで、ほとんど何も挑戦しないからね。苦い教訓だと思うよ。

いつも同じユーザー名やログインを使ってたのかな?

今の時代に理解できないことの一つは、銀行のような機密データを扱う企業が、ユーザーがメールアドレスを入力した後に確認を求めないことだよ。私のメールアドレスは残念ながら非常に一般的で、間違って入力されやすいんだ。毎日のように高額なバケーションホテルの注文確認や、銀行振込の確認メールが届く。これは、送信元の企業がユーザーに正しいメールアドレスを入力したか確認しなかったからなんだ。正当なメールだけど、私と同じ名前の別の人に宛てられてることが多くて、その人が間違ってメールアドレスを入力しただけなんだよね。こういう企業で働いてる開発者が、簡単なメール確認を実装しようと思わないのが信じられない。

メール確認をすることで摩擦が生まれるからです。みんな、プライベートデータの漏洩リスクがあっても、摩擦を少なくすることを最優先にしています。間違ってメールを入力したユーザーを責めることができるからです。

これは意図的です。メール確認は摩擦を生むので、ユーザーに購入が本当に必要か再考する機会を与えます。これはビジネスにとって悪いことで、彼らは衝動的に購入してほしいと思っています。また、最近はオートフィル機能があるので、ほとんどの人は正しくメールを入力します。だから、確認メールを送らないのは、スムーズな体験を最適化しているということです。

メールの検証なしにアカウントを作成するのが合法だなんて、驚きです。検証されるまで、アカウント確認以外のメールを送るのは、罰金を科すべきだと思います。検証メールには「二度と連絡しないで」というボタンがあって、ワンクリックで機能し、もし機能しなければ大きな罰金が科されるべきです。

確かに、メールは往復が早いですが、郵便の確認を求められることはありませんよね。どこでも購入を確認しなければならないのはかなり面倒だと思いますし、オンラインで全ての商人にサインアップしたくないのと同じです。ゲストとして購入させて、OTPを入力する必要はないようにしてほしいです。

それは本当に狂っていますね。私も同じ状況で、住宅ローンの申請書や警察の詳細、警察の仕事の応募、マッサージの領収書など、色々なものを受け取っています。多くは顧客データの重要な漏洩と見なされるでしょう。技術系で活動している誰かと同じ名前を持っているため、機密と思われる創業者レベルのメールが私に送られてきたこともあります。小規模なグループを運営している明らかに実在の人物からのものには返信したり報告したりしますが、大企業に対しては、企業メールに素早く返信する以外にほとんどできることはありません。この「悪意のない間違った人の同名エラー」という特定の問題に対して何かを構築するための高レベルの議論があればいいのにと思います。Googleならできると思いますが、彼らが気にする規模で収益化できないからだと思います。メールのモノリスの外でこれを機能させる方法を考えられませんでした。もしアイデアがある人がいれば、ぜひ教えてほしいです。

私は非常に初期のGmailアドレスを持っています。とても一般的な名前に2文字の追加です。今ではほとんど使えません。請求書、サブスクリプション、誰かの不動産取引に関する重要な書類など、全て私の受信箱に入ってきます。約20〜30のGoogleアカウントがあり、そこに私がバックアップメールアドレスとして登録されています。その人たちがパスワードを忘れたり、アカウントを使わなくなったりすると、通知メールが届きます。私の側での確認は必要ありません。新しいアドレスを設定しましたが、これが問題になる可能性は低いです。ただ、古いアドレスから移行するのは簡単ではありません…

よく言われることだけど、最適な詐欺の量はゼロじゃないんだよね。 https://www.bitsaboutmoney.com/archive/optimal-amount-of-fra... 彼らは、気軽に物を買えるように最適化してるんだ。

私はメールセキュリティ会社のxorlabで働いています。そこで同僚たちと一緒に、顧客から見られた実際のサブスクリプションやメールボンピングの波を徹底的に分析しました。分析した攻撃からの興味深い追加情報をいくつか紹介しますね。

  • メールボンピングサービスが存在していて、10,000クレジットが10ドルで買え、1時間に2,000通以上のメールを簡単にターゲットの受信箱に送信できます。
  • ほとんどのメールボンピング攻撃は朝の8時から10時の間に始まります。
  • 最も多い攻撃日は金曜日です。

ニュースレター会社として、私たちはこれに10年以上取り組んできたよ。ちゃんとしたことをしてダブルオプトインを採用して、登録時にサブスクライバーにメールを送ってるからね。数年前までは、IPの評判がこれに対する良い防御策だった。悪質なトラフィックはほとんど特定の国のIPアドレスや、ブロックできるデータセンターのIPから来てたんだ。今はVPNの普及でそれが通用しなくなって、正当なユーザーも低評価のIPから来ているように見える。ターンスタイルは通常の形では合理的な解決策だけど、「見えない」オプションはまだ多くの人を通しちゃう。驚くことに、「webdriver」の使用を探すのも効果的なんだ。webdriverのフィンガープリンツを取り除くのは簡単なのに、ほとんどの自動化された試みはそれを気にしないみたい。もっとステップを増やしたり、ハニーポット(すぐに短期IPバンをかける)を使ったりするのも効果があるよ。いろんな防御策を積み重ねるゲームみたいなもんだね、「スイスチーズモデル」って感じ。

私のエージェントのYouTube番組がこの話を取り上げて、エピソードを作ったよ。見てみて! -- https://www.youtube.com/watch?v=hd6a7pvIyts

予想通り、これはひどいね。

これがメールアドレス提供サービス側の問題かはわからないけど、メール自体の根本的な問題だよね。メールは進化するべきだし、最終的には消えるべきだと思う。

なるほど、これがCommunickでのランダムなサインアップの理由か。パターンが私が見てるのとぴったり合ってる(1時間に3~4件のサインアップ、変なユーザー名、たくさんの「.」が入ったgmailやhotmailアドレス)。私の場合、無駄なデータを集めないことにこだわってるから、緩和策があるんだ。メールアドレスはオプションで、すでに有料のサブスクライバーの場合にしか使わないし。もしかしたら、サインアップフォームから完全に削除して、ハニーポットとして使うべきかも。