问题描述
我已经在codeignter中写了一个用户密码和电子邮件代码。
I have written a user password and emailing code in codeignter.
我创建了控制器用于恢复密码。我的代码发送临时密码在电子邮件与获取URL,我验证该URL和存储新的密码到数据库。
I have created controller for recovering password. My code send temporary password on email with get URL and I validate that URL and store new password to database.
现在我怎么能让这个代码更安全可靠。
Now how I can I make this code more secure and reliable.
我的控制器:
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
);
$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')){
$db_pass = $this->User_model->get_heshed_password($email);
if($temp_pass == $db_pass){
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('/');
}
}
我的查看文件:
<?php if(!$this->session->userdata('logged_in')) : ?>
<section style="background:#ccc;padding-top:20px;">
<div class="container">
<div class="col-md-10 col-md-offset-1">
<div class="coupon-area">
<div class="container-fluid">
<div class="col-md-12">
<div class="col-md-9 col-md-offset-1 ac-form-login">
<h4 class="modal-title">Recover Password</h4>
<hr class="separator">
<br>
<?php if($this->session->flashdata('errors')) : ?>
<div class="alert alert-danger">
<?php echo $this->session->flashdata('errors'); ?>
</div>
<?php endif; ?>
<div>
<form class="form-horizontal" action="<?php echo base_url(); ?>auth/recover_account" method="post">
<div class="form-group">
<div class="col-sm-8">
<input type="text" name="username" class="form-input-modal" placeholder="Enter your registered email" required>
</div>
</div>
<div class="form-group">
<div class=" col-sm-6">
<button type="submit" class="btn btn-default">Recover Password</button>
</div>
</div>
</form>
</div>
<br>
<hr class="separator">
<br>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<?php else: ?>
<?php redirect('account'); ?>
<?php endif; ?>
我的密码重设表单:
<?php if(!$this->session->userdata('loged_i')):?>
<section style="background:#ccc;padding-top:20px;">
<div class="container">
<div class="col-md-10 col-md-offset-1">
<div class="coupon-area">
<div class="container-fluid">
<div class="col-md-12">
<div class="col-md-9 col-md-offset-1 ac-form-login">
<h4 class="modal-title">Recover Password</h4>
<hr class="separator">
<br>
<?php if($this->session->flashdata('errors')) : ?>
<div class="alert alert-danger">
<?php echo $this->session->flashdata('errors'); ?>
</div>
<?php endif; ?>
<div>
<form class="form-horizontal" action="<?php echo base_url(); ?>auth/reset_password?user=<?php echo urlencode($this->input->get('user', true)).'&code='.urlencode($this->input->get('code', true)).'&rstc='.urlencode($this->input->get('rstc', true));?>" method="post">
<div class="form-group">
<div class="col-sm-8">
<input type="text" name="user" class="form-input-modal form-control" value="<?php echo urldecode($this->input->get('user', true));?>" required>
</div>
</div>
<div class="form-group">
<div class="col-sm-8">
<input type="password" name="newpass" class="form-input-modal" placeholder="Set Password" required>
</div>
</div>
<div class="form-group">
<div class="col-sm-8">
<input type="password" name="newpass2" class="form-input-modal" placeholder="Confirm Set Password" required>
</div>
</div>
<div class="form-group">
<div class=" col-sm-6">
<button type="submit" class="btn btn-default">Reset Password</button>
</div>
</div>
</form>
</div>
<br>
<hr class="separator">
<br>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<?php else: ?>
<?php redirect('account'); ?>
<?php endif; ?>
我的问题是我想让这个代码更加用户友好和安全,注入等问题。
My problem is I want to make this code more user friendly and secure, so that I can prevent SQL injection and other issue.
推荐答案
我已经读过你的代码,我想即使我添加时间限制使用新令牌仍然不安全。根据,你可以做得更好。我为你缩短一点。
I've read your code and I think even if I add time limit for using new token it is still not secure. According to owasp cheatsheat on password recovery, you can do better than that. I shorten it a little for you. They name five points.
- 使用您在用户注册过程中收集的一些数据 - 可以是生日,手机号码,姓氏等。
- 使用安全性问题,将答案输入设置为纯文本,不要使用下拉列表或类似内容。这里限制猜测的数量。
- 在第二步之后,建议锁定用户帐户imidiatelly。生成有时间限制的密码令牌,并通过不同的通讯渠道(可能使用短信或辅助电子邮件)发送(至少尝试)。
- 密切注意会话,并允许重置密码仅在当前会话期间。在此步骤中强制实施密码复杂性(您可以使用一些jquery插件)。
- 尝试记录用户操作,IP地址和浏览器数据。关注失败的尝试或使用过期的令牌。这样,您可以监控恶意行为并得出一些结论。
- Use some data that you collected in user registration process - it can be birthday, mobile phone number, surname etc.
- Use security questions, and put the answer inputs as pure text, don't do dropdown or anything like that. Limit here the number of guesses. Be non trivial and inventive in constructing those questions.
- After step two, it is recommended to lock user account imidiatelly. Generate time limited password token and send it(at least try to) through different communication channel, maybe with sms, or to secondary email.
- Keep an eye on session, and allow to reset password only during current session. Enforce password complexicity in this step, (you can use some jquery plugin for that).
- Try to log user actions, ip address, browser data. Focus on failed attempts or using expired tokens. This way you can monitor malicious behaviours and draw some conclusions.
这是我的小升级。我使用updated_at列,这在许多其他情况下可能有用,或者您可以指定自己的列仅限制重置密码时间。
And here's my little upgrade. I use updated_at column, which can be useful in many other situations or you may specify your own column only for limiting resetting password time.
<?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('/');
}
}
这篇关于如何使我的codeiginter密码重置功能安全?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!