インターネット上のサービスを利用する際、もはやIDとパスワードだけの認証では自身の情報を守り切ることが難しい時代となりました。
フィッシング詐欺やパスワードリスト攻撃といったサイバー攻撃の手口は日々巧妙化しており、これに対抗するための手段として「多要素認証(MFA)」の導入が不可欠です。
多要素認証の代表的な手法の一つが、一定時間だけ有効な使い捨てのパスワードを用いる「ワンタイムパスワード(OTP)」です。
このワンタイムパスワードを支える技術には、大きく分けて「HOTP」と「TOTP」という2つのプロトコルが存在することをご存知でしょうか。
本記事では、セキュリティ担当者やITエンジニアが知っておくべき、TOTPとHOTPの仕組みの違い、それぞれのメリット・デメリット、そしてどのように使い分けるべきかを詳しく解説します。
ワンタイムパスワード(OTP)が求められる背景
私たちが普段利用している静的なパスワードは、一度設定すると変更しない限り同じ文字列を使い続けることになります。
しかし、万が一そのパスワードが外部に漏えいしてしまった場合、悪意のある第三者によって不正アクセスを許してしまうリスクが非常に高まります。
こうしたリスクを低減するために考案されたのが、「一度しか使えない」かつ「短時間で無効になる」性質を持つワンタイムパスワードです。
ワンタイムパスワードは、認証のたびに新しいコードを生成するため、たとえ一度コードを盗まれたとしても、次回のログイン時にはそのコードは利用できません。
現在、多くのWebサービスや金融機関のアプリでは、このワンタイムパスワードをスマートフォンアプリや専用デバイスで生成する仕組みが採用されています。
この仕組みを標準化したものが、IETF(Internet Engineering Task Force)によって策定されたHOTPおよびTOTPです。
HOTP(HMAC-based One-Time Password)の仕組み
HOTPは、HMAC(Hash-based Message Authentication Code)に基づいたワンタイムパスワードのアルゴリズムです。
2005年にRFC 4226として標準化され、現在主流となっている多くの認証システムの基礎となりました。
カウンター値をベースにした生成プロセス
HOTPの最大の特徴は、「カウンター値」を用いてパスワードを生成する点にあります。
具体的には、サーバーとクライアント(ユーザーのデバイス)の間で共有されている「秘密鍵」と、認証のたびにインクリメントされる「カウンター」を組み合わせてハッシュ値を計算します。
ユーザーがデバイスのボタンを押したり、ログインを試みたりするたびにカウンターが1つ増え、それに応じた新しいパスワードが生成されます。
この仕組みにより、生成されたパスワードは次にボタンが押されるまで、あるいは認証が成功するまで有効な状態が保たれます。
HOTPのメリット
HOTPの利点は、デバイス側に時計(リアルタイムクロック)を内蔵する必要がないことです。
そのため、安価なハードウェアトークンや、通信機能を持たない小型のデバイスでも実装が可能となります。
また、時間の制限がないため、ネットワークの遅延やユーザーの入力速度に左右されにくいという安定性も備えています。
HOTPの課題とデメリット
一方で、HOTPには「同期ズレ」という特有の問題がつきまといます。
例えば、ユーザーがログインするつもりがないのにデバイスのボタンを何度も押してしまった場合、クライアント側のカウンターだけが進んでしまいます。
すると、サーバー側が保持しているカウンター値と不一致が生じ、正しいパスワードを入力しても認証に失敗する事態が発生します。
このため、サーバー側には「ルックアヘッド・ウィンドウ」と呼ばれる、将来のカウンター値を一定範囲内で受け入れるための許容範囲を設ける必要があり、これがセキュリティ上のわずかな隙を生む要因にもなり得ます。
また、一度生成されたパスワードが次に更新されるまで有効であるため、有効期限の短さという点では後述のTOTPに劣ります。
TOTP(Time-based One-Time Password)の仕組み
TOTPは、HOTPを拡張する形で2011年にRFC 6238として策定されました。
現在、Google Authenticator(Google 認証システム)やMicrosoft Authenticatorなどのスマートフォンアプリで広く使われているのは、このTOTPです。
時間をカウンターとして利用する進化形
TOTPは、HOTPのカウンター部分を「現在の時刻」に置き換えたものです。
通常、30秒や60秒といった一定の「タイムステップ」ごとにカウンターが自動的に更新される仕組みになっています。
具体的には、Unixエポック(1970年1月1日0時0分0秒)からの経過時間をタイムステップで割った数値をカウンターとして使用します。
これにより、ユーザーが操作を行わなくても、時間が経過するだけで自動的に新しいパスワードが生成され、古いパスワードは無効化されます。
TOTPのメリット
TOTPの最大の強みは、その極めて短い有効期限にあります。
パスワードが30秒程度で失効するため、万が一攻撃者がパスワードを盗聴したとしても、それを利用して不正ログインを行うための時間がほとんど残されていません。
また、HOTPのように「ボタンを押しすぎて同期がズレる」といったユーザー起因のトラブルが発生しないことも、運用上の大きなメリットです。
TOTPの課題とデメリット
TOTPを安全に動作させるためには、サーバーとクライアントの「時刻」が正確に同期している必要があります。
スマートフォンのように自動的に時刻補正が行われるデバイスであれば問題ありませんが、安価なハードウェアトークンの場合、内蔵時計の精度によって少しずつ時刻がズレてしまうことがあります。
また、時刻の同期が必要な分、デバイスのコストがHOTP対応のものよりも高くなる傾向があります。
TOTPとHOTPの比較表
それぞれのプロトコルの特徴を整理するために、主要な項目で比較表を作成しました。
| 比較項目 | HOTP (RFC 4226) | TOTP (RFC 6238) |
|---|---|---|
| ベースとなる値 | カウンター(回数) | 時刻(タイムステップ) |
| パスワードの更新タイミング | ユーザーがアクションを起こした時 | 一定時間(例:30秒)が経過した時 |
| 有効期限 | 次の認証成功または更新まで | 極めて短い(設定された時間内のみ) |
| 同期ズレの原因 | ボタンの空押しなどによる回数の不一致 | デバイスの内蔵時計の誤差 |
| 主な利用形態 | 専用ハードウェアトークン | スマホアプリ(Google Authenticator等) |
| セキュリティ強度 | 良好 | 非常に高い(時間制限があるため) |
どちらを選択すべきか?安全な使い分けのポイント
現代のWebサービス開発において、TOTPとHOTPのどちらを採用すべきかは、ターゲットとなるユーザー層や利用環境によって異なります。
一般的なWebサービス・個人ユーザー向けには「TOTP」
現在の主流は間違いなくTOTPです。
スマートフォンという、正確な時刻を常に保持し、アプリを容易に導入できるプラットフォームが普及したことで、TOTPの利便性と安全性が高く評価されています。
実装が容易で、QRコードをスキャンするだけで設定が完了するユーザー体験(UX)の良さも、TOTPが選ばれる大きな理由です。
特に理由がない限り、新規で多要素認証を導入する場合はTOTPを選択するのが最適解と言えるでしょう。
特定のビジネス環境やオフライン環境では「HOTP」
一方で、業務上の制約からスマートフォンを持ち込めない現場や、極めて長期間(10年以上など)電池を交換せずに使い続けたいハードウェアトークンの場合は、HOTPが採用されることがあります。
HOTPは電力を消費する時計機能を必要としないため、電池寿命を極限まで延ばすことが可能です。
また、オフライン環境で時刻同期を行う手段が限られている古いシステムとの親和性が高いのもHOTPの特徴です。
ワンタイムパスワード生成アルゴリズムの仕組み(テクニカル深掘り)
ここでは、エンジニアの方向けに、実際にどのようにして6桁の数字が生成されているのか、そのアルゴリズムの内部構造を少し詳しく見てみましょう。
TOTPもHOTPも、基本的には同じ「動的な切り出し(Dynamic Truncation)」という手法を用いています。
# TOTP/HOTPの生成ロジックのイメージ(概念的なコード)
import hmac
import hashlib
import struct
import time
def generate_otp(secret_key, counter):
# 1. 秘密鍵とカウンターからHMAC-SHA1ハッシュを計算
# ※TOTPの場合はカウンターを「現在のUnixタイム / 30」とする
msg = struct.pack(">Q", counter)
h = hmac.new(secret_key, msg, hashlib.sha1).digest()
# 2. ダイナミック・トランケーション(動的切り出し)
# ハッシュの最後の4ビットをオフセットとして使用
offset = h[-1] & 0x0f
# オフセット位置から4バイトを取り出す
truncated_hash = struct.unpack(">I", h[offset:offset+4])[0] & 0x7fffffff
# 3. 6桁の数字にする
otp = truncated_hash % 1000000
return str(otp).zfill(6)
# 実行例(実際の秘密鍵はBase32エンコードされていることが多い)
secret = b'SECRET_KEY_BASE_32'
current_counter = int(time.time() / 30)
print(f"Current OTP: {generate_otp(secret, current_counter)}")
Current OTP: 123456
このように、複雑なハッシュ計算の結果から特定の部分を抽出し、人間が入力しやすい6桁(あるいは8桁)の数字に変換しています。
この変換プロセス自体は非常に軽量であるため、スペックの低いマイコンや古いスマートフォンでも高速に動作します。
ワンタイムパスワード運用における注意点
TOTPやHOTPを導入する際には、技術的な仕様だけでなく、運用の安全性についても考慮しなければなりません。
バックアップコードの提供
スマートフォンの紛失や故障によって認証アプリにアクセスできなくなると、ユーザーは自分のアカウントにログインできなくなってしまいます。
これを防ぐために、あらかじめ「リカバリコード(バックアップコード)」を発行し、安全な場所に保管するよう促す必要があります。
秘密鍵(シークレット)の保護
TOTP/HOTPのセキュリティの要は、サーバーとクライアントの間で共有される「秘密鍵」です。
この鍵が第三者に漏えいした場合、攻撃者はユーザーと全く同じワンタイムパスワードを生成できるようになってしまいます。
データベースへの保存時には暗号化を行い、QRコードを表示する際も通信路の暗号化(HTTPS)を徹底しなければなりません。
フィッシング耐性の限界
非常に重要な点として、TOTPやHOTPは「フィッシング耐性」が完全ではないということが挙げられます。
攻撃者が用意した偽のログインサイトにユーザーが誘導され、ID・パスワードと一緒にワンタイムパスワードを入力してしまった場合、攻撃者はリアルタイムでその情報を盗み取り、正規のサイトへログインを試みることができます。
より高度なセキュリティを求める場合は、FIDO2/WebAuthnのような「デバイスとドメインが紐付いた認証方式」への移行を検討する必要があります。
まとめ
ワンタイムパスワードの主要なプロトコルであるTOTPとHOTPは、いずれも強力なセキュリティを提供する技術です。
HOTPは「カウンター」をベースにし、ハードウェアの制約が厳しい環境に適した歴史ある方式です。
対してTOTPは「時刻」をベースにし、有効期限の短さからより高いセキュリティと利便性を両立させた現代のデファクトスタンダードです。
それぞれの仕組みと特性を正しく理解し、自社のサービスやセキュリティポリシーに合わせて最適な方式を選択することが重要です。
多要素認証を適切に実装し、ユーザーの安全を守るための一歩を踏み出しましょう。
