私はあなたのコードを読みました、そして私が新しいトークンを使用するための時間制限を追加したとしても、それはまだ安全ではないと思います。 パスワード回復に関するowaspチートヒート によると 、あなたはそれよりもうまくやることができます。少し短くします。彼らは5つのポイントを挙げています。
- ユーザー登録プロセスで収集したデータを使用します。誕生日、携帯電話番号、名前などがあります。
- セキュリティ保護用の質問を使用し、回答の入力を純粋なテキストとして入力します。ドロップダウンなどは行わないでください。ここで推測の数を制限します。これらの質問を作成する際は、自明ではなく独創的である必要があります。
- 手順2の後、ユーザーアカウントを同じようにロックすることをお勧めします。期間限定のパスワードトークンを生成し、それを別の通信チャネルを介して、おそらくSMSを使用して、またはセカンダリ電子メールに送信します。
- セッションを監視し、現在のセッション中にのみパスワードのリセットを許可します。このステップでは、パスワードの複雑さを強制します(そのためにjqueryプラグインを使用できます)。
- ユーザーアクション、IPアドレス、ブラウザデータをログに記録してみてください。失敗した試行または期限切れのトークンの使用に焦点を合わせます。このようにして、悪意のある動作を監視し、いくつかの結論を導き出すことができます。
そして、これが私の小さなアップグレードです。私はupdated_at列を使用します。これは他の多くの状況で役立つ可能性があります。または、パスワードのリセット時間を制限するためにのみ独自の列を指定することもできます。
<?php
public function recover(){
$data['main_content'] = 'auth/recover';
$this->load->view('public/layouts/home_main', $data);
}
public function recover_account(){
$this->form_validation->set_rules('username','Username','trim|xss_clean|required');
if ($this->form_validation->run() == FALSE){
//Show View
$data = array(
'errors' => validation_errors()
);
$this->session->set_flashdata($data);
$data['main_content'] = 'auth/recover';
$this->load->view('public/layouts/home_main', $data);
}
else{
$account = $this->input->post('username');
if($this->User_model->user_exist($account)){
$options = [
'cost' => 8,
'salt' => mcrypt_create_iv(22, MCRYPT_DEV_URANDOM),
];
$temp_pass = password_hash(rand(23456,975655), PASSWORD_BCRYPT, $options);
$reset_code = rand(23456,975655);
$data = array(
'reset_link_code' => $reset_code
);
$this->session->set_userdata($data);
$this->email->from('[email protected]', 'Your Name');
$this->email->to('[email protected]');
$this->email->subject($reset_code);
$this->email->message(
'Testing the email class.'.' pass: <a href="'.base_url().'auth/reset_password?user='.urlencode($account).'&code='.urlencode($temp_pass).'&rstc='.urlencode($reset_code).'">Click Here</a>'
);
$db_pass = array(
'password' => $temp_pass,
'updated_at' => time() //or even date("Y-m-d H:i:s")
);
$this->db->where('email', $account);
$this->db->or_where('username', $account);
$this->db->update('users', $db_pass);
if($this->email->send()){
echo 'Passowrd resend link sent to email';
}else{
echo 'email count not check, pls talk to support';
}
}else{
echo "User not Fount";
}
}
}
function reset_password(){
$email = urldecode($this->input->get('user', true));
$temp_pass = urldecode($this->input->get('code', true));
$reset_code = urldecode($this->input->get('rstc', true));
if($email && $temp_pass && $reset_code){
$this->form_validation->set_rules('user','Username','trim|xss_clean|min_length[4]');
$this->form_validation->set_rules('newpass','Password','trim|xss_clean|required|min_length[4]|max_length[50]');
$this->form_validation->set_rules('newpass2','Confirm Password','trim|xss_clean|required|matches[newpass]');
if($reset_code == $this->session->userdata('reset_link_code')){
//get user data by email
//$user = $this->User_model->get_heshed_password($email);
$user = $this->User_model->get_heshed_password_and_updated_value($email);
//calculate time difference
$dbdate = strtotime($user->updated_at);
if (time() - $dbdate > 15 * 60) {
// 15 mins has passed
$time_allowed = false;
} else {
$time_allowed = true;
}
if($temp_pass == $user->password && $time_allowed){
if ($this->form_validation->run() == FALSE){
//Show View
$data = array(
'errors' => validation_errors()
);
$this->session->set_flashdata($data);
$data['main_content'] = 'auth/reset_password';
$this->load->view('public/layouts/home_main', $data);
}
else{
$options = [
'cost' => 8,
'salt' => mcrypt_create_iv(22, MCRYPT_DEV_URANDOM),
];
$password = $this->input->post('newpass');
$passtodb = password_hash($password, PASSWORD_BCRYPT, $options);
$data = array(
'password' => $passtodb
);
$this->db->where('email', $email);
$this->db->or_where('username', $email);
$this->db->update('users', $data);
redirect('account');
}
}
}else{
echo 'invalid reset code';
}
}else{
redirect('/');
}
}