Laravel5で簡易的なスロットル

2018.6.22 (金)

普通のページでも異常なアクセスをある程度検知してアクセス不可にしておきたいと思って簡易的なもの作りました。
Laravelのログインスロットルをそのまま使ってもよかったのですが、ここではわかりやすくミドルウェアでちょろっと書いた感じです。
基本はリクエストの根っこのところでIPをとって、30秒の間に30回以上のアクセス(だいたい1秒に1回のアクセス)があったら403に飛ばします。コンテンツや好みに応じてパラメータを適当に調整してください。
あと.envで設定するときは、

## Throttle
THROTTLE_KEEP_TERM=0.5
THROTTLE_LIMIT=30

こんな感じで設定も可能です。

Source

php artisan make:middleware Throttle

app\Http\Kernel.php

....
    /**
     * The application's global HTTP middleware stack.
     *
     * These middleware are run during every request to your application.
     *
     * @var array
     */
    protected $middleware = [
....
        \App\Http\Middleware\Throttle::class, ←これ追加
    ]; 
....

app\Http\Middleware\Throttle.php (新規作成)

<?php

namespace App\Http\Middleware;

use Closure;
/* ThrottleRequests */
use Illuminate\Support\Facades\Cache;
use Illuminate\Http\Request;

class Throttle
{
    public $kepp_term = 0.5; //minite
    public $limit = 30; //minite

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
      /* para */
      if (env("THROTTLE_KEEP_TERM")) {
        $kepp_term = env("THROTTLE_KEEP_TERM");
      } else {
        $kepp_term = $this->kepp_term;
      }
      if (env("THROTTLE_LIMIT")) {
        $limit = env("THROTTLE_LIMIT");
      } else {
        $limit = $this->limit;
      }

      $acc = Cache::get($this->getIpaddress($request));
      // $acc = array(uniqid() => $this->getIpaddress($request));
      if (Cache::has($this->getIpaddress($request))) {
        $acc = array_merge($acc, array(uniqid() => $this->getIpaddress($request)));
      } else {
        $acc = array(uniqid() => $this->getIpaddress($request));
      }

      Cache::store(env("CACHE_DRIVER"))->put($this->getIpaddress($request), $acc, $kepp_term);
      if (count($acc) > $limit) {
        abort(403);
      }
      // var_dump(count($acc));

      return $next($request);
    }

    /**
     * IPアドレスの取得
     *
     * @param  \Illuminate\Http\Request  $request
     * @return string
     */
    public function getIpaddress($request)
    {
      return $request->ip();
    }
}