JP / EN

広告
2025/02/27

PHPでレートリミットをかける実装:フレームワーク非依存でできる

タグ:php Web

レートリミット(レート制限)とは特定のユーザから短時間に多すぎるリクエストがきた ときに機能の制限を設ける機能である。サーバに高負荷の処理が足りすぎるのを防ぐほか、 パスワード認証を様々なパスワードで叩きまくって突破を試みるブルートフォース攻撃などへの 初歩的な対策としても機能する。
PHPではLaravelなどのフレームワークを使えば比較的に簡単に設定できるのだが、 生PHPでやるとなるとちょっとしたコードが必要となる。安いレンタルサーバなどLaravel環境のセットアップが そもそもしにくいときにはこのようにやる手がある。

  >?php
    // 設定
    // 60秒間に5回まで許可
    $limit = 5;
    $window = 60;
    $ip = $_SERVER['REMOTE_ADDR']; // クライアントIPアドレスをキーにする

    // ファイル名(IPアドレスごとにログを分ける)
    $file = sys_get_temp_dir() . "/rate_limit_" . md5($ip) . ".txt";

    // 初期化
    if (!file_exists($file)) 
    {
        file_put_contents($file, json_encode(['count' => 0, 'timestamp' => time()]));
    }

    // ファイルの内容を読み込み
    $data = json_decode(file_get_contents($file), true);

    $now = time();
    // 60秒過ぎていたらリミット解除
    if ($now - $data['timestamp'] > $window) 
    {
        $data = ['count' => 0, 'timestamp' => $now];
    }

    $data['count']++;
    // 制限を超えた場合はエラーを返す
    if ($data['count'] > $limit) 
    {
        // リクエスト数で接続拒絶するときは429を返すのが行儀が良い
        http_response_code(429);
        echo "Too Many Requests. Try again later.";
        exit;
    }

    // 更新したデータはファイルに落とす
    file_put_contents($file, json_encode($data));

    // 正常処理
    echo "Request allowed. You have used {$data['count']} of {$limit} requests.";
    // デモなのでlimitまでの残りリクエスト数を表示、本当は隠したほうが良いかも
  ?<
  
この例では
  • ユーザはIPアドレスをキーとして見分けることとする:同IPアドレスと別ユーザは巻き添えを食う
  • リミットがかかったかはファイルで記憶;ここでRedisなどを使えばさらにパフォーマンスが良い
という実装方法を取っている点に注意。特にIPアドレスをキーとして

サンプル:1分5リクエストの制限がかかったページ
ここに5回連続でアクセスすると、6回目にはBANされていることが確認できる(笑)。 再度試したいときは60秒で解除されるので、少し待ってみていただきたい。

動作確認した環境

  • さくらのレンタルサーバ ライト
  • PHP 5.4.45


おすすめ記事

PHPでログインページ①

PHPでログインページ①

HTML5で立ち絵展示用Canvas



このエントリーをはてなブックマークに追加

https://wonderhorn.net/