OTP
デバイスの所持認証にて用いるパスワードのことを指す事が多い OTP生成方法
2つの生成方法が主流
時間ベースのOTP(TOTP:Time-based One Time Password)
名前の通りシードと時間をベースにパスワードを生成
カウンタベースのOTP(HOTP:HMAC-based One-Time Password) シードとハッシュ関数を使って一時的パスワードを生成します。利用した回数によってパスワードが変化
原理
秘密のシード(種、キー、シークレット)となる情報をサーバー側とクライアント側で共有し、時間、順序などに基き一時的または使い捨てパスワードを生成する
攻撃者はパスワード以外に、MFA設定時にしかやり取りされない秘密のシード情報を知らない限り、正しい使い捨てパスワードを送信することはできない
シードの共有
読み取る文字列は以下のようになる
otpauth://<algorithm>/<name>?secret=<seed>
otpauth://totp/Amazon%20Web%20Services:root-account-mfa-device@<account-id>?secret=<secret>
algorithmとsecretさえ共有できれば良いので、AWSコンソールでは「シークレットキーを表示」で文字列としてシークレットキーを得ることもできる
Ruby実装
code:usage.rb
secret = "<base32 string>"
totp = ROTP::TOTP.new(secret)
totp.now
# => 123456
AuthyやGoogle Authenticatorで表示する結果と一致することを確認できる
MFAアプリはシークレットをローカルに保存しつつ、毎回OTPを生成しているだけだとわかる
code:algorithm.rb
interval = 30 # 30秒ごとにOTP更新
input = Time.now.utc.to_i / interval # interval中は同一値が得られる
result = []
until int == 0
result << (int & 0xFF).chr
int >>= 8
end
bytestring = result.reverse.join.rjust(padding, 0.chr)
hmac = OpenSSL::HMAC.digest(
OpenSSL::Digest.new(digest),
ROTP::Base32.decode(secret),
bytestring
)
offset = hmac-1.ord & 0xf code = (hmacoffset.ord & 0x7f) << 24 | (code % 10**digits).to_s.rjust(digits, '0')
参考