Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to limit the number of login attempts in a login script?

Tags:

php

I cant work out how to implement the cookie code into my script. Heres my code for my pages below:

Login Page:-

<form name="loginform" class="form-horizontal" action="includes/login.php" method="post" onsubmit="return validateloginForm()">

  <div class="form-group">
    <label for="username" class="col-sm-2 control-label">Username</label>
    <div class="col-sm-10">
      <input type="text" class="form-control" name="username" placeholder="Enter the username" id="username">
    </div>
  </div>

  <div class="form-group">
    <label for="password" class="col-sm-2 control-label">Password</label>
    <div class="col-sm-10">
      <input type="password" class="form-control" name="password" placeholder="Password" id="password">
    </div>
  </div>

  <div class="form-group">
    <div class="col-sm-offset-2 col-sm-10">
      <button type="submit" name="signin" class="btn btn-primary">Sign in</button>
    </div>
  </div>
</form>

Login Check

if(isset($_POST['signin'])) {

    $username = $_POST['username'];
    $password = $_POST['password'];

    $username = mysqli_real_escape_string($connection, $username);
    $password = mysqli_real_escape_string($connection, $password);

    $query = "SELECT *FROM users WHERE username = '{$username}'";
    $select_user_query = mysqli_query($connection, $query);

    if(!$select_user_query) {
       die("QUERY FAILED". mysqli_error($connection));
    }
    while ($row = mysqli_fetch_array($select_user_query)) {
        $db_user_id = $row['user_id'];
        $db_username = $row['username'];
        $db_user_password = $row['user_password'];
        $db_user_firstname = $row['user_firstname'];
        $db_user_lastname = $row['user_lastname'];
        $db_user_role = $row['user_role'];
    }
    $password = crypt($password, $db_user_password);

    if ($username !== $db_username && $password !== $db_user_password ){
        header("Location: ../index.php");
    } else if ($username == $db_username && $password == $db_user_password) {
        $_SESSION['username'] = $db_username;
        $_SESSION['firstname'] = $db_user_firstname;
        $_SESSION['lastname'] = $db_user_lastname;
        $_SESSION['user_role'] = $db_user_role;

        header("Location: ../admin"); 
    } else {
        header("Location: ../login.php");
    }
}

I need to implement this code into the the script above

if($login_incorrect){
     if(isset($_COOKIE['login'])){
          if($_COOKIE['login'] < 3){
               $attempts = $_COOKIE['login'] + 1;
               setcookie('login', $attempts, time()+60*10); //set the cookie for 10 minutes with the number of attempts stored
          } else{
               echo 'You are banned for 10 minutes. Try again later';
          }
     } else{
          setcookie('login', 1, time()+60*10); //set the cookie for 10 minutes with the initial value of 1
     }
}

Thank you in advance. I need to limit the login to 3 times attempts and then ban them for 10mins.

like image 236
Morph9090 Avatar asked May 09 '16 15:05

Morph9090


2 Answers

Cookies are not a reliable method.
I can create a script that sends whatever cookies I want in the request.
I would use mySQL

$ip = $_SERVER["REMOTE_ADDR"];
mysqli_query($connection, "INSERT INTO `ip` (`address` ,`timestamp`)VALUES ('$ip',CURRENT_TIMESTAMP)");
$result = mysqli_query($connection, "SELECT COUNT(*) FROM `ip` WHERE `address` LIKE '$ip' AND `timestamp` > (now() - interval 10 minute)");
$count = mysqli_fetch_array($result, MYSQLI_NUM);

if($count[0] > 3){
  echo "Your are allowed 3 attempts in 10 minutes";
}

After the page is loaded add a query to delete any records older than 10 minutes.

The ip table:

CREATE TABLE IF NOT EXISTS `ip` (
  `address` char(16) COLLATE utf8_bin NOT NULL,
  `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

You should set the character set for mysqli_real_escape_string()

mysqli_set_charset($connection, "utf8")

Instead of using a redirect which causes an additional routnd trip http request,

header("Location: ../login.php");

use a much faster include:

include("../login.php");

When doing a redirect you should use the full path:

header("Location: http://example.com/login.php");

I do not like using "SELECT *", when unneeded data is returned in the query it is a waste of resources. In most queries the time to return the data takes most of the query time.

My personal preference for retrieving field values:

SELECT `user_id`,`username`,`user_password`,`user_firstname`,`user_lastname`,`user_role` FROM users WHERE ...


while (list($db_user_id,$db_username,$db_user_password,$db_user_firstname,$db_user_lastname,$db_user_role ) = mysqli_fetch_array($select_user_query, MYSQLI_NUM)) {
like image 76
Misunderstood Avatar answered Oct 26 '22 01:10

Misunderstood


For PHP you can use this Option: with session (but not secure):

<?php

function init() {
          //$showInsertDat = insert login name from your login form
          $attempts = passwordattempt($showInsertDat);

          $tries = $_SESSION['login_attempts'] = $attempts;
          echo "Versuch: " .$tries;
}

function passwordattempt($insertLoginName) {

    session_start();
    $i = 0;
    //if session is not set
    if (!isset($_SESSION['login_attempts'])) {

        //1. attempt
        $loginAttempts = $_SESSION['login_attempts'] = 1;
        return $loginAttempts;
    }

    else {
        // 1 or more attempt
        $i = $_SESSION['login_attempts'];
        $j = $i+1;

        switch ($_SESSION['login_attempts']) {
            case $i:
            $loginAttempts = $j;
        }

        //Insert login attempt into your database (if insert user exists)
        //connection to your database 
        //--> see: https://www.php-einfach.de/mysql-tutorial/crashkurs-pdo/
        $pdo = conntectToDatabase();
        if ($pdo != "") {
            $conn = $pdo;

            $name = $insertLoginName[0];

            //find out login name:
            $statement = $pdo->prepare("SELECT * FROM {your table} WHERE {your login column} = :name");

            $result = $statement->execute(array('name' => $name));
            $user = $statement->fetch();

            if ($user == true) {
                $statement = $conn->prepare("UPDATE {your table} SET {your column with login_attempts} = ? WHERE name = ?");
                $statement->execute(array($loginAttempts, $name));      
            } 
        }
        return $loginAttempts;
    }
}

init();
?>
like image 30
FixItRob Avatar answered Oct 26 '22 01:10

FixItRob