如何使我的codeiginter密码重置功能安全?

时间:2016-10-01 13:43:48

标签: php mysql codeigniter

我已经在codeignter中编写了用户密码和电子邮件代码。

我已经创建了用于恢复密码的控制器。我的代码在带有get URL的电子邮件中发送临时密码,我验证该URL并将新密码存储到数据库。

现在我如何才能使这段代码更安全可靠。

我的控制员:

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('info@netbeam.in', 'Your Name');
                $this->email->to('vikas@onusworld.com');
                $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; ?>

我的问题是我想让这段代码更加用户友好和安全,这样我就可以防止SQL注入和其他问题。

1 个答案:

答案 0 :(得分:1)

我已经阅读了您的代码,我认为即使我添加使用新令牌的时间限制,它仍然不安全。根据{{​​3}},你可以做得更好。我为你缩短了一点。他们说了五点。

  1. 使用您在用户注册过程中收集的一些数据 - 可以是生日,手机号码,姓氏等。
  2. 使用安全问题,并将答案输入作为纯文本,不要做下拉列表或类似的事情。这里限制猜测的数量。在构建这些问题时要轻而易举。
  3. 在第二步之后,建议imidiatelly锁定用户帐户。生成限时密码令牌并通过不同的通信渠道发送(至少尝试),可能使用短信或辅助电子邮件。
  4. 密切关注会话,并允许仅在当前会话期间重置密码。在此步骤中强制执行密码复杂性(您可以使用一些jquery插件)。
  5. 尝试记录用户操作,IP地址,浏览器数据。专注于失败的尝试或使用过期的令牌。通过这种方式,您可以监控恶意行为并得出一些结论。
  6. 这是我的小升级。我使用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('info@netbeam.in', 'Your Name');
                $this->email->to('vikas@onusworld.com');
                $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('/');
        }
    }