OTPとは?HOTP/TOTPの生成アルゴリズムと実装・SMS OTPの限界を実装視点で解説
OTP(ワンタイムパスワード)は、一度きりで使い捨てられる認証コードで、固定パスワードに追加する second factor として広く実装されています。多くはサーバと利用者が事前に共有した秘密鍵と、時刻またはカウンターという同期要素を組み合わせて、その場限りの数字を計算する仕組みです。この記事では、HOTP(RFC 4226)とTOTP(RFC 6238)の生成アルゴリズム、otpauth:// URIによるシークレットの受け渡し、クロックずれを吸収する許容ステップ、そしてSMS OTPが抱えるSIMスワップやリアルタイムフィッシングへの弱さと採用判断までを、認証機能を実装する開発者の視点で整理します。
目次
まとめ:OTPの生成方式とTOTP/HOTPの選択・実装で外せない要点
OTPは、サーバと端末が共有する秘密鍵(シークレット)に、TOTPなら現在時刻を、HOTPならカウンター値を混ぜてHMACで計算し、その結果を6桁前後の数字に切り詰めたものです。鍵と同期要素が両側で一致するからこそ、通信路にコードを流さずに同じ値を突き合わせられます。生成の実体は標準化されており、TOTPはRFC 6238、その土台のHOTPはRFC 4226で定義されています。
実装の勘所は3点に絞れます。第一に、シークレットの受け渡しはotpauth:// URIをQRコード化する方式が事実上の標準で、桁数や周期、issuerを含めてGoogleやMicrosoftの認証アプリと相互運用できること。第二に、TOTPの検証では端末とサーバの時刻ずれを見越し、前後1ステップ程度の許容窓を持たせつつ、同じコードの再利用を弾くこと。第三に、SMSで送るOTPはSIMスワップやリアルタイムフィッシングに抜かれるため、守りたい資産に見合わないなら認証アプリやパスキーへ寄せる判断です。OTPは所持要素の一手段であり、単独で万能ではない前提で設計します。
OTPの基礎:使い捨てコードを支える共有シークレットと同期の仕組み
OTPを実装する前に、なぜ毎回違うコードが両側で一致するのかを押さえておくと、後の検証ロジックで迷いません。鍵は「共有シークレット」と「同期要素」の2つです。
ワンタイムパスワードが固定パスワードと異なる使い捨ての性質と役割
固定パスワードは一度漏れると変更するまで使われ続けますが、OTPは1回の認証か短い時間だけ有効で、使った瞬間に価値を失います。盗聴やショルダーハックでコードを覗かれても、次の認証では別の値が要るため、再利用が効きません。この性質から、OTPは固定パスワードを置き換えるものではなく、パスワード+OTPの二要素として重ねる使い方が基本です。企業として二段階認証をどう位置づけるかは二段階認証とは?二要素認証・多要素認証との違いと企業の導入判断を解説で扱っており、本記事はその生成・検証の内部に踏み込みます。
共有シークレットと同期要素(時刻・カウンター)で成り立つ生成の前提
OTPの計算には、登録時に両側へ配った秘密鍵(Base32でエンコードされた共有シークレット)と、時刻またはカウンターという「毎回変わる値」を使います。サーバと端末が同じ鍵と同じ同期要素を持てば、通信路にコードそのものを流さなくても、両者が独立に同じ数字を導けます。ここが要点で、OTPはネットワーク越しに正解を送り合うのではなく、それぞれが手元で計算した値を突き合わせる方式です。したがってシークレットが漏れれば攻撃者も同じコードを作れてしまうため、鍵の保管が防御の要になります。
SMS・認証アプリ・ハードウェアトークンという配布経路の違い
同じOTPでも、コードをどう利用者へ届けるかで安全性と実装難度が変わります。実装で選ぶ経路は主に次の3つです。
| 配布経路 | 生成主体 | 特徴 |
|---|---|---|
| SMS・メール | サーバ側 | 導入が容易だが傍受・転送に弱い |
| 認証アプリ | 端末側(TOTP) | オフライン生成・通信不要 |
| ハードウェアトークン | 専用端末 | 物理隔離で堅牢・配布コスト高 |
SMSやメールはサーバがコードを生成して送る方式で、番号さえあれば始められる手軽さがあります。一方、Google Authenticatorのような認証アプリは端末内でTOTPを計算するため、コードが通信路を流れません。守りたい資産が大きいほど、サーバ送信型より端末生成型やハードウェアトークンへ寄せるのが定石です。OTPはこうした所持要素の一つであり、上位の枠組みは多要素認証(MFA)とは?3つの認証要素と実装方式・耐フィッシングMFAを実装視点で解説で整理しています。
HOTPとTOTPの生成アルゴリズム:RFC 4226とRFC 6238の違い
OTPの中核は生成アルゴリズムです。現在の認証アプリが実装するのは、カウンター基準のHOTPと、それを時刻基準に置き換えたTOTPの2系統に整理できます。まず土台のHOTPから見ます。
HOTP(RFC 4226)のカウンター基準とHMAC・動的切り詰めの生成手順
HOTPは2005年のRFC 4226で標準化された、カウンター値を同期要素に使う方式です。共有シークレットとカウンターをHMAC-SHA1に通し、得られた20バイトのハッシュから一部を取り出して数字に変換します。処理の流れは次のとおりです。
- 共有シークレットとカウンターをHMAC-SHA1で計算する
- ハッシュ末尾4ビットが指す位置から4バイトを取り出す(動的切り詰め)
- その値を10のべき乗で剰余し、6桁などの数字に整える
- 認証成功のたびに両側のカウンターを1つ進める
カウンター方式の弱点は同期ずれです。端末側でコードを生成したのにサーバへ届かず認証されないと、カウンターが片側だけ進んでずれます。実装では、サーバがカウンターを数個先まで試す「先読み窓(look-ahead window)」を設け、ずれても一定範囲なら追従できるようにします。
TOTP(RFC 6238)の時刻基準とタイムステップ30秒・SHA1既定の仕組み
TOTPは2011年のRFC 6238で定義され、HOTPのカウンターを「現在のUNIX時刻をタイムステップで割った商」に置き換えた方式です。既定ではタイムステップ30秒、6桁、HMAC-SHA1が使われ、30秒ごとにカウンター相当の値が1つ進むため、コードが自動で切り替わります。利用者がボタンを押さなくても時間経過で更新される点が、認証アプリで広く採用された理由です。
時刻を同期要素にしたことで、カウンターの取りこぼしという問題は起きません。代わりに端末とサーバの時計がずれると値が合わなくなるため、検証側は現在ステップの前後を少し許容します。桁数やアルゴリズムはSHA1既定のまま運用されることが多いものの、RFC上はSHA256やSHA512、8桁への拡張も認められています。ただし認証アプリ側の対応状況にばらつきがあるため、相互運用を優先するなら既定値から動かさない判断が無難です。
HOTPとTOTPの同期方式・ずれ耐性・用途で分かれる比較観点
2方式は同じHMACベースでも、同期のとり方が異なるため向く用途が分かれます。
| 観点 | HOTP | TOTP |
|---|---|---|
| 同期要素 | カウンター | 時刻(30秒) |
| 有効期間 | 使うまで有効 | タイムステップで失効 |
| ずれ対策 | 先読み窓 | 時刻の許容ステップ |
| 主な用途 | ハードトークン | 認証アプリ |
選択の分岐は明快です。時計を持たない安価なハードウェアトークンや、生成回数を絞りたい局面ではHOTPが向きます。スマートフォンの認証アプリで数十秒ごとにコードを切り替える一般的な二要素認証なら、時刻同期で失効まで自動化できるTOTPを選ぶのが実装・運用ともに素直です。新規に組むならTOTPを基準に置き、特殊要件でHOTPを検討する順序になります。
OTP実装の要点:otpauth:// URI・ライブラリ・クロックずれの吸収
アルゴリズムを理解したら、実装で詰まりやすい3点を具体的に押さえます。シークレットの受け渡し、検証コード、ずれと再利用への備えです。
otpauth:// URIとQRコードでシークレット・桁数・周期を受け渡す仕組み
認証アプリへシークレットを登録するとき、事実上の標準になっているのがotpauth:// で始まるKey URI Formatです。方式・ラベル・パラメータを1本のURIに詰め、これをQRコード化して読み取らせます。典型的な形は次のようになります。
典型的な形は otpauth://totp/Issoh:[email protected]?secret=BASE32SECRET&issuer=Issoh&digits=6&period=30&algorithm=SHA1 のように、方式(totp)とラベル(サービス名:アカウント)に続けてクエリパラメータを並べたものになります。
secretがBase32エンコードした共有シークレット、issuerがサービス名、digitsが桁数、periodがタイムステップ、algorithmがハッシュ方式です。この形式はGoogle Authenticatorが定めた事実上の仕様で、多くの認証アプリが解釈します。issuerとラベルを正しく入れておくと、利用者のアプリ上でどのサービスのコードか判別しやすくなり、登録ミスや取り違えを減らせます。
pyotp・otplibで検証する最小実装と許容ステップ(±1)の設計
生成と検証をゼロから書く必要はほぼなく、実績あるライブラリに任せるのが現実的です。PythonならpyotpのTOTPクラス、Node.jsならotplibが広く使われ、シークレットとコードを渡すだけで検証できます。実装で自分の判断が要るのは、時刻ずれをどこまで許すかです。検証関数の多くはwindowやvalidWindowという引数で「現在ステップの前後いくつまで受け入れるか」を指定でき、既定は0か1です。
実務では前後1ステップ(±30秒)程度の許容が落としどころになります。窓を広げるほど時計のずれた端末を救えますが、同じコードが有効な時間が延び、盗まれたコードを使い回される猶予も広がります。±1を基準に、ずれの問い合わせが多いなら一時的に広げる運用が無難です。サーバ側の時計はNTPで同期し、端末側のずれだけを許容ステップで吸収する切り分けにしておくと、原因の切り分けも楽になります。
リプレイ防止・レート制限・シークレット保管で押さえる運用の勘所
アルゴリズムが正しくても、周辺の運用が甘いとOTPは容易に破られます。実装時に外せない備えは次のとおりです。
- 直前に成功したコードとタイムステップを記録し、同一コードの再提出を拒否する(リプレイ防止)
- 検証の失敗回数に上限を設け、総当たりで6桁を試す攻撃を遮断する(レート制限・ロックアウト)
- 共有シークレットは暗号化して保管し、平文のままDBに置かない
- 登録用QRの表示や再発行に、本人確認の再認証を挟む
特にリプレイ防止とレート制限は、TOTPの短い有効時間を前提にしても外せません。6桁は100万通りしかなく、30秒の窓でも自動化された総当たりには耐えられないためです。「一度使ったコードは二度と通さない」「一定回数で止める」の2点を、検証ロジックとセットで実装します。
OTPのセキュリティ限界と採用・見送りを分ける判断基準の整理
OTPは固定パスワード単独より確実に堅くなりますが、万能ではありません。どの経路のOTPが何に弱いかを知らないと、守ったつもりで抜けが残ります。ここは判断を言い切ります。
SMS OTPのSIMスワップとNIST SP 800-63Bが制限扱いとする背景
もっとも導入が容易なSMS OTPは、もっとも弱い経路でもあります。攻撃者が携帯キャリアを欺いて被害者の番号を自分のSIMへ移すSIMスワップに遭うと、SMSで届くコードごと奪われかねません。加えて、SS7などの通信網の脆弱性を突いた傍受や、端末のSMS転送設定の悪用も報告されています。米国のNIST SP 800-63B系のガイドラインでも、PSTN(SMS・音声)経由のワンタイムパスワードは「制限付き(restricted)」の認証方式として扱う方針が示されており、無条件の推奨はされていません。実装としては、SMS OTPは導入初期の妥協策と割り切り、守りたい資産が大きいなら端末生成のTOTPやパスキーへ移行する計画をセットで持つべきです。
リアルタイムフィッシングにOTPが抜かれる限界と耐フィッシング認証の位置づけ
TOTPやハードトークンでも越えられない壁が、リアルタイムのフィッシングです。偽サイトが利用者からIDとOTPをその場で受け取り、正規サイトへ即座に中継すれば、30秒の有効時間内に本物の認証を通されてしまいます。OTPは「利用者が正しい相手と通信しているか」を検証しないため、この中間者攻撃を原理的に防げません。ここを埋めるのが、認証先のドメインに鍵を結び付けるFIDO/WebAuthn系の耐フィッシング認証です。仕組みの詳細はFIDO認証の基本的なメカニズムとは?で解説しており、公開鍵暗号でオリジンを検証するためフィッシング中継が成立しません。フィッシング耐性を要件に含めるなら、OTPを最終形にせずパスキーへの移行を前提に設計します。
OTPを採用すべき場面と見送るべき場面の条件付きでの切り分け
採用判断は条件で切り分けられます。既存のログインに低コストで二要素を足したい、利用者の端末にアプリを入れてもらえる、守る対象が過度に高リスクではない——この条件ならTOTPベースのOTPが素直な選択です。オフライン生成で通信も不要なため、実装と運用の負荷も軽く済みます。逆に、金融取引や管理者権限のように奪取の被害が甚大で、リアルタイムフィッシングまで想定すべき領域では、OTPを主軸に据えるのは見送り、耐フィッシングのパスキーを一次手段に置く判断が妥当です。SMS OTPだけで高リスク領域を守る構成は避けます。導入方式の比較や製品選定といった企業目線の判断はワンタイムパスワードとは?仕組みと種類・企業が選ぶ導入方式を解説に整理しました。OTPやMFAを組み込んだ認証・会員基盤の設計から実装までは、会員管理システム開発としてシークレット保管や失効設計ごと受託しています。要件整理の段階からご相談ください。
よくある質問
OTPの実装検討でよく挙がる疑問を、開発者の視点で簡潔にまとめます。
OTPとTOTPとHOTPの違いは何ですか?
OTPは使い捨てパスワードの総称で、TOTPとHOTPはその生成アルゴリズムの名前です。HOTP(RFC 4226)はカウンターを同期要素に使い、認証のたびにカウンターを進めます。TOTP(RFC 6238)はそのカウンターを現在時刻ベースに置き換えた方式で、既定では30秒ごとにコードが切り替わる仕組みです。認証アプリの多くはTOTPを実装しています。
SMSで届くOTPは安全ですか?
他の経路に比べて弱い部類です。SIMスワップで番号を乗っ取られたり、通信網の傍受やSMS転送の悪用でコードを奪われる経路があり、NIST SP 800-63B系のガイドラインでもSMS/PSTN経由のOTPは制限付きの扱いです。導入は容易ですが、守る資産が大きい場合は認証アプリのTOTPやパスキーへ寄せる前提で設計します。
TOTPの時刻ずれで認証が通らないときはどうしますか?
検証側の許容ステップ(window)を確認します。多くのライブラリは前後1ステップまで受け入れる設定が可能で、既定が0なら1へ広げるとずれた端末を救える設計です。ただし窓を広げるほどコードの有効時間が延びるため、±1を基準にします。サーバの時計はNTPで同期し、原因が端末側かサーバ側かを切り分けます。
OTPはフィッシングを防げますか?
完全には防げません。偽サイトが利用者からOTPをその場で受け取り正規サイトへ中継するリアルタイムフィッシングには、有効時間内に本物の認証を通されてしまいます。フィッシング耐性を要件にするなら、認証先ドメインに鍵を結び付けるFIDO/WebAuthn系のパスキーを併用または主軸にします。
OTPの実装は自作すべきですか、ライブラリを使うべきですか?
ライブラリを使う判断が無難です。生成・検証はRFC 4226/6238で標準化されており、Pythonのpyotp、Node.jsのotplibなど実績あるライブラリが揃っています。自作すると動的切り詰めや許容ステップの実装ミスが入りやすく、そこが脆弱性になります。周辺のリプレイ防止・レート制限・シークレット保管に開発リソースを回すのが得策です。
関連記事
- ワンタイムパスワードとは?仕組みと種類・企業が選ぶ導入方式を解説:本記事の生成アルゴリズムに対し、導入方式の比較や製品選定を企業目線でまとめた判断ハブです。
- 多要素認証(MFA)とは?3つの認証要素と実装方式・耐フィッシングMFAを実装視点で解説:OTPが位置づく所持要素の上位概念。MFA全体の設計の中でOTPをどう使うかを整理しています。
- 二段階認証とは?二要素認証・多要素認証との違いと企業の導入判断を解説:OTPを second factor として重ねる二段階認証の全体像と導入判断を扱っています。
- FIDO認証の基本的なメカニズムとは?:OTPが越えられないリアルタイムフィッシングを、公開鍵とオリジン検証で防ぐ耐フィッシング認証の兄弟記事です。