SMS 認証のベストプラクティス:破綻しない OTP フローの設計

Jan 16, 2026

SMS ワンタイムパスコードはインターネット上で最も広く導入されている第二要素であり、同時に今なお広く使われている中で最も弱いものでもあります。NIST は 2016 年以降 SMS を制限付き認証手段として推奨しない立場を取っていますが、それでもどこにでもあるのは、ほぼすべてのユーザーがすでに持っている唯一の要素だからです。

OTP フローを構築・運用する立場での実務的な問いは「SMS が理想的かどうか」ではありません。「どう運用すれば、起きる失敗が自分で選んだものになるか」です。この記事は防御的な設計を扱うものであり、誰かの保護を回避する話ではありません。

脅威モデルの要点

漠然と「不正」に備えるのではなく、次の具体的な項目に対して設計してください。

  • SIM スワップと番号乗っ取き —— 攻撃者がキャリアを説得し、被害者の番号を自分の端末へ移します。OTP フロー側でこれを検知することはできず、直近性のシグナルとステップアップ検証だけが効きます。
  • リアルタイムのフィッシング中継 —— プロキシサイトが被害者からコードを取得し、有効期間内に再送します。今日の SMS OTP に対する主流の攻撃であり、コードの寿命が主な対抗手段です。
  • 端末侵害によるコード傍受 —— 通知プレビュー、SMS 権限を持つ悪意あるアプリ、端末間で同期されたメッセージ履歴。
  • 総当たりと再利用 —— 6 桁コードの推測、あるいは取得済みコードの使い回し。
  • 列挙 —— OTP エンドポイントを使い、どの電話番号にアカウントがあるかを探る行為。
  • SMS ポンピング(課金詐欺) —— 攻撃者が自らの収益になるプレミアムレート帯へ送信を誘発します。これは直接あなたの費用を焼くもので、請求書が来るまで見過ごされがちです。

実際に効くレート制限

多くのレート制限が機能しないのは、1 つの軸にしか適用されておらず、攻撃者が他の軸を回すからです。

複数のキーで同時に制限する。 電話番号ごと、アカウントごと、IP ごと、デバイスフィンガープリントごと、そして宛先国ごとの全体上限。IP を回す攻撃者も番号あたりの上限に当たり、番号を回す攻撃者は IP あたりの上限に当たります。

硬い壁ではなく段階的な遅延を。 30 秒、2 分、10 分と増えていくバックオフは、自動化攻撃のスループットを落としつつ、単に入力を間違えただけの正規ユーザーを締め出しません。

宛先国ごとに上限を設ける。 SMS ポンピングは特定の番号帯に集中します。国別の送信上限を設け、接近時にアラートを出せば、請求が膨らむ前に捕捉できます。

量ではなく異常時に摩擦を足す。 すべての要求に CAPTCHA を出せば、ユーザーはそれを無視するよう訓練されます。リスクスコアが閾値を超えたときだけ出すことで、そのシグナル価値が保たれます。

送信の上限と検証の上限を分ける。 別の攻撃だからです。送信は費用が発生しポンピングを可能にし、検証試行は総当たりです。許可する送信回数とは独立に、少数回(5 回が一般的)の検証失敗でコードをロックしてください。

コードの寿命、エントロピー、束縛

寿命は短く。 時間単位ではなく分単位です。このウィンドウはリアルタイム中継フィッシングに対する主要な防御です。5 分で失効するコードは、攻撃者に 5 分を与えます。短いほど安全ですが、2 分を切るあたりから低速なキャリア経路のユーザーによるサポート負荷が生じ始めます。

単回使用、再発行で無効化。 新しいコードを要求されたら、古いコードは即座に失効させます。以前のコードを有効なまま残すのは、利点なしに攻撃面を増やすだけです。

最低 6 桁。 5 回の試行上限と組み合わせれば、6 桁で総当たりは現実的でなくなります。4 桁は、緩い試行上限のもとでは推測可能です。

コードをコンテキストに束縛する。 何のために発行されたかを保存し、使用時に検証してください。

  • アクション(サインアップ / ログイン / パスワードリセット / 決済確認)
  • 要求元のセッションまたはデバイス
  • E.164 に正規化した電話番号と地域

中でもアクションへの束縛が最も重要です。メールアドレス変更の確認用に発行されたコードが、送金の承認に使えてはいけません。

本文にコードの用途を書く。 「123456 は 400 ドルの送金を確認するためのコードです」と書けば、フィッシングの被害者が違和感に気づく余地が生まれます。数字 6 桁だけでは、その余地はありません。

配信 UX:サポート問い合わせの発生源

ユーザーにとって OTP は二値です。動いたか、この製品は壊れているか。そしてその印象の大半は、配信ではなく画面が作っています。

待ち時間の期待値を示す。 「コードは通常 30 秒以内に届きます」の一文が再送スパイラルを防ぎます。再送スパイラル自体がスロットリングを招き、配信を実際に悪化させます。

再送はカウントダウン付きで抑制する。 タイマー付きのグレーアウトしたボタンが、ユーザー自身を最も傷つける行動を止めます。

エラーでアカウントの存否を漏らさない。 「この番号のアカウントが存在する場合、コードを送信しました」が標準的な文面です。「アカウントなし」と「送信済み」を区別すると、攻撃者に無料の列挙手段を与えることになります。

貼り付けと自動入力に対応する。 入力欄に autocomplete="one-time-code" を設定し、本文はオリジン束縛の WebOTP 形式にします。6 個の独立したボックスに分割したうえ貼り付けを拒否する実装は、ユーザビリティであると同時にアクセシビリティの問題です。

代替経路を用意する。 音声通話、メール、あるいは認証アプリ登録への導線。特定のキャリアと地域の組み合わせでは配信が静かに失敗することがあり、代替のないユーザーは単に離脱します。

完全な番号は決して表示しない。 確認画面では末尾 2〜4 桁のみをマスク表示にします。

地域とキャリアで計測する

集計された配信率は、見つける価値のある問題をすべて覆い隠す数字です。

送信成功、配信レシート、認証完了を宛先国とキャリア別に分けて追跡してください。上流のルーティング変更は、全体平均がほとんど動かないまま特定の地域だけが崩れる形で現れます。アラートは全体値ではなく、各セグメント自身のベースラインからの乖離で出します。

もう 1 つ追跡に値するのが認証所要時間の分布です。p95 の上昇は、経路が完全に落ちる前の劣化を示していることが多いです。

データ保持:持たない

サポート運用とインシデント調査に必要なものだけを保持します。

  • 持つべきもの: タイムスタンプ、配信ステータス、宛先国、番号のハッシュまたは切り詰めた参照、認証結果の監査証跡。
  • 持つべきでないもの: 認証ウィンドウを超えて、有効なコードを含む本文を保持すること。運用上の理由はなく、侵害時には負債にしかなりません。
  • 保存時はコードをハッシュ化する。 データベースやログに平文で残るコードは不要な露出です。存在した事実を記録し、値は決して記録しないでください。
  • 実際に TTL を設定する。 無期限に残る認証レコードは、意図していなかった電話番号データセットを勝手に育てていきます。

USPhoneGen の扱い:プライバシーポリシー · 利用規約

仮想番号を使うユーザー

一定数のユーザーは仮想番号やオンライン受信の番号で認証します。プライバシーのため、テストのため、あるいは海外にいるためです。システムは安全性を保ちつつ、彼らを初めから疑わしい存在として扱うべきではありません。

ライン種別のポリシーを意図的に決め、明示する。 VoIP 番号をブロックするなら、エラーメッセージにそう書いてください。決定論的なポリシー拒否に対して漠然と「認証に失敗しました」と返すと、絶対に成功しない再試行ループにユーザーを追い込み、最終的にサポートキューに現れます。

キャリア遅延を罰しない。 地域差は正常です。タイムアウトと再試行のロジックは、低速な経路を不正シグナルとしてではなく、想定内として扱うべきです。

ライン種別は複数の入力のうちの 1 つとして重み付けする。 番号履歴、IP レピュテーション、デバイスシグナル、試行頻度もそれぞれ情報を持ちます。一律の VoIP ブロックは鈍器であり、決済フローでは正しく、ニュースレターではたいてい誤りです。

重要な瞬間に再認証し、常時ではない。 出金や認証情報の変更時に再確認するのは相応です。休眠アカウントを再チェックして締め出すのは、何もしていないユーザーを失う方法です。

ライン種別の分類の仕組みと、それがユーザーからの拒否報告を生む理由:Non-VoIP と VoIP 番号

SMS からの出口を設計する

SMS OTP は下限であって到達点ではありません。ユーザーを移行させられるよう設計してください。

  • SMS と並行して TOTP やパスキーを提供し、登録時ではなくログイン成功後に登録を促します。サインアップでの摩擦追加はコンバージョンを損ないます。
  • SMS がより強い要素を暗黙に上書きしないようにする。 パスキーを持つユーザーに無条件の SMS フォールバックを許せば、そのユーザーのセキュリティは SMS 相当まで下がります。
  • 番号変更を高リスクイベントとして扱う。 既存要素を要求し、新しい番号が復旧手段として使えるようになるまでクーリング期間を設けます。

よくある質問

OTP の有効期間はどれくらいにすべきですか?
2〜10 分、既定値としては 5 分が妥当です。短いほど中継フィッシングの窓が狭まりますが、短すぎると低速経路のユーザーで失敗が増えます。

検証の試行回数は何回まで許すべきですか?
コードあたり 5 回程度で無効化し、新規送信を要求します。分散型の推測を捉えるため、アカウント単位の失敗回数も別途追跡してください。

VoIP 番号はブロックすべきですか?
そのアカウントに何ができるか次第です。決済や KYC 義務下ならブロックすべきです。一般消費者向け製品では一律ブロックは正規ユーザーを失います。ライン種別は他のシグナルと併せて重み付けしてください。

最も価値の高い単一の対策は?
国別送信上限を備えた多次元のレート制限です。総当たり、列挙、課金詐欺に同時に効きます。

2026 年に SMS OTP を導入する価値はありますか?
他に何も持たないユーザーのための基準線としては、あります。提供する最強の要素としては、ありません。TOTP やパスキーへの導線とセットで出してください。

SMS ポンピングはどう防ぎますか?
国別の送信上限とアラート、提供対象外の宛先帯のブロック、新規アカウントへの段階的な摩擦です。国別の「認証済みユーザー 1 人あたりコスト」を監視してください。ポンピングはそこに最初に現れます。

参考資料

関連記事

管理者

管理者

SMS 認証のベストプラクティス:破綻しない OTP フローの設計 | USPhoneGen