LoginSignup
7
4

More than 3 years have passed since last update.

【Laravel】ログイン試行回数がIPと入力した認証情報の組み合わせになっているのでIPで制限する

Last updated at Posted at 2020-10-14

やりたいこと

Laravel でログイン時に試行回数を設定したい
デフォルトだと同一IPからの制限になっているようでなっていません

ググって参考記事とか真似して作っても
特定のIPから、入力した認証情報(emailとか、ユーザ名とか)が複数回、同じものの場合、
IPと入力した認証情報での組み合わせでロックになります。
なので、別の認証情報を入力すれば再度認証処理が走ります

下記はlaravelのデフォルトのログインです(1分で5回でロック)

例えば、1分間に2回ミスるとロックの場合

1.) emailにhoge@hoge.com
2.) emailにhoge@hoge.com ←二回同じなのでロック
3.) emailにfuga@fuga.com ←異なる認証情報なのでチェックが普通に走る

これじゃなんの意味もない...総当りし放題では...

原因

大雑把にロックの流れは、

1.キャッシュでカウントしたもので制限超えているか確認
2.認証情報でログインできる試行
3.失敗したらキャッシュでカウント

LoginControllerで使ってるtraitAuthenticatesUsers
loginメソッドの中で行っています

AuthenticatesUsers
    public function login(Request $request)
    {
        $this->validateLogin($request);

        // ここで制限超えているか確認している
        if (method_exists($this, 'hasTooManyLoginAttempts') &&
            $this->hasTooManyLoginAttempts($request)) {
            $this->fireLockoutEvent($request);

            return $this->sendLockoutResponse($request);
        }

        if ($this->attemptLogin($request)) {
            return $this->sendLoginResponse($request);
        }

        // これでキャッシュでカウントしてる!!!!
        $this->incrementLoginAttempts($request); //これ!

        return $this->sendFailedLoginResponse($request);
    }

incrementLoginAttemptsでカウントしています
んでこの中身です

ThrottlesLogins
   protected function incrementLoginAttempts(Request $request)
    {
        $this->limiter()->hit(
            $this->throttleKey($request), $this->decayMinutes() * 60
        );
    }

んで、このhitメソッドでキャッシュに入れたり、時間をどうのこうのしてますがここはいいのですが

第一引数として渡している$this->throttleKey($request)でキャッシュのキーを設定しているのですがこいつが問題です

ThrottlesLogins
    /**
     * Get the throttle key for the given request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return string
     */
    protected function throttleKey(Request $request)
    {
        return Str::lower($request->input($this->username())).'|'.$request->ip();
    }

$request->input($this->username()はメールアドレスだったり、パスワードと何を入力させるのか設定しているやつ(ここではメールアドレスとして進めます)

なので、メールアドレスとipを文字列でつないでキーを作っています....

なので当然メールアドレスの入力が変わればもう一度認証の試行を行います

解決策

throttleKeyをオーバーライドして、ipだけ返すようにします

LoginController
 protected function throttleKey(Request $request)
 {
     return $request->ip();
 }

あとは時間と試行回数をいい感じにしておけば
入力値に関わらずIPで制限になります

LoginController
protected $maxAttempts = 10;
protected $decayMinutes = 5;

7
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
4