Skip to main content
added 3470 characters in body
Source Link

As you requested, I tried to add some code examples around my suggestion:

<?php

//the db interaction is pseudo code, because it depends on the API you are using
/**
 * 
 * @param int $success : 0 for fail, 1 for success
 */
function logAttempt($success) {
    $user = $db->escape($_POST['userName']);
    $pass = $db->escape($_POST['password']);
    $session_id = session_id();
    if (!in_array($success, array(0, 1))) {
        return false;
    }
    $db->query("INSERT INTO `log_attempts` 
                    (`user`, `pass`, `ip`, `session_id`, `success`, `tried_on`)
                VALUES
                    ('$user', '$pass', '{$_SERVER['REMOTE_ADDR']}', '$session_id', '$success', NOW());
            ");
    return $db->affected_rows > 0;
}

function isAttemptsLimitExceeded() {
    $max_attempts = 5;
    $session_id = session_id();
    $res = $db->query("SELECT 
                            COUNT(*) AS cnt
                        FROM 
                            `log_attempts`
                        WHERE
                            `session_id` = '$session_id' AND
                            `tried_on` > DATE_SUB(NOW(), INTERVAL 24 HOUR) AND
                            `success` = '0';
                    ");
    $row = $db->fetch($res);
    if ($row['cnt'] >= $max_attempts) {
        return true;
    }
    return false;
}

function banFailedLogins() {
    if(isAttemptsLimitExceeded()) {
        $db->query("INSERT INTO `blacklist`
                        (`ip`, `banned_on`)
                    VALUES
                        ('{$_SERVER['REMOTE_ADDR']}', NOW()");
    }
    return $db->affected_rows > 0;
}

function clearBans() {
    $db->query("DELETE from `blacklist` WHERE `ip` = '{$_SERVER['REMOTE_ADDR']}';");
    return $db->affected_rows > 0;
}

//check for expired bans?
function canAcess() {
    $ban_expire = 24; // hours
    $res = $db->query("SELECT 
                            COUNT(*) AS cnt 
                        FROM 
                            `blacklist` 
                        WHERE 
                            `ip` = '{$_SERVER['REMOTE_ADDR']}' AND
                            `banned_on` > DATE_SUB(NOW(), INTERVAL $ban_expire HOUR);
                        ");
    $row = $db->fetch($res);
    if ($row['cnt'] > 0) {
        return false;
    }
    else {
        clearBans();
        return true;
    }
}

if (!canAcess()) {
    die("You are banned for failed login attempts");
}
  if (isset($_POST['password']) && isset($_POST['userName'])) {
    if ($_POST['password'] == "myPassword" && $_POST['userName'] == "myUsername") {
      if (!session_id()) {
        session_start();
        $_SESSION['logon'] = true;
        logAttempt(1); //log successfull attempt
        header('Location: admin_area.php');
        die();
      }
    } else if ($_POST["password"] == "" || $_POST["userName"] == "") {
      echo "Please enter both a username and a password! You are sent back in 3 seconds";
      logAttempt(0); //log failed attempt
      banFailedLogins();
      echo "<meta http-equiv='refresh' content='3;url=login.html'>";
    } else {
      echo "Wrong username and/or password! You are set back in 3 seconds";
      logAttempt(0); //log failed attempt
      banFailedLogins();
      echo "<meta http-equiv='refresh' content='3;url=login.html'>";
    }
  } else {
    echo "This is a restricted area, you have to log in!";
    echo "<meta http-equiv='refresh' content='3;url=login.html'>";
  }

?>

As you requested, I tried to add some code examples around my suggestion:

<?php

//the db interaction is pseudo code, because it depends on the API you are using
/**
 * 
 * @param int $success : 0 for fail, 1 for success
 */
function logAttempt($success) {
    $user = $db->escape($_POST['userName']);
    $pass = $db->escape($_POST['password']);
    $session_id = session_id();
    if (!in_array($success, array(0, 1))) {
        return false;
    }
    $db->query("INSERT INTO `log_attempts` 
                    (`user`, `pass`, `ip`, `session_id`, `success`, `tried_on`)
                VALUES
                    ('$user', '$pass', '{$_SERVER['REMOTE_ADDR']}', '$session_id', '$success', NOW());
            ");
    return $db->affected_rows > 0;
}

function isAttemptsLimitExceeded() {
    $max_attempts = 5;
    $session_id = session_id();
    $res = $db->query("SELECT 
                            COUNT(*) AS cnt
                        FROM 
                            `log_attempts`
                        WHERE
                            `session_id` = '$session_id' AND
                            `tried_on` > DATE_SUB(NOW(), INTERVAL 24 HOUR) AND
                            `success` = '0';
                    ");
    $row = $db->fetch($res);
    if ($row['cnt'] >= $max_attempts) {
        return true;
    }
    return false;
}

function banFailedLogins() {
    if(isAttemptsLimitExceeded()) {
        $db->query("INSERT INTO `blacklist`
                        (`ip`, `banned_on`)
                    VALUES
                        ('{$_SERVER['REMOTE_ADDR']}', NOW()");
    }
    return $db->affected_rows > 0;
}

function clearBans() {
    $db->query("DELETE from `blacklist` WHERE `ip` = '{$_SERVER['REMOTE_ADDR']}';");
    return $db->affected_rows > 0;
}

//check for expired bans?
function canAcess() {
    $ban_expire = 24; // hours
    $res = $db->query("SELECT 
                            COUNT(*) AS cnt 
                        FROM 
                            `blacklist` 
                        WHERE 
                            `ip` = '{$_SERVER['REMOTE_ADDR']}' AND
                            `banned_on` > DATE_SUB(NOW(), INTERVAL $ban_expire HOUR);
                        ");
    $row = $db->fetch($res);
    if ($row['cnt'] > 0) {
        return false;
    }
    else {
        clearBans();
        return true;
    }
}

if (!canAcess()) {
    die("You are banned for failed login attempts");
}
  if (isset($_POST['password']) && isset($_POST['userName'])) {
    if ($_POST['password'] == "myPassword" && $_POST['userName'] == "myUsername") {
      if (!session_id()) {
        session_start();
        $_SESSION['logon'] = true;
        logAttempt(1); //log successfull attempt
        header('Location: admin_area.php');
        die();
      }
    } else if ($_POST["password"] == "" || $_POST["userName"] == "") {
      echo "Please enter both a username and a password! You are sent back in 3 seconds";
      logAttempt(0); //log failed attempt
      banFailedLogins();
      echo "<meta http-equiv='refresh' content='3;url=login.html'>";
    } else {
      echo "Wrong username and/or password! You are set back in 3 seconds";
      logAttempt(0); //log failed attempt
      banFailedLogins();
      echo "<meta http-equiv='refresh' content='3;url=login.html'>";
    }
  } else {
    echo "This is a restricted area, you have to log in!";
    echo "<meta http-equiv='refresh' content='3;url=login.html'>";
  }

?>
Source Link

Tha major security issue I see is that you do not have any limiting or logs for wrong/success attempts. One can use automated brute force attacks trying all day/night long to guess your username and password. If lack of success, at least you might have your app slowed down, because of the billion requests.