綺麗に死ぬITエンジニア

Laravel 5で2段階認証(2要素認証)を実装する方法(Google Authenticator利用)

2017-02-03

Webアプリケーションのセキュリティを考える上で、やはり最も重要視すべきなのが、認証の部分でしょう。いくら脆弱性の含まない、完全なWebアプリだったとしても、IDとパスワードが流出してしまったら、全く意味がありません。

近年、推測可能なパスワードを使ってしまい、また、そのIDとパスワードを使い回してしまい、芋づる式に様々なサービスの不正アクセスを許してしまう事件が後を絶ちません。

たとえ「簡単なパスワードにしない」「パスワードを使いまわさない」など心がけていたとしても、ブルートフォースアタック(総当たり攻撃)によって不正アクセスされてしまう可能性はゼロではありません。特に大量の個人情報や機密情報を扱うWebアプリケーションの場合、不正アクセスのリスクは莫大です。

そこで、ブルートフォースアタックによる不正アクセスの可能性を限りなくゼロに近づけることができる2段階認証(2要素認証)が、近年では様々なWebサービスで使われ始めています。

今回は、Google Authenticator(Google 認証システム)を使って、比較的簡単に、Laravelで構築したWebアプリに2段階認証を実装する方法を解説します。

2段階認証(2要素認証)とは

通常のWebアプリケーションの認証は、「IDとパスワードの組み合わせ」によって認証を行います。

この場合、適当なIDとパスワードの組み合わせをプログラムで何度も試すこと(ブルートフォースアタック)によって、いずれ正しい組み合わせにたどり着く可能性がゼロではないのです。

2段階認証は、「IDとパスワードの組み合わせ」+「ワンタイムパスワード」によって認証を行います。

ワンタイムパスワードとは、ある一定時間(数十秒から数時間程度)だけ有効なパスワードのことで、利用者だけがメールやSMS、専用のアプリ等を使って知りうるパスワードです。

実際に、メールやSMSで数字の羅列が送られてきて、それを入力するような仕組みを見たことがある人も多いでしょう。それが、2段階認証です。

2段階認証の場合、ブルートフォースアタックが無力化されます。ブルートフォースアタックは総当たりでパスワードを試すため、時間がかかります。しかし、「IDとパスワードの組み合わせ」+「ワンタイムパスワード」は、一定時間で変更されてしまうので、いくら時間をかけて何度も試されたとしても、一定時間後にはまた変更されるので、いつまで経ってもたどり着けないのです。

Google Authenticator(Google 認証システム)とは

Google Authenticatorは、Googleが開発した2段階認証を行うトークンソフトウェアです。iOS、BlackBerry、Android用のアプリがGoogleから提供されており、スマホにインストールして使います。

通常の2段階認証の場合、ログインボタンを押すとメールやSMSでワンタイムパスワードが飛んできて、さらにそれを入力する形が一般的です。

しかし、Google Authenticatorを利用する場合、アプリをスマホにインストールしてログインしたいWebアプリを登録後、見てみると、30秒ごとに変更されるワンタイムパスワードが表示されます。いちいちメールなどを確認するのではなく、このアプリを開いて表示されているパスワードと一緒に、自分のIDとパスワードを入力すれば良いのです。とても簡単です。

Google Authenticatorの各プラットフォーム用のアプリは、以下のリンクから取得できます。

Laravelへの導入方法

では、Laravelへの導入方法を解説していきます。(動作確認はLaravel 5.4で実施しています)

以下の手順で、Google2FAライブラリを導入します。

Composerを使い、ライブラリをインストールします。

composer require pragmarx/google2fa

Google AuthenticatorのWebアプリ登録は、生成されたシークレットコードを手動で入力するか、生成されたQRコードをカメラで読み取ることでできます。QRコード生成機能を使う場合は、以下のライブラリもインストールします。

composer require "bacon/bacon-qr-code":"~1.0"

config/app.phpへサービスプロバイダの設定を追加します。

'providers' => [
    // Other Service Providers

    PragmaRX\Google2FA\Vendor\Laravel\ServiceProvider::class,
],

config/app.phpへエイリアスの設定を追加します。

'aliases' => [
    // Other Aliases

    'Google2FA' => PragmaRX\Google2FA\Vendor\Laravel\Facade::class,
],

これで設定は完了です。

実装方法

使う処理は、主に以下の3つです。設定でファサードがエイリアスに設定してあるので、Laravelの各ファイルからアクセスできます。

シークレットキーの生成

以下のコードは、ユーザーへ生成したシークレットキーをセットする例です。

use Google2FA;

$user = User::find(1);

$user->google2fa_secret = Google2FA::generateSecretKey();

$user->save();

generateSecretKeyメソッドで、乱数を元に生成したシークレットキーを取得します。例では、Userモデルへgoogle2fa_secretカラムを追加し、そこに設定・保存しています。

シークレットキーは設定と認証のときに必要になります。

シークレットキーの設定

Google Authenticatorアプリへ、Webアプリの登録をします。

アプリの新規追加画面で、生成したシークレットキーを手動で入力するか、以下の方法で表示したQRコードを読み取ります。

<?php
use Google2FA;

$qrCodeUrl = Google2FA::getQRCodeGoogleUrl(
    config('app.name'),
    $user->email,
    $user->google2fa_secret
);
?>

<img src={{ $qrCodeUrl }}>

getQRCodeGoogleUrlメソッドは、Google Chart APIを用いてQRコードを作成し、URLを生成します。Google Chart APIを利用しない(BaconQrCodeライブラリを利用する)場合はgetQRCodeInlineメソッドを利用します。

認証処理

認証処理は、以下のように実装します。

use Google2FA;

$success = Google2FA::verifyKey($user->google2fa_secret, $request->input('one_time_password'));

verifyKeyメソッドは、ユーザーのシークレットキーとGoogle Authenticatorアプリで取得したワンタイムパスワードを比較し、正しい場合はtrueを返します。

上記の処理を、通常のログイン処理の間に挟めば、ワンタイムパスワードを利用した認証処理が実装できます。

例えば、以下のようなコントローラーを用意すれば実装できるでしょう。

<?php

namespace App\Http\Controllers;

use Auth;
use Google2FA;
use Illuminate\Http\Request;

class AuthController extends Controller
{
    public function authenticate(Request $request)
    {
        $email = $request->input('email');
        $password = $request->input('password');
        $secretKey = $request->input('one_time_password');
        $remember = boolval($request->input('remember', 0));

        if (Auth::validate([
            'email' => $email,
            'password' => $password
        ])
        ) {
            $user = Auth::getLastAttempted();

            if ($user->google2fa_secret) {
                if (!Google2FA::verifyKey($user->google2fa_secret, $secretKey)) {
                    return redirect()->route('login');
                }
            }

            Auth::login($user, $remember);

            return redirect()->intended(route('admin::index'));
        }

        return redirect()->route('login');
    }
}

以上で各処理の説明は終了です。

あとは、上記の3つの処理に相当する画面を作成すれば、Laravelで2段階認証が実装できます。

まとめ

Google2FAライブラリを利用することで、簡単にLaravelへ2段階認証を実装できました。

Google Authenticatorを利用した2段階認証は、実装面でも運用面でも、比較的容易に導入できます。利用者全員がスマホを持っていて、かつ手軽にセキュリティ強度を上げたい場合は、最適の選択ではないかと思います。

ぜひ、これを機に導入を検討してみてはいかがでしょうか。