Hi, I am building a login with optional two step auth (google authenticator) and just wondering whether what i am doing is secure. What currently happens is the user turns on two step auth which changes extra_security
column to 1 (activated) then on login screen once credentials correct it checks to see if activated via the switch case func and then creates the correct session.
If not activated sets the uaccess
session as 1 straight away but if 2 step is enabled then it will set it as 0 and redirect you to login2 where you then enter the code and then finally if code is correct then it unsets the authCode session and changes the uaccess session to 1. Is this secure enough or how should i do it better? Right now it is literally just looking for uaccess to be = to 1 then it logs you in fully but i don’t think this is secure enough so all feedback and improvements much appreciated!
Also any advice on how i could achieve a if failed 3 attempts do this, 5 attempts do this and then 8 attempts show a recaptcha etc.?
Thanks in advance.
Login code:
public function login()
{
if (startHelp::isLoggedIn()) { startHelp::redirect(''); exit(0); }
if (startHelp::isPartLoggedIn()) { startHelp::redirect('user/login2'); exit(0); }
if ($_SERVER['REQUEST_METHOD'] == 'POST')
{
$_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);
$this->csrf->CSRFTokenVerify();
$formData = [
'username' => trim($_POST['username']),
'password' => trim($_POST['password']),
'username_err' => '',
'password_err' => '',
];
$data = [
'formData' => $formData,
'title' => LANG['auth-login-title'],
'description' => '',
];
if (empty($data['formData']['username'])) { // Username not empty
$data['formData']['username_err'] = 'username empty';
}
if (empty($data['formData']['password'])) { // Password not empty
$data['formData']['password_err'] = 'password empty';
}
if (empty($data['formData']['username_err']) && empty($data['formData']['password_err']) && empty($data['formData']['global_err'])) {
$userAuthenticated = $this->auth->doLogin($data['formData']['username'], $data['formData']['password']);
if ($userAuthenticated && $this->auth->checkActive($data['formData']['username'])) {
switch ($userAuthenticated[0]['extra_security']) {
case 1:
$this->createUserExtraSession($userAuthenticated);
break;
default:
$this->createUserSession($userAuthenticated);
}
} elseif ($userAuthenticated && $this->auth->checkBan($data['formData']['username'])) {
$data['formData']['global_err'] = 'user banned';
$data['formData']['password'] = '';
$this->view('user/login', $data);
} elseif ($userAuthenticated && !$this->auth->checkActive($data['formData']['username'])) { // If user not active lock
$data['formData']['global_err'] = 'user not active';
$data['formData']['password'] = '';
$this->view('user/login', $data);
} else { // If user credentials incorrect then
$formData = [
'username' => trim($_POST['username']),
'password' => '',
'username_err' => 'invalid username',
'password_err' => 'invalid password',
'global_err' => '',
];
$data = [
'formData' => $formData,
'title' => LANG['auth-login-title'],
'description' => '',
];
$this->view('user/login', $data);
}
} else {
$this->view('user/login', $data);
}
} else {
$formData = [
'username' => '',
'password' => '',
'username_err' => '',
'password_err' => '',
];
$data = [
'formData' => $formData,
'title' => LANG['auth-login-title'],
'description' => '',
];
$this->view('user/login', $data);
}
}
private function createUserSession($user) // no two step auth
{
$_SESSION['uid'] = $user[0]['id'];
$_SESSION['upin'] = $user[0]['pin'];
$_SESSION['uemail'] = $user[0]['email'];
$_SESSION['uname'] = $user[0]['username'];
$_SESSION['uaccess'] = ($user[0]['extra_security'] == 0 ? '1' : '0');
$_SESSION['authCode'] = $user[0]['extra_security_code'];
startHelp::flash('message', 'success login', 'alert alert-success mb-0', 'data-auto-dismiss="10000"');
startHelp::redirect('');
exit(0);
}
private function createUserExtraSession($user)
{
$_SESSION['uid'] = $user[0]['id'];
$_SESSION['upin'] = $user[0]['pin'];
$_SESSION['uemail'] = $user[0]['email'];
$_SESSION['uname'] = $user[0]['username'];
$_SESSION['uaccess'] = ($user[0]['extra_security'] == 0 ? '1' : '0');
$_SESSION['authCode'] = $user[0]['extra_security_code'];
startHelp::redirect('user/login2');
exit(0);
}
public function login2()
{
if (startHelp::isLoggedIn()) { startHelp::redirect(''); exit(0); }
if (!startHelp::isPartLoggedIn()) { startHelp::redirect('user/login'); exit(0); }
if ($_SERVER['REQUEST_METHOD'] == 'POST')
{
$_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);
$this->csrf->CSRFTokenVerify();
$formData = [
'username' => $_SESSION['uname'],
'code' => trim($_POST['code']),
'code_err' => '',
];
$data = [
'formData' => $formData,
'title' => '',
'description' => '',
];
if (empty($data['formData']['code'])) { // Username not empty
$data['formData']['code_err'] = 'code empty';
}
if (empty($data['formData']['code_err']) && empty($data['formData']['global_err'])) {
$verifyCode = $this->auth->verifyCode($_SESSION['authCode'], $data['formData']['code'], 2); // 2 = 2*30sec clock tolerance
if ($verifyCode) {
$_SESSION['uaccess'] = '1';
unset($_SESSION['authCode']);
startHelp::flash('message', '2 step login success', 'alert alert-success mb-0', 'data-auto-dismiss="10000"');
startHelp::redirect('');
exit(0);
} else {
$formData = [
'username' => $_SESSION['uname'],
'code_err' => 'invalid code',
'global_err' => '',
];
$data = [
'formData' => $formData,
'title' => 'login to account',
'description' => '',
];
$this->view('user/login2', $data);
}
} else {
$this->view('user/login', $data);
}
} else {
$formData = [
'username' => $_SESSION['uname'],
'code' => '',
'username_err' => '',
'code_err' => '',
];
$data = [
'formData' => $formData,
'title' => 'enter code to complete login',
'description' => '',
];
$this->view('user/login2', $data);
}
}
The static helper functions:
/*
* Checks Login Authentication.
*/
public static function isLoggedIn()
{
if (isset($_SESSION['upin']) && $_SESSION['uaccess'] == 1) {
return true;
} else {
return false;
}
}
/*
* Checks Part-Login Authentication.
*/
public static function isPartLoggedIn()
{
if (isset($_SESSION['upin']) && $_SESSION['uaccess'] == 0) {
return true;
} else {
return false;
}
}