Laravel 5.5に2段階認証システムを導入する(Google2FA)

laravel-google2fa

何かとセキュリティが問われる昨今、これまでのIDパスワードだけの認証では不安を感じている方も多々いると思います。
近年、もしかしたら皆さんもご存知か、既に使われているかもしれませんが、ワンタイムパスワードを利用した2段階認証というものがあり、今回はそれをLaravelに導入していきます。

2段階認証とは?

2段階認証は、さまざまなオンラインサービスで使われています。
ユーザーに2種類の認証情報を要求することにより、アカウントへログインする際のセキュリティを強化するのが目的です。
1段階目で要求される認証情報は、パスワードであることが一般的です。
2段階目で要求される認証情報はさまざまですが、最も一般的なのは、SMSかメールで送られてくるコードです。
2段階認証の根底にあるのは、ログインするには何かを「知って」いて、何かを「持って」いなければならない、という論理です。
引用:2段階認証とは何か?どんなアカウントで使うべきか? – カスペルスキー公式ブログ

2段階認証システムを導入する方法

SMSを送信するシステムだとお金かかるし、メールが溜まるのも嫌なので、使用するパッケージは「Google Two-Factor Authentication(以下、Google2FA)for Laravel」を採用しました。
何より、あのGoogle先生が提供しているので何かと安心です。
今回はそのモジュールをサーバー側に組み込み、iOSAndroidで無料でダウンロードできアプリGoogle Authenticator」を利用して実装します。

パッケージのインストール

それでは、いつのようにComposerを使用してパッケージをインストールしましょう。
これが2段階認証を実装してくれるGoogle2FAパッケージです。

composer require pragmarx/google2fa-laravel

次にQRコードを作成してくれるパッケージも入れておきます。
これはなくてもいいですが、ユーザーがアプリで設定する際、非常に便利になりますので、ぜひインストールしておきましょう。

composer require bacon/bacon-qr-code

Laravel 5.5は他に何もする必要はありませんが、Laravel 5.4以下はconfig/app.phpのprovidersとaliasesに追加してください。
最後に設定ファイルを公開して完了です。

php artisan vendor:publish --provider="PragmaRXGoogle2FALaravelServiceProvider"

フィールド追加とモデル更新

Google2FAで必要になるシークレットキーを保存するためのフィールドカラム)を追加します。
基本的には自由ですが、私は認証で使用するためusersテーブルに追加しています。
マイグレーションファイルを作って、

php artisan migrate:make update_users_table

中はこんな感じです。

databasemigrationsXXXX_XX_XX_XXXXXX_update_users_table.php

...
class UpdateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->text('google2fa_secret')->nullable()->after('password');
        });
    }    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function(Blueprint $table) {
            $table->dropColumn('google2fa_secret');
        });
    }
}

フィールド名は設定ファイルconfig/google2fa.phpのデフォルトに合わせて、google2fa_secretとしています。
できたら、

php artisan migrate

でusersテーブルに反映させましょう。また、同時にUserモデルも変更しておきましょう。
$fillableとパスワード同様に$hiddenにも加えておきます。

appUser.php

...
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password', 'google2fa_secret',
    ];    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'google2fa_secret', 'remember_token',
    ];
...
シークレットキーの暗号化

余談ですが、シークレットキー暗号化することもお勧めします。
以前の記事で紹介したトレイトを利用する方法でも構いません。

単純に暗号化するならこちらを参考にどうぞ。

...
    /**
     * Ecrypt the user's google_2fa secret.
     *
     * @param  string  $value
     * @return string
     */
    public function setGoogle2faSecretAttribute($value)
    {
         $this->attributes['google2fa_secret'] = encrypt($value);
    }    /**
     * Decrypt the user's google_2fa secret.
     *
     * @param  string  $value
     * @return string
     */
    public function getGoogle2faSecretAttribute($value)
    {
        return decrypt($value);
    }
}

シークレットキーの登録

ユーザー登録する際に、一緒にシークレットキーを生成して、先程作成したgoogle2fa_secretフィールドに追加します。

RegisterController.php

...
use Google2FA;
...
    /**
     * Create a new user instance after a valid registration.
     *
     * @param  array  $data
     * @return AppUser
     */
    protected function create(array $data)
    {
        return User::create([
            'name' => $data['name'],
            'email' => $data['email'],
            'password' => bcrypt($data['password']),
            'google2fa_secret' => Google2FA::generateSecretKey(),
        ]);
    }
}

追加したのはこの一行だけです。

'google2fa_secret' => Google2FA::generateSecretKey(),

これでシークレットキーの登録は完了です。

ミドルウェアを追加

Google2FAパッケージには既にミドルウェアが用意されています。
それを反映させるためにKernel.phpに追加しましょう。

appKernel.php

/**
 * The application's route middleware.
 *
 * These middleware may be assigned to groups or used individually.
 *
 * @var array
 */
protected $routeMiddleware = [
    ...
    '2fa' => PragmaRXGoogle2FALaravelMiddleware::class,
];

通常、ミドルウェアでログイン状態をフィルターする場合は’auth‘だけですが、2段階認証をするには上記で追加した’2fa‘を加えます。

routesweb.php

Route::group(['middleware' => ['auth', '2fa']], function () {
    ...
});

更に、認証画面用のルートも用意されています。

Route::post('/2fa', function () {return redirect()->back();})->name('2fa');

ビューを追加

ビューを作成する前に、Google2FAで用意されているgetQRCodeGoogleUrl関数でQRコードURLを作成します。

...
use Google2FA;
...
$google2fa_url = Google2FA::getQRCodeGoogleUrl(
    config('app.name'),
    auth()->user()->email,
    auth()->user()->google2fa_secret
));
...

$google2fa_url変数に代入したものを次のビューに渡してあげましょう。
ビューも設定ファイルに記載している通り、’google2fa.index‘に作成します。

resourcesviewsgoogle2faindex.blade.php

...
<div class="content-wrapper">
    <!-- Content Header (Page header) -->
    <section class="content-header">
        <h1>
            2段階認証
            <small>Two Factor Authentication</small>
        </h1>
    </section>
    <!-- Main content -->
    <section class="content">
        <div class="row">
            <div class="col-md-6 col-sm-6 col-xs-12">
                <div class="panel panel-info">
                    <div class="panel-header with-border">
                        <h3 class="panel-title">QRコード</h3>
                    </div>
                    <div class="panel-body text-center">
                        <img src="{{ $google2fa_url }}" alt="" style="max-width: 100%;">
                    </div>
                </div>
                <div class="panel panel-info">
                    <div class="panel-header with-border">
                        <h3 class="panel-title">シークレットキー</h3>
                    </div>
                    <div class="panel-body text-center">
                        <div>
                            <div class="input-group input-group-lg">
                                <span class="input-group-addon"><i class="fa fa-key"></i></span>
                                <input id="copy" type="text" class="form-control" value="{{ auth()->user()->google2fa_secret }}" readonly>
                                <span id="clipboard" class="input-group-addon" data-clipboard-target="#copy" data-toggle="tooltip" title="クリップボードにコピー"><i class="fa fa-clipboard"></i></span>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            <div class="col-md-6 col-sm-6 col-xs-12">
                <div class="panel panel-info">
                    <div class="panel-header with-border">
                        <h3 class="panel-title">ワンタイムキーで認証する</h3>
                    </div>
                    <div class="panel-body">
                        <form class="form-horizontal" method="POST" action="{{ route('2fa') }}">
                            {{ csrf_field() }}
                            <div class="input-group input-group-lg">
                                <input id="one_time_password" type="number" class="form-control" name="one_time_password" placeholder="123456" required>
                                <span class="input-group-btn">
                                    <button type="submit" class="btn btn-info"><i class="fa fa-check"></i> 認証</button>
                                </span>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </section>
</div>
...

ここでのポイントは、QRコード画像URL

{{ $google2fa_url }}

で取得し、シークレットキーをユーザー登録時に追加した

{{ auth()->user()->google2fa_secret }}

で取得します。
そして、ワンタイムキーを入力するフォームの名前を設定ファイルの通り

one_time_password

とします。

2段階認証 完成イメージ

アプリを使ってみる

ここまで設定したら、Google Authenticatorをダウンロードしてみよう。
ダウンロードはこちら。

Google Authenticator




Google Authenticatorについて

Google AuthenticatorとはGoogleが開発した二段階認証(二要素認証)を行うトークンソフトウェアである。
AuthenticatorはユーザーがGoogleのサービスにログインする時に必要な通常のIDとパスワードと共に入力しなければいけない6桁の数字コードを提供する。
また、LastPassやDropboxといった他社製のアプリケーションでもコードを発行することが出来る。
引用:Google Authenticator – Wikipedia

今回はかなり長い記事になりました…。
書き洩れてるかもしれませんので、見つけたらご指摘ください。


Amazonベストセラー

返信を残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA