Вдохновленный StackOverflow я реализовал следующую защиту:
для каждого пользователя мы храним мягкий/жесткий замок. Жесткий замок откажется проверять пароль, даже если он правильный. soft lock - это период времени, после которого мы сбросим счетчик «неудачных попыток». каждый раз, когда вы вводите неверный пароль, как мягкий, так и жесткий блокировки, заставляя вас ждать дольше (но не навсегда) постепенное увеличение дает разумный предел, поэтому, если ваш злоумышленник пытается взломать вашу учетную запись на час - у него будет только несколько попыток, но ваша учетная запись будет в порядке после входа в систему через несколько часов. Я реализовал это в одном из своих проектов, хотя это не контроллер, а встроенный код. Посмотрите, пожалуйста, в комментариях, и я надеюсь, что это поможет вам и другим:
В модели пользователя Добавить:
$this->addField('pwd_locked_until');
$this->addField('pwd_failure_count');
$this->addField('pwd_soft_unlock');
Вам также понадобятся два метода:
/* Must be called when user unsuccessfully tried to log-in */
function passwordIncorrect(){
$su=strtotime($this['pwd_soft_unlock']);
if($su && $su>time()){
// aw, they repeatedly typed password in, lets teach them power of two!
$this['pwd_failure_count']=$this['pwd_failure_count']+1;
if($this['pwd_failure_count']>3){
$this['pwd_locked_until']=date('Y-m-d H:i:s',time()
+pow(2,min($this['pwd_failure_count'],20)));
$this['pwd_soft_unlock']=date('Y-m-d H:i:s',time()
+max(2*pow(2,min($this['pwd_failure_count'],20)),60*5));
}
}else{
$this['pwd_failure_count']=1;
$this['pwd_soft_unlock']=date('Y-m-d H:i:s',time() +60*5);
}
$this->save();
}
и
/* Must be called when user logs in successfully */
function loginSuccessful(){
$this['last_seen']=date('Y-m-d H:i:s');
$this['pwd_soft_unlock']=null;
$this->save();
}
И наконец - вы можете использовать это как форму для входа:
class Form_Login extends Form {
function init(){
parent::init();
$form=$this;
$form->setModel('User',array('email','password'));
$form->addSubmit('Login');
if($form->isSubmitted()){
$auth=$this->api->auth;
$l=$form->get('email');
$p=$form->get('password');
// check to see if user with such email exist
$u=$this->add('Model_User');
$u->tryLoadBy('email',$form->get('email'));
// user may have also typed his username
if(!$u->loaded()){
$u->tryLoadBy('user_name',$form->get('email'));
}
// incorrect email - but say that password is wrong
if(!$u->loaded())$form->getElement('password')
->displayFieldError('Incorrect Login');
// if login is locked, don't verify password at all
$su=strtotime($u['pwd_locked_until']);
if($su>time()){
$form->getElement('password')
->displayFieldError('Account is locked for '.
$this->add('Controller_Fancy')
->fancy_datetime($u['pwd_locked_until']));
}
// check account
if($auth->verifyCredentials($u['email'],$p)){
// resets incorrect login statistics
$u->loginSuccessful();
$auth->login($l);
// redirect user
$form->js()->univ()->location($this->api->url('/'))->execute();
}else{
// incorrect password, register failed attempt
$u->passwordIncorrect();
$form->getElement('password')->displayFieldError('Incorrect Login');
}
}
}
}
Это должно быть преобразовано в дополнение кем-то.