こんにちは、MasaKuです。
2020年9月8日に Laravel 8 がリリースされました。
Laravel 8 では セキュリティ周りの強化として Laravel Jetstream という新しいスキャフォールディングが注目されています。
しかし、レート制限の新機能にも注目です!
今回はレート制限の解説と新機能部分の説明を行いたいと思います。
- レート制限とは
- 1. 特定のアクション(APIなど)に個別の制限をかける
- 2. 認証を通過したユーザとゲストユーザで制限を分ける
- 3. 特別なオプションを保有しているユーザだけは制限を開放する
- おわりに
- 参考サイト
レート制限とは
Laravel にはDoS攻撃などの大量アクセス対策として、単位時間当たりに一定以上のアクセスを検知するとアクセス拒否する機能が導入されておりました。
最初にこの機能を知ったときは Apache や Nginx などの Webサーバ側で制限すればいいんじゃないの?
と思っていましたが、以下のようなケースではアプリケーション側で制御するほうが都合が良いことに気が付きました。
上記はいずれも Laravel 8 以前から実現できましたが、より直感的かつ簡潔に実装できるようになりましたので、Laravel 8 での実装方法について説明したいと思います。
1. 特定のアクション(APIなど)に個別の制限をかける
まず、前提としてレート制限は throttle
というミドルウェアを利用して実装します。
このミドルウェアにリミッター名と任意のレート制限を設定します。
app/Providers/RouteServiceProvider.php
の configureRateLimiting
メソッドに以下のような処理を追加します。
<?php // 一部省略 class RouteServiceProvider extends ServiceProvider { // 一部省略 protected function configureRateLimiting() { // リミッター名と制限値を設定 RateLimiter::for('testLimit', function (Request $request) { // 1分間に5アクセスまでの制限を追加 return Limit::perMinute(5); }); } }
後は、ルーティングを記載している routes/web.php
にレート制限をかけたいアクションに対しthrottle
ミドルウェアを設定するだけです。
throttle
ミドルウェアには上記で設定したリミッター名を指定します。
<?php use Illuminate\Support\Facades\Route; use App\Http\Controllers\TestController; // アクセス制限をかけたいアクションに上記で設定したリミッター名を設定 Route::middleware(['throttle:testLimit'])->get('/test', [TestController::class, 'index']);
なお、ミドルウェアは複数のアクションをグルーピングできますので、以下のように各アクションに対して同じリミッターを適応することもできます。
<?php Route::middleware(['throttle:testLimitUser'])->group(function () { Route::get('/test1', [TestController::class, 'index']); Route::get('/test2', [TestController::class, 'index']); });
上記のように記載することで /test1
と /test2
それぞれへのアクセスの合計回数を1分間5回にする制限を付けることができます。
2. 認証を通過したユーザとゲストユーザで制限を分ける
次はログイン認証を通過したユーザとゲストユーザで制限を分けてみます。
先ほど修正した app/Providers/RouteServiceProvider.php
の configureRateLimiting
メソッドを以下の通り修正します。
<?php RateLimiter::for('testLimit', function (Request $request) { return $request->user() ? Limit::none() : Limit::perMinute(5); });
ログイン認証を通過しているユーザがアクセスした場合、Request オブジェクトにはユーザ情報がセットされます。
そのため、認証済みのユーザの場合はレートの制限が解放されますが、認証前のユーザの場合は1分間5アクセスまでの制限を付けられます。
3. 特別なオプションを保有しているユーザだけは制限を開放する
認証後のユーザオブジェクトは app\Models\User.php
モデルが利用されますので、こちらに独自メソッドを追加することで特別なオプションを持つユーザだけをレート制限から解放することができます。
まずは、以下のようにして app\Models\User.php
に独自メソッドを追加します。
<?php // 省略 class User extends Authenticatable { // 省略 public function vipCustomer(){ // rakus.co.jp のドメインで登録されているユーザのみ制限を解除する if(strpos($this->email,'@rakus.co.jp') !== false){ return true; } return false; } }
あとは、リミッター内で上記で設定した独自関数を実行すれば特別なオプションを持つユーザのみアクセス制限を解除することができます。
<?php RateLimiter::for('testLimit', function (Request $request) { return $request->user()->vipCustomer() ? Limit::none() : Limit::perMinute(5); });
また、上記に加えて、by
でメソッドチェインをすると特定のIPからのアクセスを制限する、などの処理を追加できます。
<?php RateLimiter::for('testLimit', function (Request $request) { return $request->user()->vipCustomer() ? Limit::none() : Limit::perMinute(5)->by($request->ip()); });
おわりに
いかがでしたでしょうか。
Laravel は非常に多くの機能があるため、こんなこともできるんだ!と驚くような便利な機能に気づいていないことがあります。
新機能のリリースによって、前バージョンよりも使いやすくなったりわかりやすくなることによって、いままで注目されていなかった機能にも気づいてもらいやすくなるのではないかと思います。
そのほかにも、便利な機能がリリースされておりますので、気になった方は是非ご確認ください!
参考サイト
Release Notes - Laravel - The PHP Framework For Web Artisans
Introduction | Laravel Jetstream
LaravelのAPIで429 Too Many Requestsが返る - suzu6の技術ブログ
エンジニア中途採用サイト
ラクスでは、エンジニア・デザイナーの中途採用を積極的に行っております!
ご興味ありましたら是非ご確認をお願いします。
https://career-recruit.rakus.co.jp/career_engineer/カジュアル面談お申込みフォーム
どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。
以下フォームよりお申込みください。
rakus.hubspotpagebuilder.comラクスDevelopers登録フォーム
https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/イベント情報
会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください!
◆TECH PLAY
techplay.jp
◆connpass
rakus.connpass.com