1

我很想知道:一旦通过电子邮件发送了 pw_reset 令牌,是否可以获取推荐人帐户的电子邮件地址进行验证,或者最好针对 IP 进行验证?我已将我的令牌设置为仅 1 小时过期,即使是动态 IP 也不会以该速率更改,对吗?

我正在玩的一些代码(非常 WIP),对改进/建议/批评开放。

提前致谢。

 /**
 * Reset Password Form
 * 
 * $route['auth/reset-password'] = 'reset_password_form';
 * 
 */
public function reset_password_form()
{
    $this->load->view('templates/public', array(
        'content'   =>  'auth/reset_password_form',
        'title' =>  'Password reset',
        'description'   =>  '',
        'canonical' =>  'auth'
    ));
}
/**
 * Reset Password Authentication
 * 
 * $route['auth/reset_password/validate'] = 'auth/reset_password';
 * 
 */
public function reset_password()
{
    //setup validation rules
    $config = array(
        array('field'=>'email_address', 'label' =>'Email address', 'rules'=>'trim|required|max_lenght[128]|valid_email|valid_user_email')
    );
    $this->form_validation->CI =& $this; 
    $this->form_validation->set_rules($config); 

    //run validator and confirm OR
    if($this->form_validation->run($this))
    {

        //create the token data
        $tokenhash = Auth::create_token();
        $password_token = json_encode(array(
            'token'      => $tokenhash,
            'expires'    => date('h:i:s A', strtotime($this->config->item('pw_token_expires'))), // default 1 hours
            'ip_address' =>  $this->input->ip_address()
        )); // output {"token":"3513f5ee34ED3","expires":"01:14:06 AM","ip_address":"127.0.0.1"}


        //grab a userid to use via php-activerecord custom USER model
        $user = User::get_by_email_address($this->input->post('email_address'));

        //update the user pw_token field
        try{
            if($user->update_attribute('pw_token', $password_token))
            {
                throw new \ActiveRecord\ActiveRecordException($user->errors);
            }
        }catch(\ActiveRecord\ActiveRecordException $e){
            log_message('error', $e->getMessage());
        }

        //setup email data
        //TODO : move this to USER activeRecord\Model (pre_)
        $email_data = array(
            'email_to'  =>  $user->email_address,
            'token'     =>  anchor(site_url('auth/reset_password/confirm/'.$tokenhash.'/'.$user->id.''), 'click here to reset your password'),
            'site_link' =>  anchor(site_url(), site_url())
        );

        try{
            if(Mail::send($email_data, 'reset_password.tpl.html'))
            {
                throw new Exception(Mail::errors());
            }
        }catch(Exception $e){
            log_message('error', $e->getMessage());
        }

    }
    else
    {
        $this->reset_password_form();
    }
}
/**
 * Reset Password Confirmation
 * 
 * $route['auth/reset_password/confirm/(:any)/(:num)'] = 'auth/confirm_password_reset';
 */
public function confirm_password_reset($token='', $userid='')
{
    //check for null values
    if(!$token || !$id)
    {
        redirect('/');
    }

    //ugly
    $attempts = $this->session->set_userdata('reset_pw_attempt', (int)0);
    $this->session->set_userdata('reset_pw_attempts', $attempts++);



    if(!$this->user->id != $userid && $this->session->userdata('logged_in') === (int)0)
    {
        //not great but cant validate the email, so we check to see if they have a logged in session.
        //this is not a "forgot_password request" so we should be good as long as they are logged in
        show_404();
    }
    else
    {

        //looking good so far, now lets see do they have the correct permissions
        if(in_array(PERM_UPDATE, Auth::permissions($this->user->permissions)))
        {
            if($attempts == (int)3)
            {
                $this->session->set_flashdata('', $this->lang->line('pw_reset_attempt_over'));
                redirect('/');
            }
            else
            {
                $tokn[] = json_decode($this->user->pw_token);

                if(date('h:i:s A', time()) > $tokn['expires'] && $token===$tokn['token'])
                {
                    $this->load->view('do-pw_reset_form');
                }
            }
        }
        else
        {
            $this->session->set_flashdata('info', $this->lang->line('update_permission_denied'));
            redirect('/');
        }
    }
}
4

3 回答 3

1

Why would you want to check the referrer? Using a closed loop verification is a standard practice for confirming user email addresses. You don't need to check IP or referrer, all you need to do is create a custom hash and track the email address, then send the email with this information to the user.

When the user clicks the embedded link you then confirm the hash you created, if the hash line up, then the user has confirmed their email account with your system.

//Example Link
https://mydomain.com/verify?hash=<some_hash>

For added security you can also track the time your system sent the email, and invalidate the hash after 24 hours. So if the user clicks after 25 hours, you inform them the hash is invalid and ask if they want another email sent, if so, repeat the above process.

于 2011-12-10T02:08:41.730 回答
1

通过查询字符串参数检查电子邮件地址或利用 IP 限制都是完全多余的。如果密码令牌是随机的且足够长,则不可能对其进行暴力破解,尤其是与令牌过期和令牌猜测的速率限制结合使用时。

IP 地址限制也可能是一个可用性问题。例如,用户可能会在下班前请求重置密码,然后在家中或在回家途中完成重置过程——也就是说,用户的 IP 地址在重置请求和重置确认之间发生变化。

于 2011-12-10T02:23:17.913 回答
0

没有理由检查推荐人,如果客户的计算机受到威胁,您将无法避免劫持。你可以做的是注意 CSRF 漏洞。

此外,在阅读它之后,它看起来确实检查了“ip_address”=> $this->input->ip_address()。

于 2011-12-10T01:57:42.317 回答