laravel-nist-password-rules icon indicating copy to clipboard operation
laravel-nist-password-rules copied to clipboard

Implement Rate Limiting (Throttling)

Open DivineOmega opened this issue 6 years ago • 5 comments

We should attempt to implement login rate limiting as part of these validation rules, as described in NIST SP800-63b section 5.2.2.

the verifier SHALL implement controls to protect against online guessing attacks. the verifier SHALL limit consecutive failed authentication attempts on a single account to no more than 100. Requiring the claimant to wait following a failed attempt for a period of time that increases as the account approaches its maximum allowance for consecutive failed attempts (e.g., 30 seconds up to an hour).

Source: https://pages.nist.gov/800-63-3/sp800-63b.html#throttle

It would also be useful to provide Artisan commands that will remove login bans / delays entirely or for specific users / IPs.

DivineOmega avatar Nov 19 '18 08:11 DivineOmega

Would this really be needed since Laravel already offers throttling? https://laravel.com/docs/5.7/authentication#login-throttling

Defaults can also easily be overridden by using such in the Controller.

    // Max Attempts Until Lockout
    public $maxAttempts = 5;

    // Minutes Lockout
    public $decayMinutes = 60;

HDVinnie avatar Nov 19 '18 14:11 HDVinnie

You're right. Most of this is covered by Laravel's build in login throttling.

It's not exactly as specified by NIST though. For example, it does not support...

a period of time that increases as the account approaches its maximum allowance for consecutive failed attempts (e.g., 30 seconds up to an hour

Also it does not provide the ability to fully lock out an account after a number of attempts, as in the following.

the verifier SHALL limit consecutive failed authentication attempts on a single account to no more than 100.

DivineOmega avatar Nov 19 '18 15:11 DivineOmega

Makes sense. Good idea!

HDVinnie avatar Nov 19 '18 16:11 HDVinnie

Update: see the following comment.

To make integration as seamless as possible, this functionality would require the validation rules to have knowledge of how to check if a user's credentials are valid. This could be achieved via a callback, as follows.

$hasValidCredentials = function(Request $request) {
    return Auth::attempt(['email' => $request->email, 'password' => $request->password], false, false);
};

$this->validate($request, [
    'email' => 'required',
    'password' => PasswordRules::login($hasValidCredentails),
]);

DivineOmega avatar Dec 10 '18 15:12 DivineOmega

Actually, the Rule object does not have direct access to the Request, so it may be best if this is checked outside of the rule and a boolean is passed in, as follows.

$hasValidCredentials = Auth::attempt([
    'email' => $request->email, 
    'password' => $request->password,
], false, false);

$this->validate($request, [
    'email' => 'required',
    'password' => PasswordRules::login($hasValidCredentails),
]);

DivineOmega avatar Dec 10 '18 15:12 DivineOmega