Google認証システムを使って多要素認証を実装してみた

こんばんは, ritouです.

いやー、最近パスワード漏洩の話が多いですね.
ユーザー認証も, レガシーなパスワード認証だけではなく, 新しい方向性を求められているのです.
こういうときに話題に出てくるのが多要素認証です.

多要素認証と言えば, GoogleさんはAndroid/iPhone向けにOTP生成アプリを出したりして実装しています. 以前エントリを書きました.
Googleの2段階認証で使われているOTPの仕様が気になった - r-weblife

Google認証システムというアプリがあるのですが、これはGoogleのサービスとは別で、TOTPもしくはHOTPの鍵を設定することでOTPクライアントとして簡単に利用できます.
https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2

今回は, このアプリを用いて自サイトに多要素認証を実装してみたという報告になります.

やったこと

検証的な取り組みですので, 私が作っているOpenID ConnectのデモOPで実装してみました.
https://openidconnect.info/

  • このGoogle認証システムを信頼する(OTPのSecretを預けるという意味で)
  • Google認証システムに設定するKeyを払い出した
  • QRコードにしてアプリに読み込ませた
  • 払い出されたOTPでログインしてみた

画面フローとその裏側

まずは設定からです.
今話題のmixiのOAuthを認証に用いています.

リソースアクセスを許可して戻ります

ここでログイン状態となり, One Time Passwordのメニューをクリックします.

ここでまだこのアカウントはOTP設定が有効ではないため, 設定画面に遷移します.

QRコードが表示されており, Google認証システムにて"アカウント追加"→"バーコードをスキャン"として読み込みます.
これで設定が完了して, 時間単位で変化するTOTPが払い出されるようになります.

ここでQRコードは次のようなURLになっています.

otpauth://totp/ritou@openidconnect.info?secret=base32_encoded_otp_secret

otpauthのURIスキームにGoogle認証システムが対応しているのでしょう.
"ritou@openidconnect.info"の部分はユーザー名としてGoogle認証システムに登録される値です.
"base32_encoded_otp_secret"はTOTPのsecretをBase32 Encodeした値です.
これを, Google Chart APIとかに投げるなり自分で生成するなりしてQRコードを表示します.
払い出されたOTPの値を入力し, サーバー側で払い出されたものと一致したら設定をONにしています.

OTPを払い出すphpのライブラリはこちら.
GitHub - ritou/php-Akita_OATH: OATH One Time Password Utility Library

一度この設定を行ったら, 次からmixiのOAuthを用いたログイン後にOTP入力画面を表示するようにしています.

簡単ですね.

思ったこと

OTP生成周りは難しくないのです.
実際のプロダクトに利用する場合には, 以下の点に気を付ける必要があるでしょう.

  • Google認証システムを信頼する : secretを外部に送ったりしないことを確認, 信頼できない場合は使ってはいけません
  • OTP設定時にはできる限りの本人確認しよう : OTP設定時に乗っ取られてたらもう話にはなりませんね
  • OTP払い出す端末の時計に気を付けよう : iOS/Android端末の時刻がずれている可能性があります. 今回のデモOPでは前後1分のずれぐらいなら動くように緩くしてあります
  • OTPが使えなくなった時のリカバリーフロー : Googleの対応を見てもわかるとおり, OTPが使えなくなった時のフォローは重要です

誰かのお役にたてれば幸いです.
ではまた!