こんにちは。エンジニアの @localdisk です。2017/09/27に CVE-2017-14775 という Laravel の脆弱性が報告されました。CVE-2017-14775 はオートログイン処理に*1タイミング攻撃の脆弱性があるというものです。
タイミング攻撃についてとその対策については下記エントリに詳しくまとまっています。
この脆弱性は 2017/09/21 にリリースされた 5.5.10 で修正されています。対象のクラスは下記になります。
- Illuminate\Auth\DatabaseUserProvider
- Illuminate\Auth\EloquentUserProvider
修正された PR は下記になります。
以前は remember_token
を DB の where 条件としていますがこの修正ではプライマリキーでモデルを取得し remember_token
カラムの値と引数を hash_equals
関数で比較しています。
この hash_equals
関数がポイントでこの関数はタイミング攻撃の対策となります。
即座にバージョンアップできないあなたへ
さて、5.5 をお使いの人は composer update
すれば万事解決なのですが、5.5 未満のバージョンを使っている場合はそうもいきません。現在の LTS は 5.5 であり、それ未満のバージョンを使っている場合は自力で対処するしかありません。なのでやっていきましょう💪
カスタムプロバイダへの差し替え
(2017/10/17 追記) EloquentUserProvider, DatabaseUserProvider の修正は大体一緒なので本エントリでは EloquentUserProvider の差し替え方を説明します。
CVE-2017-14775の脆弱性で修正が必要なのは下記のクラスの retrieveByToken
メソッドです。
- Illuminate\Auth\DatabaseUserProvider
- Illuminate\Auth\EloquentUserProvider
config/auth.php
の下記でどの Provider を使用しているかがわかります。
<?php return [ 'providers' => [ 'users' => [ 'driver' => 'eloquent', // ここ。デフォルトは eloquent 'model' => App\User::class, ], ];
driver
が eloquent
の場合は EloquentUserProvider
。 database
の場合は DatabaseUserProvider
が差し替えの対象になります。
まずは差し替える カスタムプロバイダ を作成しましょう。 app
ディレクトリの下に Auth
ディレクトリを作成し、下記 CustomEloquentUserProvider
を作成しました。
<?php namespace App\Auth; use Illuminate\Auth\EloquentUserProvider; class CustomEloquentUserProvider extends EloquentUserProvider { /** * Retrieve a user by their unique identifier and "remember me" token. * * @param mixed $identifier * @param string $token * * @return \Illuminate\Contracts\Auth\Authenticatable|null */ public function retrieveByToken($identifier, $token) { $model = $this->createModel(); $model = $model->where($model->getAuthIdentifierName(), $identifier)->first(); if (!$model) { return null; } $rememberToken = $model->getRememberToken(); return $rememberToken && hash_equals($rememberToken, $token) ? $model : null; } }
retrieveByToken
メソッドは修正された内容を反映したものをそのままコピーしています。次は \App\Providers\AuthServiceProvider
の boot
メソッドに下記内容を追加します。
<?php class AuthServiceProvider extends ServiceProvider { public function boot() { // custom という名前で カスタムプロバイダ を登録 Auth::provider('custom', function ($app, array $config) { return new CustomEloquentUserProvider($app['hash'], $config['model']); }); } }
最後に config/auth.php
を変更します。カスタムプロバイダ を指定して終了。簡単ですね。
<?php return [ 'providers' => [ 'users' => [ 'driver' => 'custom', // eloquent から custom に変更 'model' => App\User::class, ], ];
まとめ
今回はバージョンアップする工数はすぐには確保できない方に向けてエントリを書きましたが、一番の対策はこまめなバージョンアップです。Laravel Announcementsや Laravel News 等、便利な情報源がありますので上手く活用していきましょう。
*1:Remember me のアレ