PHP google authenticatorで2段階認証を実装する

PHPで2段階認証を実装 php

AWSへのルートログインでもお馴染みの2段階認証を実装します。
PHPで簡単に実現するにはPHPGangsta/GoogleAuthenticatorを使うのが良さそうです。
SMSで6桁送信して認証も作ったのですが、AmazonSNSを利用するなど別途料金かかるし、なにより導入が簡単だったのが理由です。

スポンサーリンク

1.PHPGangsta/GoogleAuthenticatorライブラリを使う

下記のライブラリを使います。

PHPGangsta/GoogleAuthenticator
PHP class to generate and verify Google Authenticator 2-factor authentication - PHPGangsta/GoogleAuthenticator

1.1 composerでインストール

といいたいところですが、公式にはないようでdev-masterということです。
composerでインストールと書いてあるけどどうやるの?というのを下記で。

composer show --available phpgangsta/googleauthenticator

composer require --prefer-dist phpgangsta/googleauthenticator:dev-master

2. スマホアプリ google認証システム

Google 認証システム - Google Play のアプリ
Google 認証システムにより、スマートフォンで 2 段階認証プロセスのコードが生成されます。 2 段階認証プロセスは、ログイン時に 2 つ目の確認手順を求めることで Google アカウントのセキュリティを強化するものです。パスワードに加えて、スマートフォンの Google 認証システム アプリによって生成された...
‎Google Authenticator
‎Google 認証システムを Google アカウントの 2 段階認証プロセスで使用して、ログイン時のセキュリティを強化できます。 2 段階認証プロセスでは、アカウントへのログイン時にパスワードと確認コードの両方が必要になります。このアプリでは確認コードを生成でき、一度設定すればネットワーク接続や携帯電話回線を利...

3. 2段階認証の流れ

流れは以下のような感じにしました。

  1. ログイン後、認証ページに移動
  2. 始めてなので、QRコード出す
    同時にDBにそのユーザーのsecretを登録
  3. ユーザーがQRコード撮ってGoogle認証アプリ入れる
  4. 6桁コードを入力し認証
  5. 認証ダメなら失敗カウント増やし、4に戻る
    〇回以上なら、アカウントロックしておく。
  6. 認証成功したら完了

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>

2段階認証 QRコード表示

上記は勿論読み込めません。画像いじっています。

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()をしておきます。

参考

https://www.blognow.org/blogs/view/e71ce135-acfb-4b0c-996e-55efb55c6245/how-to-implement-2-factor-authentication-with-google-authenticator-using-php-library-phpgangsta
QR code APIでQRコードを生成してみた!
PHPでファイルを暗号化 - Qiita
以前、単純な文字列を暗号化する方法書きました。 今回はAES256以上でファイルを暗号化して!と言われたのでテストしてみました。 文字列の際と同様に、基本は、openssl_encrypt()を使う。 文法的には、 strin...

コメント

タイトルとURLをコピーしました