TOTPの基礎と実装ガイド:時間同期型ワンタイムパスワードの仕組みと運用ポイント
TOTPとは何か — 概要
TOTP(Time-based One-Time Password:時間同期型ワンタイムパスワード)は、時刻に基づいて短期間だけ有効な使い捨てパスワードを生成する認証方式です。二要素認証(2FA)や多要素認証(MFA)で広く用いられ、Google Authenticator、Microsoft Authenticator、Authy、ハードウェアトークンなどのトークンで採用されています。標準的な仕様は IETF の RFC 6238(TOTP)および基礎となる RFC 4226(HOTP:HMAC-based OTP)に定義されています。
基本的な仕組み(アルゴリズムの流れ)
TOTP は HOTP を時間で駆動する形にしたものです。概略は次の通りです。
- 共有シークレット(秘密鍵)をクライアント(トークンアプリ)とサーバーで共有する。
- 現在時刻を一定の期間(デフォルト30秒)で区切り、その区切り番号(タイムステップ値)をカウンターとして扱う。
- そのカウンターを 8 バイトのビッグエンディアン整数として HMAC(SHA-1 / SHA-256 / SHA-512 など)に入力し、ダイナミックトランケーションで短い数値を取り出す。
- 得られた数値を 10^digits(通常 6 桁)で剰余して短いワンタイムコードを得る。
数式と擬似コード
主要な式は次のようになります。
- T = floor((CurrentUnixTime - T0) / X) — T0 は基準時刻(通常 0)、X はタイムステップ(秒、通常 30)。
- H = HMAC(secret, T_as_8byte)
- offset = H[last_byte] & 0x0f
- code = ( (H[offset..offset+3] & 0x7fffffff) % 10^Digits )
擬似コード例:
function generateTOTP(secret, time=now, digits=6, period=30, algo=SHA1):
T = floor(time / period)
text = to8byteBigEndian(T)
H = HMAC(algo, secret, text)
offset = H[last] & 0x0F
binary = (H[offset]<<24 | H[offset+1]<<16 | H[offset+2]<<8 | H[offset+3]) & 0x7FFFFFFF
return binary % (10 ** digits)パラメータと推奨値
- タイムステップ(period):一般的に 30 秒。短くすればセキュリティは若干上がるが使い勝手は悪化し、長くすれば有効期間が長くなりリスクが増える。
- 桁数(digits):通常 6 桁。高セキュリティを目指すなら 7 や 8 桁も可能だが、ユーザビリティに影響。
- ハッシュ関数(algorithm):SHA-1 が広く使われているが、SHA-256/512 に対応する実装もある。秘密鍵の長さはハッシュ強度に応じて適切にする(例:SHA-1 なら 160 ビット以上、推奨は 128–256 ビット以上)。
- 初期時刻(T0):通常は Unix epoch(1970-01-01 00:00:00 UTC)。
プロビジョニング(利用開始時の流れ)
一般的にはサーバーがユーザーのためにシークレットを生成し、QRコード化した「otpauth://」形式の URI をユーザーに提示します。ユーザーは認証アプリでQRを読み取り、シークレットをインポートします。Key URI Format の例:
otpauth://totp/ISSUER:ACCOUNT?secret=BASE32SECRET&issuer=ISSUER&algorithm=SHA1&digits=6&period=30
この方法により人為的ミスを減らし、簡単にトークンを登録できます。
サーバー側の検証と同期
- サーバーは受け取ったコードに対して現在のタイムステップおよび前後のステップ(例:±1)を検証することで時計ずれを吸収することが多い。
- 時計ずれが大きい場合は「同期(resync)」機能を用意し、ユーザーが連続して入力した複数コードから正しいオフセットを推定する実装もある。
- 検証の際は総当たり攻撃防止のため、試行回数制限やレート制限、アカウントロック等を組み合わせるべき。
セキュリティ上の注意点と限界
- シークレット漏洩のリスク:シークレットが漏れると攻撃者はコードを生成可能。サーバー側でのシークレット保護(暗号化、アクセス制御、KMS利用など)が重要。
- フィッシングに弱い:TOTP はユーザーがコードを入力するフローだと、攻撃者がリアルタイムでリレーして認証を突破できる(MITM)。フィッシング耐性は FIDO2 等に比べ劣る。
- SIMスワップやアカウント窃取:SMS を経由する OTP 配信とは別だが、アカウントのバックアップ方法やリカバリ手段(メール、SMS、サポートによる解除)が弱いとアカウントを奪われる可能性がある。
- リプレイの管理:同じコードを繰り返し使わせないか、短時間での複数利用を検出する必要がある(ただしコードは短期間で無効になるのでその期間を考慮)。
- ユーザビリティと運用:端末紛失時のリカバリ用に「バックアップコード」や別の MFA 要素を用意する。複数デバイスでの同期(例:Authy のクラウドバックアップ)は利便性とリスクを天秤にかける必要がある。
実装上のベストプラクティス
- シークレットは十分な長さのランダムな値を使う(少なくとも 128 ビット、できれば 160 ビット以上を推奨)。
- サーバー側でシークレットを平文で置かない。暗号化(KMS 等)や慎重なアクセス制御を行う。
- 検証は ±1 のタイムウィンドウを許容するのが一般的だが、状況に応じて調整。ログとアラートを充実させる。
- 総当たり対策として試行回数制限、IP レート制限、CAPTCHA、アカウントロックを組み合わせる。
- ユーザー教育:QR を共有しない、バックアップコードを安全に保管する、紛失時の手順を分かりやすく提示する。
- 可能ならフィッシング耐性の高い認証(WebAuthn/FIDO2)を検討する。
HOTP と TOTP の違い
HOTP(RFC 4226)は「カウンター(イベント)」に基づくワンタイムパスワードで、各認証ごとにカウンターがインクリメントされます。TOTP は時刻をカウンターに見立てる形式で、同期の取り方が異なります。HOTP はオフラインの使用やイベント駆動のシナリオに向いており、TOTP はユーザービリティと広い互換性から多く採用されています。
運用面での考慮点
- 複数端末での利用:同じシークレットを複数デバイスに登録すると利便性は上がるが、盗難や漏洩時のリスクが増す。
- バックアップとリカバリ:復旧用のワンタイムバックアップコードや登録解除ポリシーを明確にする。
- 監査とログ:認証失敗や大量の試行を検出できるログと告知を用意する。
まとめ
TOTP は比較的シンプルで広くサポートされている二要素認証方式です。正しく実装・運用すればパスワードのみの認証より大幅にセキュリティを高められますが、シークレットの保護、試行制限、フィッシング対策、リカバリ設計など運用上の配慮が不可欠です。より高いフィッシング耐性が必要な場面では、FIDO2 / WebAuthn のような公開鍵ベースの認証を検討することを推奨します。
参考文献
- RFC 6238 — TOTP: Time-Based One-Time Password Algorithm
- RFC 4226 — HOTP: An HMAC-Based One-Time Password Algorithm
- NIST Special Publication 800-63B — Digital Identity Guidelines: Authentication and Lifecycle
- Google Authenticator — Key URI Format (プロビジョニングURI仕様)
- Google Authenticator(GitHub)


