やりたいこと
Laravel でログイン時に試行回数を設定したい
デフォルトだと同一IPからの制限になっているようでなっていません
ググって参考記事とか真似して作っても
特定のIPから、入力した認証情報(emailとか、ユーザ名とか)が複数回、同じものの場合、
IPと入力した認証情報での組み合わせでロックになります。
なので、別の認証情報を入力すれば再度認証処理が走ります
下記はlaravelのデフォルトのログインです(1分で5回でロック)
— 棗(なつめ) (@natsume_aurlia) October 14, 2020
例えば、1分間に2回ミスるとロックの場合
1.) emailにhoge@hoge.com
2.) emailにhoge@hoge.com
←二回同じなのでロック
3.) emailにfuga@fuga.com
←異なる認証情報なのでチェックが普通に走る
これじゃなんの意味もない...総当りし放題では...
原因
大雑把にロックの流れは、
1.キャッシュでカウントしたもので制限超えているか確認
2.認証情報でログインできる試行
3.失敗したらキャッシュでカウント
LoginControllerで使ってるtrait
のAuthenticatesUsers
の
login
メソッドの中で行っています
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
でカウントしています
んでこの中身です
protected function incrementLoginAttempts(Request $request)
{
$this->limiter()->hit(
$this->throttleKey($request), $this->decayMinutes() * 60
);
}
んで、このhit
メソッドでキャッシュに入れたり、時間をどうのこうのしてますがここはいいのですが
第一引数として渡している$this->throttleKey($request)
でキャッシュのキーを設定しているのですがこいつが問題です
/**
* 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だけ返すようにします
protected function throttleKey(Request $request)
{
return $request->ip();
}
あとは時間と試行回数をいい感じにしておけば
入力値に関わらずIPで制限になります
protected $maxAttempts = 10;
protected $decayMinutes = 5;