Reputation: 71
I am building a login script with a brute force checker that, when triggered, displays reCAPTCHA. The problem that I am having is that when the correct username/password/captcha response are entered, the login script runs but not until the majority of the page content has loaded (this happens after the form is submitted). The result is that I must hit F5 to refresh the page and resubmit the form data in order for the session to be active when the page begins to load.
Now, the problem that I am having is that, once the form is submitted (when it requires a CAPTCHA that is), the session is not started until index.php gets to
else {
$captchaResponse = 1;
$auth = Auth::verifyPass($userName,$password,$captchaResponse);
}
I am stumped as to how I can reorganize this so that the session is started way before that. Any ideas?
The first part is the index.php page containing the code that is triggered if a brute force attempt is detected. This portion of the code begins with the conditional if($auth === "bruteForce") This code displays reCAPTCHA and is supposed to submit the username, password and reCAPTCHA response code (0-incorrect response, 1-correct response) back to the login function.
<?php
include('includes/header.php');
spl_autoload_register(function ($class){
include 'includes/class.' . $class . '.php';
});
if(null !==(filter_input(INPUT_POST,'userName'))){$userName = filter_input(INPUT_POST,'userName');}
if(null !==(filter_input(INPUT_POST,'password'))){$password = filter_input(INPUT_POST,'password');}
if(isset($userName)&& isset($password)){
$auth = Auth::verifyPass($userName,$password);
}
if(isset($_GET['logout']) && $_GET['logout'] == true){
session_start();
session_destroy();
setcookie ("PHPSESSID", "", time() - 3600, "/");
header("Location: index.php");
}
if(Auth::checkLoggedIn() === true){
if(session_id() !== ''){echo 'Session ID is not blank<br />';}
echo '<a href="index.php?logout=true">Logout</a><br />';
echo 'Welcome! This is protected content!' . "<br />";
}
if(!Auth::checkLoggedIn()) :
?>
<h1>Sign In</h1>
<?php if(isset($userName) && isset($password)){if($auth === "invalidPassword"){echo '<span class="error">Invalid username or password</span>';}} ?>
<form name="login" method="post" action="index.php" id="loginForm">
<ul>
<li>
<input placeholder="Username" type="text" name="userName" id="userName" class="login" />
</li>
<li>
<input placeholder="Password" type="password" name="password" id="password" class="login" />
</li>
<?php
if(isset($userName) && isset($password)){
echo $auth . "<br />";
if($auth === "bruteForce"){
echo $auth;
require_once('includes/recaptchalib.php');
// Get a key from https://www.google.com/recaptcha/admin/create
$publickey = "xxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
$privatekey = "xxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
$resp = null;
$error = null;
if(isset($_POST["recaptcha_response_field"])){
$resp = recaptcha_check_answer ($privatekey,
$_SERVER["REMOTE_ADDR"],
$_POST["recaptcha_challenge_field"],
$_POST["recaptcha_response_field"]);
if ($resp->is_valid) {
Auth::checkLoggedIn();
$auth = Auth::verifyPass($userName,$password,1);
} else {
$auth = Auth::verifyPass($userName,$password,0);
//$captchaResponse = 2;
}
}
echo recaptcha_get_html($publickey, $error);
if($auth === "invalidCaptcha"){
echo "Invalid Captcha Response. Please try again.";
}
}
}
if(isset($auth)){echo $auth;}
?>
<div class="clearAll"> </div>
<li id="submit">
<input type="submit" value="Login" id="loginBtn" class="login" />
</li>
<li id="reset">
<input type="reset" value="Reset" id="resetBtn" class="login" />
</li>
</ul>
</form>
<div class="clearAll"> </div>
<h1>New User?</h1>
<p><a href="register.php">Sign Up!</a></p>
<?php endif; ?>
<div class="clearAll"> </div>
<?php include('includes/footer.php'); ?>
</body>
</html>
This is the log in function
public static function verifyPass($username,$password,$captchaResponse = 3){
$authenticatedUser = FALSE;
$bruteTest = self::_bruteTest($username);
if($bruteTest === TRUE && $captchaResponse === 3){
$status = "bruteForce";
return $status;
} else if($bruteTest === TRUE && $captchaResponse === 0){
//The brute force check was positive and the captcha response failed
//Don't even try to log in because the captcha failed.
$status = "invalidCaptcha";
return $status;
} else if ($bruteTest === TRUE && $captchaResponse === 1){
//The brute force check was positive and the captcha response was successful
//Try to log in now.
$continueLogin = TRUE;
} else if($bruteTest === FALSE){
//The bruteTest was negative, proceed with login.
$continueLogin = TRUE;
}
if($continueLogin === TRUE){
try{
$connection = Database::getDbConnection();
if($connection){
$query = "SELECT usr_name, usr_pass, usr_salt, uid, email_pri FROM users WHERE usr_name=? LIMIT 1";
$stmt = $connection->prepare($query);
$stmt->execute(array($username));
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
if($stmt->rowCount() === 0){$authenticatedUser = FALSE;} //Username was not found We are not going to say which was incorrect, only that the "username or password was incorrect"
if($results){
$resultsArray = $results[0];
$connection = null;
echo "<br />";
$dbUserName = $resultsArray['usr_name'];
$dbPass = $resultsArray['usr_pass'];
$dbSalt = $resultsArray['usr_salt'];
$dbUid = $resultsArray['uid'];
$dbEmail = $resultsArray['email_pri'];
$passHash = hash('sha512',$password);
$passToCheck = hash('sha512',$dbSalt.$passHash);
if($passToCheck != $dbPass){
$authenticatedUser = FALSE; //Password did not match. We are not going to say which was incorrect, only that the "username or password was incorrect"
} else if ($passToCheck === $dbPass && $username === $dbUserName){
$authenticatedUser = TRUE;
}
}
}else if(!$results){$authenticatedUser = FALSE;}
} catch (PDOException $e) {
echo "Error: " . $e->getMessage() . "<br />";
die();
}
try{
if($authenticatedUser === FALSE){
//Log the failed attempt into the database
$remoteIp = $_SERVER['REMOTE_ADDR'];
try {
$connection = Database::getDbConnection();
if($connection){
$query = "INSERT INTO `login_attempts`(`usr_name`, `usr_ip`) VALUES (:usr_name,INET_ATON(:usr_ip))";
$stmt = $connection->prepare($query);
$stmt->execute(array(':usr_name' => $username, ':usr_ip' => $remoteIp));
}
$connection = null;
} catch (PDOException $e){
echo "Error: " . $e->getMessage() . "<br />";
die();
}
$status = "invalidPassword";
return $status;
exit();
}else if($authenticatedUser === TRUE){
//Clear login attempts from the database
self::_clearAttempts($username);
//Start the session (if not already started somehow. session and cookie expiration need to be adjusted so that the session does not persist after browser close)
if(!isset($_SESSION)){
session_start();
}
//Set the session variables
$_SESSION['userIp'] = $_SERVER['REMOTE_ADDR'];
$_SESSION['userName'] = $dbUserName;
$_SESSION['userAgent'] = $_SERVER['HTTP_USER_AGENT'];
$session_name = 'sec_session_id';
$httponly = TRUE;
$cookieParams = session_get_cookie_params();
session_set_cookie_params($cookieParams["lifetime"],
$cookieParams["path"],
$cookieParams["domain"],
$httponly);
session_name($session_name);
}
} catch (PDOException $e) {
echo "Error: " . $e->getMessage() . "<br />";
die();
}
//End $continueLogin statement below
}
}
Upvotes: 7
Views: 1045
Reputation: 1239
As les said above: session_start at the top of your page (or even having it configured to auto-prepend to every php script, with session_auto_start=1 in your PHP ini) will cause your session data to be loaded at script startup.
You can then test in the same place you test for null username and password, for some variable like $session['lastPasswordWasInvalid'] and if it's set, check whether the captcha is null.
Upvotes: 0
Reputation: 584
Move this:
if(!isset($_SESSION)){
session_start();
}
to the top of your script and try it.
or just:
session_start();
Upvotes: 1