AWSへのルートログインでもお馴染みの2段階認証を実装します。
PHPで簡単に実現するにはPHPGangsta/GoogleAuthenticatorを使うのが良さそうです。
SMSで6桁送信して認証も作ったのですが、AmazonSNSを利用するなど別途料金かかるし、なにより導入が簡単だったのが理由です。
1.PHPGangsta/GoogleAuthenticatorライブラリを使う
下記のライブラリを使います。
1.1 composerでインストール
といいたいところですが、公式にはないようでdev-masterということです。
composerでインストールと書いてあるけどどうやるの?というのを下記で。
composer show --available phpgangsta/googleauthenticator composer require --prefer-dist phpgangsta/googleauthenticator:dev-master
2. スマホアプリ google認証システム

3. 2段階認証の流れ
流れは以下のような感じにしました。
- ログイン後、認証ページに移動
- 始めてなので、QRコード出す
同時にDBにそのユーザーのsecretを登録 - ユーザーがQRコード撮ってGoogle認証アプリ入れる
- 6桁コードを入力し認証
- 認証ダメなら失敗カウント増やし、4に戻る
〇回以上なら、アカウントロックしておく。 - 認証成功したら完了
4. QRコードを出す
ログイン後に初めてならQRコードを出すようにします。
人によってさまざまですが、
- 筆者はテーブルにデータがなければ初めて
$row == NULL - テーブルにデータがあっても、認証トライを一度もしていなければ初めて
$valid==FALSE
と見なし、QRコード出すようにしています。
一回出たけどアプリ入れ忘れや、うまくいかず認証トライもしないでページを閉じ、再度ログイン後に認証ページになった時にQRが出るようになっています。
4.1 PHP QRコード表示部分
$row = $this->auth_model->get_passcode(); if( $row == NULL || !$row->valid){ $ga = new PHPGangsta_GoogleAuthenticator(); //早速secret生成 $secret = $ga->createSecret(); //QRコード取得 $title = "サービスタイトル"; $url_qr = $ga->getQRCodeGoogleUrl($title, $secret); //urlをviewに渡す $this->data['url_qr'] = $url_qr; // secret保存しておきます $ret = $this->auth_model->add_Passcode($secret); }
4.2 QRコード表示 HTML
htmlは、もしurl_qrが存在すればimgタグで表示。
<div class="col-12"> <?php if(isset($url_qr)): ?> <imf src="<?php echo $url_qr;?>">; <?php endif;?> </div> <div class="form-group row"> <lavel for"verifycode" class="col-form-label col-4">コードを入力</label> <div class="col-8"> <input type="text" class="form-control" name="verifycode" placeholder="6桁の数値を入力してください" value=""> </div> </div> <div class="form-group"> <button type="submit" name="submit" class="btn btn-block btn-info">認 証</div> </div>

上記は勿論読み込めません。画像いじっています。
4.3 QR画像はapi.qrserver.comで生成される
ここを良しとするかですが、自分は良しとしています。
詳細は各自調べて判断してください。
5. 認証処理
3.2でinput name=”verifycode”で6桁入力したとします。それ以外はエラーチェックを入れておけばOK。DBから3.1の最後で登録したsecretを取得し、inputのコードとマッチするかチェックするだけです。
public function verify() { $verifycode = $_POST['verifycode']; //strlenなど使ってもいいけど、GoogleAuthenticator()に渡せばOK //3.1の最後でsecretを保存しているので、それを取得 $yoursecret = $this->auth_model->get_passcode(); $ga = new PHPGangsta_GoogleAuthenticator(); //マッチするかチェック $ret = $ga->verifyCode($yoursecret, $verifycode); if( $ret ){ //成功なのでどこかに成功フラグ入れておく }else{ //失敗 //失敗カウント追加 } }
筆者の場合、secretと一緒に失敗数(成功した時にリセット)、一定以上の失敗でロックするフラグも同じテーブルに入れています。
6. secretは一応暗号化して保存しておく
secretはopenssl_encrypt()で暗号化、openssl_decrypt()で復号化しておきます。
詳細は書いていないですが、auth_model->add_passcode()内でopenssl_encrypt(), auth_model->get_passcode()内でopenssl_decrypt()をしておきます。
参考


コメント