Tôi đã đọc mã của bạn và tôi nghĩ rằng ngay cả khi tôi thêm giới hạn thời gian sử dụng mã thông báo mới, nó vẫn không an toàn. Theo owasp cheatsheat về khôi phục mật khẩu , Bạn có thể làm tốt hơn thế. Tôi rút ngắn nó một chút cho bạn. Họ đặt tên cho năm điểm.
- Sử dụng một số dữ liệu mà bạn đã thu thập trong quá trình đăng ký người dùng - đó có thể là ngày sinh, số điện thoại di động, họ, v.v.
- Sử dụng câu hỏi bảo mật và đặt đầu vào câu trả lời dưới dạng văn bản thuần túy, không thực hiện thả xuống hoặc bất cứ điều gì tương tự. Giới hạn ở đây số lần đoán. Hãy không tầm thường và sáng tạo trong việc xây dựng những câu hỏi đó.
- Sau bước hai, bạn nên khóa tài khoản người dùng ngay lập tức. Tạo mã thông báo mật khẩu có giới hạn thời gian và gửi (ít nhất là cố gắng) thông qua các kênh liên lạc khác nhau, có thể bằng sms hoặc tới email phụ.
- Theo dõi phiên và chỉ cho phép đặt lại mật khẩu trong phiên hiện tại. Thực thi tính đầy đủ của mật khẩu trong bước này, (bạn có thể sử dụng một số plugin jquery cho việc đó).
- Cố gắng ghi lại các thao tác của người dùng, địa chỉ ip, dữ liệu trình duyệt. Tập trung vào những lần thử không thành công hoặc sử dụng mã thông báo đã hết hạn. Bằng cách này, bạn có thể theo dõi các hành vi độc hại và đưa ra một số kết luận.
Và đây là nâng cấp nhỏ của tôi. Tôi sử dụng cột updated_at, cột này có thể hữu ích trong nhiều trường hợp khác hoặc bạn có thể chỉ định cột của riêng mình để giới hạn thời gian đặt lại mật khẩu.
<?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('/');
}
}