LoginSignup
60
51

More than 5 years have passed since last update.

RFC6238 Time-based One-time Password Algorithm (TOTP)の仕組みのメモ

Last updated at Posted at 2015-04-03

RFCに書いてある実装使うとかでサクッとワンタイムパスワードを生成できるので、もっと普及するといいですね。その場合はシークレットの扱いは適切にお願いします。

認証の概要

サーバーと共有しているシークレットキーと現在時刻からハッシュを生成してそれが合ってるかをみる、というのが大筋の流れ。

ワンタイムパスワードの生成

Wikipediaに書いてある通りだけど、少し補足説明。

TimeCounter = (unixtime(now) - unixtime(T0)) / TimeStep  # T0はエポック開始時点なので実質0, TimeStepはサーバーと共有する。30秒が推奨されてる。

HOTP(K,C) = Truncate(HMAC(K,C)) & 0x7FFFFFFF  # HMACはRFC2104で、TruncateのマナーはRFC4226でそれぞれ定義されている

TOTP = HOTP(SecretKey, TimeCounter)  # SecretKeyは事前にサーバーから提供されたもの
TOTP-Value = TOTP mod 10^ditits_number  # 剰余オペレーターを通して、指定桁数になるよう整形
  • TruncateについてはHOTP1で定義されている
  • 有効期間は30秒を推奨とRFCに書いてある
  • ハッシュ関数の推奨はRFCにはない。実質、SHA-1がデファクト。RFC上では、HMAC-SHA-1ではなく、HMAC-SHA-256 or HMAC-SHA-512が使われることも、実装によってはありうるとある。けど、TOTPのベースになっているHOTPのRFCではSHA-1が使われることが想定されているので、それに則っているのかな
  • 当然、Secretキーをサーバー側と共有しないといけなくて、シークレットの受け渡しは以下の2つがよく使われる
    • QRコード
    • ユーザーに表示して手入力してもらう

実際の運用でのシークレットの渡し方

例えば以下はFacebookで2段階認証を有効にした場合に表示されるQRコードをデコードしたもの。

otpauth://totp/Facebook:johndoe?secret=16DIGITS_SECRET&digits=6&issuer=Facebook

Qiitaの場合は以下。

otpauth://totp/johndoe?secret=16DIGITS_SECRET&issuer=Qiita

Qiitaのほうはdigitsも省略してるけど、6桁がよく使われるからだろうね。

アプリケーションでのワンタイムパスワードの生成

という感じで実装側はとくに難しいところはないので、アプリケーションを差別化するのは難しそう。
IIJ SmartkeyやAuthyや、そもそもGoogle Authenticatorも汎用TOTPコードジェネレーターとして動くので、どれでも好きなの使えばよい、が、そのTOTPコードジェネレーターが秘密鍵を適切に管理してるかは気にしたほうがいい。平文で適切なパーミッションなしで保存などされていたら台無し。Authyだとデバイスが代わっても大丈夫!復元可能!と言ってるけど、それってつまりシークレットを外部のサーバーに保存してるということなので、それが許容されるひとは使えばいいと思う。

セキュリティトークンとの比較

比較 TOTP/HOTP セキュリティトークン
開始するコスト 安い 高い
耐タンパー性 低い(rootedなデバイスで第三者のアプリケーションからSecretKeyを覗き見されたらどうする?) 高い(独立したセキュリティトークンはたいてい耐タンパー性が高くなるように設計されている、はず)
60
51
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
60
51