Jump to content

Validate username and password


Jason_Wong

Recommended Posts

There is a login page called login.php, after user type their username and password into textbox, then the page direct it to the page validate, which is validate.php. In validate.php, if user do not type anything, then direct it to the login.php again; if user type their username and password worng less than 3 times, then direct it to the login.php also. However, if user type their username and password more than 3 times, then direct it to the register.php.

 

Question: i don't know how to make 3 attempts (maybe there are something worng in my page), it doesn't work, Please help, here is my validate.php

<?php
$loginErrorV = false;
$loginErrorW = false;
if(!empty($_POST['username']) && !empty($_POST['password']) && strlen($_POST['username'])!=0 && strlen($_POST['password'])!=0)
{
	//
	$username = $_POST['username'];
	$password = $_POST['username'];

	//Connect to Database
	$conn = mysql_connect("localhost", "root", "");
	if(!$conn){
		die('Could not connect:'.mysql_error());
	}
	mysql_select_db("logindb", $conn);

	//
	$sql = "Select count(username) as user_exist from logint where username = '$username' and password = '$password'";
	$result = mysql_query($sql, $conn);
	$row = mysql_fetch_assoc($result);

	//
	if($row['user_exist'] == 1){
		session_start();
		$_SESSION['username'] = $username;
		header('Location: 10586740.html');
		mysql_close($conn);
	} else {
		$loginErrorV = true;
	}
} else {
	$loginErrorW = true;
}

if($loginErrorV){
	if(isset($_COOKIE['login'])){
		if($_COOKIE['login']<3){
			header('Location:login.php');
			$attempts = $_COOKIE['login'] + 1;
		} else {
			header('Location:register.php');
		}
	}
}

if($loginErrorW){
	header('Location:login.php');
}
?>
Link to comment
Share on other sites

On a side note, there is usually a login link and sign up link which most people understand these days. If they keep attempting to login and failing...they should be able to click the forgot username/password link and get a hint or temp password emailed to them.

A session will expire, but depending how long a cookie is set, they could forever be going to the sign up page even though they are just forgetful members. Let them try to login all day if they want because eventually they will:

A) remember their login details

B) click the link sign up link

C) click the forgot username/password link

Link to comment
Share on other sites

you wouldn't want to store the number of login tries in a session variable either, since you can get a new empty session simply by not propagating the session id with the page request.

 

to detect and count failed login attempts, you need to store the information in a database. by storing each failed attempt as a separate row, along with the date/time, you can get a count of the number of failed attempts for any username within a time interval to decide what action to take.

 

edit: using this method will also let you detect if there has been a flood of attempts over a longer period of time, indicating someone is trying to break into the account.

Link to comment
Share on other sites

That's a point - I take it for granted all pages are under session management. If you forget to restart a session on some page = you just lost your session. As Mac_gyver pointed out - the definitive way would be to store the attempts in the db. Just remember to delete this data when no longer needed or else everyone who makes a typo on login will be forever redirected to the signup page lol

Link to comment
Share on other sites

None of the above suggestions will work out, and the current code is horriby insecure with all those SQL injection vulnerabilities, plaintext passwords and whatnot.

 

Right now, really all you have is a lot of mumbo-jumbo: The code looks like it's protecting your application, but anybody with a basic understanding of the mechanics can break it. That's useless. It's actually downright harmful, because it creates a false sense of security. Your users will think that their accounts are protected, but in reality you've (inadvertently) published their passwords on the Internet.

 

I understand that you're new to PHP, and that's perfectly fine. But then you shouldn't make security promises you cannot keep. Be honest. Why not make a public website which is open to everybody? This has a lot of advantages:

  • No complicated registration procedure, no stupid passwords.
  • Less code, more time for the actual content of the site. Instead of spending hours on user management details, you can simply make a nice website.

Think about it. The Internet would be a better place if we didn't have to enter a frigging password on every frigging website.

 

If you absolutely must have passwords, then I strongly recommend that you postpone the project until you have a basic understanding of web programming. No, you can't just insert user input into query strings (never heard of Little Bobby Tables?). No, you can't store your user passwords as plaintext, because somebody might break into the database and steal them (that's actually very easy in your case). No, you can't store the log-in attempts in a cookie, because cookies are controlled by the user. They can be deleted or manipulated with just a few clicks in the browser. Try it yourself.

 

For PHP basics, I recommend the PHP manual. If you look up your mysql_* functions, for example, you'll see a big red warning sign which says that those functions are long obsolete and have been replaced with the PDO library. For security basics, I recommend “Survive The Deep End” by Pádraic Brady (he also has an excellent blog).

 

Checking the number of log-in attempts is fairly difficult, and even experienced programmers constantly get it wrong. First of all, yes, you have to store the attempts per user, not per cookie or whatever. Secondly, you have to increment and check the counter in a single operation. Otherwise, there's a small time gap between the check and the increment where users can make an arbitrary number of parallel requests. For example, let's say there's a delay of 1 second between your COUNT(*) query and the increment operation. If I make a new attempt every millisecond, then your server will accept all 1000 requests, because the counter still has the old value. Only after this it is finally incremented.

 

This isn't just a theoretical threat. A stock browser and a small piece of JavaScript code are enough to send a large amount of parallel requests to a website (that's what browsers are for).

 

So a simple SELECT followed by an UPDATE doesn't work. You need a single UPDATE query which also fetches the new counter value. As a basic example:

 

The table

CREATE TABLE
    users
(
    user_id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL,
    password CHAR(60) NOT NULL COMMENT 'bcrypt',
    login_attempts INT UNSIGNED NOT NULL DEFAULT 0,
    last_login_attempt DATETIME
)
    ENGINE InnoDB,
    CHARSET utf8mb4
;

database.php

<?php

define('DB_HOST', '...');
define('DB_NAME', '...');
define('DB_USER', '...');
define('DB_PASSWORD', '...');
define('DB_ENCODING', 'utf8mb4');



function get_database_connection()
{
    $dsn = 'mysql:host=' . DB_HOST . ';dbname=' . DB_NAME . ';charset=' . DB_ENCODING . '';
    $database = new PDO($dsn, DB_USER, DB_PASSWORD, array(
        PDO::ATTR_EMULATE_PREPARES => false,
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    ));

    return $database;
}

login.php

<?php

require_once __DIR__ . '/database.php';



$database = get_database_connection();

/*
 * Increment the log-in attempts counter and fetch the new value with a single atomic operation
 * to prevent race conditions.
 *
 * If the last log-in attempt was more than 1 hour ago, the counter is reset.
 */
$loginAttemptsCheck = $database->prepare('
    UPDATE
        users
    SET
        login_attempts = LAST_INSERT_ID(IF(NOW() > last_login_attempt + INTERVAL 1 MINUTE, 1, login_attempts + 1)),
        last_login_attempt = NOW()
    WHERE
        username = :username
');
$loginAttemptsCheck->execute(array(
    'username' => $_POST['username'],
));

$loginAttempts = $database->lastInsertID();

if ($loginAttempts <= 3)
{
    // check the password; if the log-in was successful, reset the counter to 0
}
else
{
    echo 'The account is temporarily locked because of more than three failed log-in attemps within one hour.';
}

Note that a hard limit allows anybody to lock out your users simply by entering a wrong password again and again. A slightly less user-hostile approach would be a CAPTCHA: If the limit is exceeded, the user can unlock the account by solving some kind of puzzle. This also slows down attackers but doesn't lock out legtimate users entirely.

 

Sounds complicated? Like I said, proper user management is a pain in the ass for both users and developers. Don't do it unless you absolutely have to.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.