Google、Facebook、Amazon(AWS)、Githubなど、大手Webサービス会社が2要素認証を取り入れてしばらく経っています。自分のWebサイトでも2要素認証を導入したい!と思ったことは無いですか?
簡単に可能です!
パスワード認証だけではもう安全とは言えません。ぜひ2要素認証を自分のサービス/プロダクトに導入してください。
2要素認証とは?
2要素認証(2 Factor Authentication)とはパスワードとは別の認証コードを利用してユーザーを認証する方式です。2段階認証(2 Step Authentication)と呼ばれることもあります。複数の認証要素を利用して認証するので多要素認証(Multi Factor Authentication) とも呼ばれています。AWSでは2要素認証をMFAと呼んでいます。
2要素認証に利用する一時的なパスワード(OTP:One Time Password)の生成方法は2つあります。(他に色々ありますが省略)
- 時間ベースのOTP(TOTP:Time-based One Time Password RFC 6238)
- 履歴ベースのOTP(HOTP:HMAC-based One-Time Password RFC 4226)
Googleの2要素認証はTOTPを利用しています。詳しい解説やアルゴリズムはRFCを参照してください。TOTPのRFCにはJavaコードによるサンプルも記載されています。
2要素認証の原理は簡単です。秘密のシード(種)となる情報をサーバー側とクライアント側で共有し、時間、順序などに基き一時的または使い捨てパスワードを生成します。攻撃者はパスワード以外に、2要素認証設定時にしかやり取りされない秘密のシード情報を知らない限り、正しい使い捨てパスワードを送信することはできません。
TOTPは名前の通りシードと時間をベースにパスワードを生成します。時間と共にパスワードは変化します。HOTPはシードとハッシュ関数を使って一時的パスワードを生成します。利用した回数によってパスワードが変化します。HOTPを利用すると同期がズレることがあります。ズレた場合、連続する2のパスワードを送信して再同期を行うなどの処理が必要です。多少、利用面で不便なのでTOTPを採用しているケースが多いです。
Google認証システム(Google Authenticator)はこのRFC 6238に基づく使い捨ての数字6桁の認証コードを生成します。Google認証はAndroid, iPhone, Blackberryをサポートしているので使い勝手も良いです。RFCで規格化されているのでGoogle認証のみでなくRFC 6238のTOTPをサポートするアプリ/デバイスならどれでも使えます。
利用するサイトはどのWebサイトでも構いません。もちろん自分のWebサイトにも使えます。Webアプリケーション以外での利用も可能です。
2要素認証の利用
ここではPHPでGoogle認証システムを自分のサイトに導入する方法をできる限り簡単に紹介します。Google認証のライブラリにはGoogleAuthenticatorを利用します。
composerを使ってインストールしても良いのですが、exampleコードもダウンロードしたいのでgitでクローンします。
0 1 2 3 |
$ cd <PHPが有効なWebサーバーのドキュメントルート> $ git clone https://github.com/PHPGangsta/GoogleAuthenticator.git |
GoogleAuthenticatorディレクトリが作成されます。※
※ 注意:インターネットに接続している環境ではライブラリやテストコードを外部からアクセス可能な場所に置いてはいけません。
サンプルプログラムの実行
WebブラウザでGoogleAuthenticator/example/example1.phpにアクセスします。次のような出力が得られます。
0 1 2 3 4 5 6 7 |
Secret is: 2ZDZXLT7CJ3O5M3L Google Charts URL for the QR-Code: https://chart.googleapis.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth%3A%2F%2Ftotp%2FBlog%3Fsecret%3D2ZDZXLT7CJ3O5M3L Checking Code '938186' and Secret '2ZDZXLT7CJ3O5M3L': OK |
example1.phpではシード(シークレット)となる値に”2ZDZXLT7CJ3O5M3L”(この値は秘密にしなければならない)を設定し、Google認証に読み込む為のQRコード用URLを生成しています。QRコード画像生成にはGoogle Chartsを利用しています。
URLをクリックするとGoogle認証などで読み込めるQRコードが表示されます。通常はimgタグでHTMLページに埋め込んで使います。
Google認証などでQRコードを読み込むと新しいOTPが追加されます。
QRコード生成にGoogle Chartsを使うと秘密にすべきシードが送信されてしまいます。これが困る場合、別のプログラムなどでQRコード画像を生成しても構いません。以下の例ではLinux上でQRコードを生成するqrencodeと画像を表示するeogと使ってTOTP設定用のQRコードを表示しています。
0 1 2 3 |
$ qrencode -o tmp.png "otpauth://totp/Blog?secret=2ZDZXLT7CJ3O5M3L" $ eog tmp.png |
最後に2要素認証のパスワードとシークレットを使い、その結果が正しいかチェックしています。”OK”と表示されているので正常に動作しています。
otpauth URIのフォーマット
Google認証の設定用QRコードに埋め込む文字列にはotpauth URIを利用します。otpauth URIフォーマットはとても簡単です。
0 1 2 |
otpauth://totp/Blog?secret=2ZDZXLT7CJ3O5M3L |
- otpauth://totp/ – TOTPであることを指定
- Blog – Google認証などで「ユーザー名」とし「Blog」を表示
- secret=2ZDZXLT7CJ3O5M3L – シークレットとして「2ZDZXLT7CJ3O5M3L」を設定
- 発行元を追加したい場合は「issuer=名前」を追加
例えば、ユーザー名を「yohgaki@php.net」、発行者を「PHP Project」とする場合
0 1 2 |
otpauth://totp/yohgaki@php.net?secret=2ZDZXLT7CJ3O5M3L&issuer=PHP Project |
などとします。詳しくはこちらを参照してください。
サンプルプログラムのコード
以下はexample1.phpのコードです。
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<?php require_once '../PHPGangsta/GoogleAuthenticator.php'; $ga = new PHPGangsta_GoogleAuthenticator(); $secret = $ga->createSecret(); echo "Secret is: ".$secret."\n\n"; $qrCodeUrl = $ga->getQRCodeGoogleUrl('Blog', $secret); echo "Google Charts URL for the QR-Code: ".$qrCodeUrl."\n\n"; $oneCode = $ga->getCode($secret); echo "Checking Code '$oneCode' and Secret '$secret':\n"; $checkResult = $ga->verifyCode($secret, $oneCode, 2); // 2 = 2*30sec clock tolerance if ($checkResult) { echo 'OK'; } else { echo 'FAILED'; } |
このコードから解るように、TOTPの利用は非常に簡単です。サンプルのみでなくTOTPを実装するクラスも7KB弱ととても簡単なコードになっています。
2要素認証導入の注意点
このように2要素認証の導入は簡単ですが、注意すべきこともあります。
- OTPを生成するデバイスを無くしたり、アプリ/アプリデータを削除した場合にログインできなくなる
当たり前のことですが、OTPを生成できなくなるとログインできなくなります。このため、何らかのリカバリー方法を提供することを忘れないでください。利便性を考えるとメールに記載したURLよる設定変更(2要素認証無効化)が良いですが、セキュリティを考えるとGoogleなどが行っているようにリカバリー用のコードを予め保存してもらう方が良いでしょう。
このブログにもTOTPを導入していますが、リカバリー方法がなかった為、携帯電話の修理交換でデータベースの値を直接操作して回復させました。一般ユーザーにこのような操作は不可能でしょう。リカバリー方法は必ず作るようにしてください。
折角TOTPを導入してもシード(シークレット)が漏れては意味がありません。
- 認証デバイス設定用のQRコード画像はHTTPSを利用する
- QRコード画像がキャッシュされないように注意する
HTTPSが利用できない場合、安全なネットワークから2要素認証の設定をしてください、と注意書きをすると良いでしょう。
セッションハイジャックなどでセッションを乗っ取られた場合にOTPのシード(シークレット)が盗まれては困ります。
- 使用済み認証デバイス設定用のQRコードは二度と表示しない
TOTPは時間ベースです。OTP生成デバイスとサーバーの時刻がズレないようにしなければなりません。
- NTPなどを使ってサーバーの時刻を正確に保つ
OTPデバイスの設定ミスなどで正しく動作していないかも知れません。無効な状態でOTPを有効にするとログインできなくなります。
- OTPが正しく設定されたか確認(一時的パスワードを入力)してから有効化する
2要素認証導入の流れ
今までの説明で自分のサイトに2要素認証をどのように導入すれば良いかわかると思います。通常の場合、以下のような流れになるでしょう。
- GoogleAuthenticatorなどの2要素認証用のライブラリを配置する
- ユーザーデータベースに「2要素認証のシークレット(シード)」用の文字列カラムを追加する(NULLの場合は無効)
- ユーザー設定画面などに「2要素認証設定」を追加する。2要素認証を有効化した場合、ユーザーデータベースにシークレット(シード)を保存する。
- 2要素認証が有効な場合、ログイン画面にOTPを入力するフィールドを追加する。
OTP生成デバイスが使えなくなった場合のリカバリー方法はサイトのセキュリティポリシーに合わせて適切な方法を選択して実装してください。
- リカバリードを利用する(お勧め)
- リカバリーURLをメールで送信する
- ユーザーによるリカバリーは認めない
などの選択肢があります。
まとめ
「パスワードが危い」と言われて久しいです。2要素認証を導入すれば安全性がかなり向上します。
- 2要素認証導入はとても簡単!
- シード(シークレット)は秘密にする(HTTPSを使う、二度と表示しない)
- サーバーの時刻は正確に(NTPを使う)
- リカバリー方法を作る
多少の作業は必要ですが、今日からでも自分のWebサイトに2要素認証を導入可能なくらい簡単です!