OTP
#セキュリティ
One Time Passwordの略、一時的なパスワード
主にmulti factor authの文脈で用いられる
デバイスの所持認証にて用いるパスワードのことを指す事が多い
OTP生成方法
2つの生成方法が主流
アルゴリズムはRFCに書いてある
時間ベースのOTP(TOTP:Time-based One Time Password)
RFC6238
名前の通りシードと時間をベースにパスワードを生成
カウンタベースのOTP(HOTP:HMAC-based One-Time Password)
RFC 4226
シードとハッシュ関数を使って一時的パスワードを生成します。利用した回数によってパスワードが変化
原理
秘密のシード(種、キー、シークレット)となる情報をサーバー側とクライアント側で共有し、時間、順序などに基き一時的または使い捨てパスワードを生成する
攻撃者はパスワード以外に、MFA設定時にしかやり取りされない秘密のシード情報を知らない限り、正しい使い捨てパスワードを送信することはできない
シードの共有
QR Codeの読み込みによる登録が一般的
読み取る文字列は以下のようになる
otpauth://<algorithm>/<name>?secret=<seed>
AWSアカウントのMFAだとこんな感じ
otpauth://totp/Amazon%20Web%20Services:root-account-mfa-device@<account-id>?secret=<secret>
algorithmとsecretさえ共有できれば良いので、AWSコンソールでは「シークレットキーを表示」で文字列としてシークレットキーを得ることもできる
Ruby実装
https://github.com/mdp/rotp
code:usage.rb
secret = "<base32 string>"
totp = ROTP::TOTP.new(secret)
totp.now
# => 123456
AuthyやGoogle Authenticatorで表示する結果と一致することを確認できる
MFAアプリはシークレットをローカルに保存しつつ、毎回OTPを生成しているだけだとわかる
code:algorithm.rb
# https://github.com/mdp/rotp より
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 |
(hmacoffset + 1.ord & 0xff) << 16 |
(hmacoffset + 2.ord & 0xff) << 8 |
(hmacoffset + 3.ord & 0xff)
(code % 10**digits).to_s.rjust(digits, '0')
参考
今すぐできる、Webサイトへの2要素認証導入