Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】SMS OTP API Ownership: 6 Rate Limit Rules for SaaS Login Recovery

2026年09月29日に「Dev.to」が公開したITニュース「SMS OTP API Ownership: 6 Rate Limit Rules for SaaS Login Recovery」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

SaaSのログイン回復(パスワードリセット)でSMS認証を使う際、アプリケーションが秘密生成や有効期限などセキュリティに関わる部分を管理すべきだ。メッセージ配信は伝達に徹し、役割を明確に分けることで、システムは一貫性を保ち、より安全な運用が可能になる。

ITニュース解説

SaaS(Software as a Service)のようなインターネットサービスで、もしパスワードを忘れてしまった時、メールやSMSでワンタイムパスワード(OTP)やパスワードリセットのリンクを受け取ることがある。この機能は「ログインリカバリ」と呼ばれ、サービスの利用者にとって非常に重要な回復手段だが、実はその裏側では、セキュリティと利便性を両立させるための複雑な設計が求められている。特に、SMSでOTPを送信するAPI(Application Programming Interface)を使う場合、どこまでをサービス提供側のシステム(アプリケーション)が管理し、どこからをメッセージ送信サービス(トランスポート層)に任せるべきか、その「責任の境界線」を明確にすることが極めて重要だ。

この境界線があいまいだと、セキュリティ上の問題や、ユーザー体験の一貫性の欠如、さらには運用上の手間が増える原因となる。例えば、メールのテンプレートには「パスワードリセットリンクは10分で期限切れになります」と書かれているのに、SMSのテンプレートには「すぐに期限切れになります」とだけ書かれていたり、実際にデータベースでは30分も有効だったりするような状況は避けなければならない。このような矛盾は、利用者にとって混乱を招き、攻撃者にとってはシステムの脆弱性を突き止めるヒントにもなりかねない。

では、具体的にサービス提供側のアプリケーションが何を責任持って管理すべきか。記事では主に以下の6つの点を挙げている。第一に「リセットの意図」、これはパスワードをリセットするというユーザーの明確な意思だ。第二に「秘密情報(シークレット)の生成」、これはパスワードリセット用のワンタイムコードやリンクのトークンといった、一度しか使えない秘密の文字列を生成することだ。第三に「有効期限」、生成された秘密情報がいつまで有効かを決める。第四に「ワンタイム消費」、秘密情報が一度使われたら、それ以降は無効になるように管理する。第五に「テンプレート変数」、メッセージに表示される「あなたのリセットコードは○○です」といった、動的に変わる情報を管理する。最後に「メッセージのユーザーが理解する意味」、例えば「このリンクは10分で期限切れになります」といった、セキュリティに関わる重要なメッセージの内容そのものを指す。

これに対し、メッセージ送信サービス(トランスポート層)は、メッセージの宛先(電話番号やメールアドレス)の書式、メッセージ送信サービス自体の認証、実際にメッセージを送信する処理、メッセージの送信状況(成功、失敗など)の正規化された通知、そしてメッセージ送信サービス固有の送信量制限(スロットリング)といった、純粋なメッセージの「配信」に関わる技術的な部分に責任を持つべきだ。

この役割分担を明確にすることで、アプリケーションはセキュリティに関わる核となる部分を完全に制御できるようになる。例えば、パスワードリセットの秘密情報はアプリケーションのサーバーで生成され、そのハッシュ値(元の秘密情報から一方向に変換された値で、元の秘密情報は推測できない)だけがデータベースに保存される。そして、秘密情報の有効期限もアプリケーションが厳密に管理する。メッセージが遅延したり、複数回届いたり、あるいは別のチャネル(メールからSMSへなど)で届いたりしても、それによって秘密情報の有効期限が延長されたり、二重に有効なリセット経路が作成されたりするような事態は防げる。

具体的なシステムの動作は次のようになる。まず、ユーザーからパスワードリセットのリクエストが送られると、アプリケーションは秘密情報を生成し、それをデータベースに記録する。この際、同時にメッセージを送信するよう指示する情報を「キュー」と呼ばれる一時的な保存場所に置く。キューから情報を取り出したワーカー(メッセージ処理担当のプログラム)は、アプリケーションが管理するテンプレートを使ってメッセージの内容を生成し、それをメッセージ送信サービスのアダプター(連携用のプログラム)を通じて実際に送信する。ユーザーが受け取った秘密情報を使ってパスワードを変更しようとする際も、アプリケーションはデータベースに保存された情報と照合し、その秘密情報が有効期限内で、かつまだ使われていない場合にのみ、パスワードの変更を許可する。

このように設計することで、例えばSMSプロバイダーのテンプレート機能を使ってメッセージを作成した場合に起こりがちな、「プロバイダーのテンプレートにはリセットリンクの変数名がreset_linkと書かれているが、アプリケーションからはreset_urlという変数名でデータが送られてしまう」といった不一致を防ぐことができる。テンプレートの内容、特に有効期限やリンクに関する記述は、コードと同じように厳密にレビューされ、バージョン管理されるべきであり、これはアプリケーションの責任範囲に含めることが望ましい。

リトライ(再送信)とレート制限(送信量制限)の扱いも重要だ。「リセットの意図を作成する」ことと「メッセージの配信を試みる」ことは、別々の操作として扱う。リクエストを受け付けるAPIエンドポイントは、登録済みアカウントか未登録アカウントかにかかわらず、常に同じ応答を返すことで、攻撃者がアカウントの存在を確認する手がかりを与えないようにする。そして、アカウントごと、宛先ごと、またはクライアントIPアドレスごとに、リセットの頻度を制限する。メッセージ送信に失敗した場合でも、新しい秘密情報を生成し直すのではなく、同じ秘密情報を使ってメッセージの再送を試みるべきだ。ただし、有効期限が残りわずかな場合は再送を中止するなどの判断も必要となる。

セキュリティのテストも欠かせない。例えば、異なる言語設定の宛先、有効期限の境界値、ユーザーが入力した悪意のあるテキスト(エスケープ処理が正しく行われるか)、必須変数の欠如、最長の組織名など、様々なケースを想定してテンプレートが正しくレンダリングされるかを確認する。生成されたメッセージにリセットURLが一つだけ含まれているか、保存されたハッシュ値が含まれていないか、正しい有効期限が示されているかなども確認対象だ。さらに、状態遷移(リセット要求→メッセージ送信→パスワード変更)のテストも行い、有効期限内であれば一度だけ成功し、同じ秘密情報では二度と成功しないことを確認する必要がある。

運用面では、サービスリリース前に、メッセージが実際のユーザーに届かないステージング環境で、リセットフロー全体を実際に動かして確認することが不可欠だ。未知のアカウントからのリクエストに対するAPIの応答形式や応答時間も、想定される脅威モデルと一致するかを検証する。デプロイの際には、コードとテンプレートは常に互換性のある単位で同時にリリースし、古いバージョンのメッセージがキューに残っている間は、そのメッセージも正しく処理できるようにしておく。

最終的に、セキュリティに関わる「意味」や「ルール」はアプリケーションが所有し、メッセージの「配信」に関わる技術的な部分は専門の配信サービスに任せる。そして、単なる文章表現のような編集可能な部分は、厳格なルールに基づいた承認プロセスを経て変更を許可する。この明確な境界線が、安全で信頼性の高いログインリカバリ機能を実現する鍵となる。

関連コンテンツ

関連IT用語