duandeng1824 2014-06-13 20:08
浏览 50

reCaptcha - 强力保护(php / codeIgniter)

I am adding a reCaptcha field in my login form when failed attempt on the same username is > 5. I'm having problem doing this without cookies. If someone has an idea, it is welcome.


Here is my pseudo code :

User get on page, counter is set to failed_login=0 When trying to login, if user guess a good username but a bad password, the db field for this username is increased When the counter is > 5, show a captcha on the login page

The problem I have is that even when the counter is > 5, the captcha field is not verified by my controller. And also, A user may just leave my site and come back to have it's counter back to 0. Is this possible to do without using cookie? I would like to have a simple way. If I use cookie, maybe check if user has cleared his cookie not too long ago, and display a captcha, any idea welcome https://www.dropbox.com/s/30mf4ha1rm7w407/still_login.png

I'll post my full code below

Controller :

public function index()
{
    $data['publickey'] = "6LczHPd2USAAAAAbffN2Po1HaNqPyfdfdfdfdsRfaDPO9E-"; // for reCaptcha

    $this->form_validation->set_error_delimiters('<div class="alert alert-danger">', '</div>');

    $this->form_validation->set_rules('email', 'lang:label_email', 'required');
    $this->form_validation->set_rules('password', 'lang:label_password', 'required');


    global $nb_failed_attempt;
    $data['show_captcha'] = FALSE;


    if ($this->form_validation->run() === FALSE)
    {
        $this->load->view('templates/header', $data);
        $this->load->view('templates/topMenu', $data);
        $this->load->view('pages/login', $data);

    }
    else
    {
        #check login
        $success = $this->User_model->checkLogin($this->input->post('email'), $this->input->post('password'));

        #sucess redirect to home page
        if ($success) {
            redirect('/');
        }
        # bad login, reload page with error message
        else {

            echo $nb_failed_attempt;  ## variable not defined even when it is global inside user_model.php?

            if ($nb_failed_attempt > 5) {
                $data['show_captcha'] = TRUE;
                $this->form_validation->set_rules('recaptcha_challenge_field', 'Challenge', 'trim|required|callback_captcha_check');
                # this doesnt get triggered even when >5, no captcha filled and with good pw you can still login..
            }
            else {
                $data['show_captcha'] = FALSE;
            }

            $this->load->view('templates/header', $data);
            $this->load->view('templates/topMenu', $data);
            $this->load->view('pages/login', $data);
        }
    }
}


public function captcha_check($string) {

    $privatekey = "6LczHPUSAAAAAKQ58YZoV8S8ZCZ6A4ZiuqxSbbK5";
    $resp = recaptcha_check_answer ($privatekey,
            $_SERVER["REMOTE_ADDR"],
            $_POST["recaptcha_challenge_field"],
            $_POST["recaptcha_response_field"]);

    if (!$resp->is_valid) {
        $this->form_validation->set_message('captcha_check', 'The reCAPTCHA wasn\'t entered correctly. Go back and try it again.');
        return FALSE;
    } else {
        return TRUE;
    }
}

User_Model (db request)

   public function checkLogin($email, $password) {


    global $nb_failed_attempt; 
    if (!isset($nb_failed_attempt)) {
        $nb_failed_attempt = 0;
    }

        #retrieve the user salt
        $query1 = $this->db->get_where ( 'user', array ('email' => $email), 1, 0 );


        if ($query1->num_rows () <= 0) {
            $this->messages->add ( sprintf ( lang ( 'error_log_in' ), 'not_exist' ), "error" );
            return false;
        }
        else {
            if ($query1->first_row ()->confirm_code != 'y') {
                $this->messages->add ( sprintf ( lang ( 'error_log_in' ), 'not yet activated' ), "error" );
                return false;
            }
        }

        $salt = $query1->first_row ()->salt;

        // check for hashed password
        $saltedPW = $password . $salt;
        $hashedPW = hash ( 'sha256', $saltedPW );


        $query2 = $this->db->get_where ( 'user', array ('email' => $email, 'password' => $hashedPW), 1, 0 );


        ### FAILED LOGIN ATTEMPT, increase failed_attempt value
        if ($query2->num_rows () <= 0) {
            $this->messages->add ( sprintf ( lang ( 'error_log_in' ), 'bad_pwd' ), "error" );  

            $nb_failed_attempt = $query1->first_row ()->failed_attempt + 1;
            $data = array ('failed_attempt' => $nb_failed_attempt );

            $this->db->where('email', $email);
            $this->db->update('user', $data);
            return false;
        }


        ######## Reset failed login attempt if need be #######
        if ($query2->first_row ()->failed_attempt > 0) {

            $nb_failed_attempt = 0;
            $data = array ('failed_attempt' => $nb_failed_attempt );

            $this->db->where('email', $email);
            $this->db->update('user', $data);
        }


        ######### Save info into cookies #########
        $this->session->set_userdata ( array (
                'id_user' => $query2->first_row ()->id,
                'email' => $query2->first_row ()->email,
                'first_name' => $query2->first_row ()->first_name,
                'last_name' => $query2->first_row ()->last_name,
                'display_name' => $query2->first_row ()->display_name,
                'birthdate' => $query2->first_row ()->birthdate,
                'sex' => $query2->first_row ()->sex,
                'weight' => $query2->first_row ()->weight,
                'height' => $query2->first_row ()->height
        ) );


        return true;
    }

Here is my table "User":

CREATE TABLE IF NOT EXISTS `user` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `email` varchar(150) NOT NULL,
  `password` varchar(255) NOT NULL,
  `failed_attempt` int(3) unsigned DEFAULT 0,
  `salt` varchar(255) NOT NULL,
  `confirm_code` varchar(255),
  `reset_token` varchar(255) NOT NULL,
  `reset_token_expire` datetime DEFAULT NULL,
  `session_id` varchar(255) NOT NULL,
  `first_name` varchar(50) NOT NULL,
  `last_name` varchar(50) NOT NULL,
  `display_name` varchar(50) NOT NULL,
  `birthdate` date NOT NULL,
  `sex` char(1) NOT NULL,
  `last_ip` varchar(50) NOT NULL,
  `last_login` datetime DEFAULT NULL,
  `date_signup` datetime DEFAULT NULL,
  `os` varchar(25) NOT NULL,
  `weight` decimal(5,2) unsigned DEFAULT NULL,
  `height` decimal(5,2) unsigned DEFAULT NULL

  PRIMARY KEY (`id`),
  UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 ;
  • 写回答

1条回答 默认 最新

  • dqm88684 2014-06-13 20:21
    关注

    You may use it without cookies. Some ways are using checking remote IP in table with all IPs and counting, or just set counter for username without checking cookie or IP.

    $nb_failed_attempt for index() function is a global variable? If it's not - that your answer ($nb_failed_attempt not set everytime).

    UPD

    Start of checkLogin() should be like this:

    global $nb_failed_attempt;
    $query1 = $this->db->get_where ( 'user', array ('email' => $email), 1, 0 );
    $nb_failed_attempt = $query1->first_row ()->failed_attempt;
    if(@!$nb_failed_attempt)
        $nb_failed_attempt = 0;
    

    Start of index() should be like this:

    global $nb_failed_attempt;
    

    Check also error messages and please write, if echo $nb_failed_attempt; work.

    UPD2

    I use follow structure of session table in big projects:

    CREATE TABLE IF NOT EXISTS `session` (
        `id` bigint AUTO_INCREMENT,
        `login` char(128),
        `ip` char(128),
        `try` smallint,
        `blocktime` datetime,
        `sitesession` char(128),
        `firsttime` datetime,
        `lasttime` datetime,
        PRIMARY KEY (`id`)
    ) ENGINE=MyISAM AUTO_INCREMENT=1;
    

    It helps save additional information about logins, enters, and help to users's support.

    This table may be not fine, but it work for me.

    评论

报告相同问题?

悬赏问题

  • ¥15 关于#Java#的问题,如何解决?
  • ¥15 加热介质是液体,换热器壳侧导热系数和总的导热系数怎么算
  • ¥15 想问一下树莓派接上显示屏后出现如图所示画面,是什么问题导致的
  • ¥100 嵌入式系统基于PIC16F882和热敏电阻的数字温度计
  • ¥15 cmd cl 0x000007b
  • ¥20 BAPI_PR_CHANGE how to add account assignment information for service line
  • ¥500 火焰左右视图、视差(基于双目相机)
  • ¥100 set_link_state
  • ¥15 虚幻5 UE美术毛发渲染
  • ¥15 CVRP 图论 物流运输优化