Brute Force_impossible

  1 <?php
  2 
  3 if( isset( $_POST[ 'Login' ] ) && isset ($_POST['username']) && isset ($_POST['password']) ) {
  4     // Check Anti-CSRF token
  5     checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
  6 
  7     // Sanitise username input
  8     $user = $_POST[ 'username' ];
  9     $user = stripslashes( $user );
 10     $user = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $user ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
 11 
 12     // Sanitise password input
 13     $pass = $_POST[ 'password' ];
 14     $pass = stripslashes( $pass );
 15     $pass = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
 16     $pass = md5( $pass );
 17 
 18     // Default values
 19     $total_failed_login = 3;    //对输入次数进行限制  
 20     $lockout_time       = 15;
 21     $account_locked     = false;
 22 
 23     // Check the database (Check user information)
 24     $data = $db->prepare( 'SELECT failed_login, last_login FROM users WHERE user = (:user) LIMIT 1;' );
 25     /*PDO::prepare  为 PDOStatement::execute() 方法准备要执行的SQL语句并返回一个PDOPDOStatement对象。
 26     SQL语句可以包含零个或多个命名(:name)或问号(?)参数标记,参数在SQL执行时会被替换  
 27     */
 28     $data->bindParam( ':user', $user, PDO::PARAM_STR );
 29     /*bindParam()方法指定绑定的参数提供给execute()的方法。
 30     第二个参数即$user存储着将要赋给占位符的值,
 31     PDO::PARAM_* 明确的表明了参数的类型。
 32     */
 33     $data->execute();
 34     //execute()方法负责执行准备好的查询 
 35     $row = $data->fetch();
 36 
 37     // Check to see if the user has been locked out.
 38     if( ( $data->rowCount() == 1 ) && ( $row[ 'failed_login' ] >= $total_failed_login ) )  {
 39         //rowCount()返回上一个对应的 PDOStatement 对象执行DELETE、 INSERT、或 UPDATE 语句受影响的行数
 40         // User locked out.  Note, using this method would allow for user enumeration!
 41         //echo "<pre><br />This account has been locked due to too many incorrect logins.</pre>";
 42 
 43         // Calculate when the user would be allowed to login again
 44         $last_login = strtotime( $row[ 'last_login' ] );
 45         $timeout    = $last_login + ($lockout_time * 60);
 46         $timenow    = time();
 47 
 48         /*
 49         print "The last login was: " . date ("h:i:s", $last_login) . "<br />";
 50         print "The timenow is: " . date ("h:i:s", $timenow) . "<br />";
 51         print "The timeout is: " . date ("h:i:s", $timeout) . "<br />";
 52         */
 53 
 54         // Check to see if enough time has passed, if it hasn't locked the account
 55         if( $timenow < $timeout ) {
 56             $account_locked = true;
 57             // print "The account is locked<br />";
 58         }
 59     }
 60 
 61     // Check the database (if username matches the password)
 62     $data = $db->prepare( 'SELECT * FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;' );
 63     $data->bindParam( ':user', $user, PDO::PARAM_STR);
 64     $data->bindParam( ':password', $pass, PDO::PARAM_STR );
 65     $data->execute();
 66     $row = $data->fetch();
 67 
 68     // If its a valid login...
 69     if( ( $data->rowCount() == 1 ) && ( $account_locked == false ) ) {
 70         // Get users details
 71         $avatar       = $row[ 'avatar' ];
 72         $failed_login = $row[ 'failed_login' ];
 73         $last_login   = $row[ 'last_login' ];
 74 
 75         // Login successful
 76         echo "<p>Welcome to the password protected area <em>{$user}</em></p>";
 77         echo "<img src="{$avatar}" />";
 78 
 79         // Had the account been locked out since last login?
 80         if( $failed_login >= $total_failed_login ) {
 81             echo "<p><em>Warning</em>: Someone might of been brute forcing your account.</p>";
 82             echo "<p>Number of login attempts: <em>{$failed_login}</em>.<br />Last login attempt was at: <em>${last_login}</em>.</p>";
 83         }
 84 
 85         // Reset bad login count
 86         $data = $db->prepare( 'UPDATE users SET failed_login = "0" WHERE user = (:user) LIMIT 1;' );
 87         $data->bindParam( ':user', $user, PDO::PARAM_STR );
 88         $data->execute();
 89     } else {
 90         // Login failed
 91         sleep( rand( 2, 4 ) );
 92 
 93         // Give the user some feedback
 94         echo "<pre><br />Username and/or password incorrect.<br /><br/>Alternative, the account has been locked because of too many failed logins.<br />If this is the case, <em>please try again in {$lockout_time} minutes</em>.</pre>";
 95 
 96         // Update bad login count
 97         $data = $db->prepare( 'UPDATE users SET failed_login = (failed_login + 1) WHERE user = (:user) LIMIT 1;' );
 98         $data->bindParam( ':user', $user, PDO::PARAM_STR );
 99         $data->execute();
100     }
101 
102     // Set the last login time
103     $data = $db->prepare( 'UPDATE users SET last_login = now() WHERE user = (:user) LIMIT 1;' );
104     $data->bindParam( ':user', $user, PDO::PARAM_STR );
105     $data->execute();
106 }
107 
108 // Generate Anti-CSRF token
109 generateSessionToken();
110 
111 ?>

Impossible级别的代码加入了可靠的防爆破机制,当检测到频繁的错误登录后,系统会将账户锁定,只有等待一段时间之后,才会再次登录,对此爆破也就无法继续。

同时采用了更为安全的PDO(PHP Data Object)机制防御sql注入,这是因为不能使用PDO扩展本身执行任何数据库操作,而sql注入的关键就是通过破坏sql语句结构执行恶意的sql命令。

学习PDO的网站:

http://www.runoob.com/php/php-pdo.html

http://www.cnblogs.com/pinocchioatbeijing/archive/2012/03/20/2407869.html

原文地址:https://www.cnblogs.com/guiguxiaosheng/p/9189439.html