我已经为此苦苦挣扎了几个小时,只是无法弄清楚我错过了什么。
我正在尝试构建一个无 cookie 登录表单,该表单在会话变量中也没有任何信息,如果攻击者能够修改它们会损害应用程序。
我所有的页面都包含以下代码。
我有两个问题:
每次我点击另一个页面时,它的行为就像 $_SESSION['token'] 是空的,并像第一次访问一样进入登录页面。
它返回 $tokenid 和 $tokentype 为空,但是每次加载页面时我都会调用它们(旨在避免将它们放入会话变量中)。
这是我当前的代码:
<?php
define('TIMEOUTMIN', 15);
define('LOCKOUTMIN', 10);
define('LOCKOUTNUM', 3);
include("includes/pp/pbkdf2.php"); // this is basically calling the validate_password function
include ("includes/vars/vars_dbconn.php"); // this contains the db data and $pdo
$userid = $_POST['userid'];
$userpw = $_POST['password'];
$deltoq = "UPDATE LoginUser SET token = ?, online = ? WHERE online < ?";
$prepdeltoq = $pdo->prepare($deltoq);
$prepdeltoq->execute(array(NULL,NULL,time()));
$loginq = "SELECT * FROM LoginUser WHERE ID = ?";
$preplq = $pdo->prepare($loginq);
$preplq->execute(array($userid));
$getuser = $preplq->fetch(PDO::FETCH_ASSOC);
$dbid = $getuser['ID'];
$dbpass = $getuser['hash'];
$dbbp = $getuser['bp'];
$dbltime = $getuser['ltimeout'];
$logintoq = "SELECT * FROM LoginUser WHERE token = ?";
$prepltq = $pdo->prepare($logintoq);
$prepltq->execute(array($_SESSION['token']));
$getoken = $prepltq->fetch(PDO::FETCH_ASSOC);
$tokenid = $getoken['ID'];
$tokentype = $getoken['type'];
$totoken = $getoken['token'];
$prolonglock = $pdo->prepare("UPDATE LoginUser SET ltimeout = ? WHERE ID = ?");
$addbp = $pdo->prepare("UPDATE LoginUser SET bp = ? WHERE ID = ?");
$loginwhen = $pdo->prepare("UPDATE LoginUser SET lastlogin = ? WHERE ID = ?");
$loginlogq = $pdo->prepare("INSERT INTO LoginUserLog (ID, action)
VALUES(:ID, :action)");
$logintokenid = $pdo->prepare("UPDATE LoginUser SET token = ? WHERE ID = ?");
$loginonid = $pdo->prepare("UPDATE LoginUser SET online = ? WHERE ID = ?");
$loginontok = $pdo->prepare("UPDATE LoginUser SET online = ? WHERE token = ?");
if(!function_exists('LoginUser')) {
function LoginUser($pwmessage) {
if (session_name() <> 'MyWebApp') session_name('WesoftskyLogin');
if (!session_id()) session_start();
$_SESSION['token'] = '';
include ("includes/header.php"); ?>
<meta name="description" content="Login - MyWebApp"/>
<title>Login - MyWebApp</title>
<script type="text/javascript">
event.keyCode == '';
function enterTab() {
if (event.keyCode == 13) {
var passInput = document.getElementById("password");
passInput.focus();
}
}
</script>
</head>
<body onkeyup="enterTab()">
<div id="homewrap">
<div id="hometitle">MyWebApp</div>
</div>
<div id="id_formwrap">
<form action="<?php echo htmlspecialchars($_SERVER['REQUEST_URI'].$_SERVER['QUERY_STRING']); ?>" method="post">
<?php if (empty($pwmessage)) echo '<div>Please enter your login details</div>'; else echo '<div style="color:red">'.$pwmessage.'</div>'; ?><br />
Login ID<br />
<input type="text" name="userid" id="id" onKeyPress="return noenter(event)" /><br /><br />
<script>document.getElementById("id").focus()</script>
Password<br />
<input type="password" name="password" id="password" /><br /><br />
<input type="submit" name="login" id="Submit" value="Login" />
</form>
</div>
</body>
</html>
<?php exit();
}
}
if(!function_exists('ProlongTime')) {
function ProlongTime() {
global $userid;
global $logintokenid;
global $loginonid;
global $loginontok;
$timeoutodb = (time () + TIMEOUTMIN*60);
if (!empty($userid)) {
$_SESSION['token'] = bin2hex(mcrypt_create_iv(16, MCRYPT_DEV_URANDOM));
$logintokenid->execute(array($_SESSION['token'], $userid));
$loginonid->execute(array($timeoutodb, $userid));
} else {
$loginontok->execute(array($timeoutodb, $_SESSION['token']));
}
}
}
if ($dbltime > time()) {
$lockcheck = time() + LOCKOUTMIN*60;
$prolonglock->execute(array($lockcheck,$userid));
LoginUser('Your account is currently locked');
}
if(isset($_POST['logout'])) {
$action = "Logged OUT";
$loginlogq->execute(array(':ID' => $tokenid, ':action' => $action));
LoginUser('Logged out');
}
if (isset($_POST['login'])) {
if ($dbid AND validate_password($userpw, $dbpass)) { // Good login info
//session_regenerate_id(true);
$action = "Logged IN";
$loginlogq->execute(array(':ID' => $userid, ':action' => $action));
$loginwhen->execute(array(time(), $userid));
$addbp->execute(array(NULL, $userid));
ProlongTime();
} else { // Bad login info
if ($dbbp >= LOCKOUTNUM-1) {
$lockbp = time() + LOCKOUTMIN*60;
$prolonglock->execute(array($lockbp,$userid));
$action = "Locked (wrong password)";
$loginlogq->execute(array(':ID' => $userid, ':action' => $action));
LoginUser('Your account has been locked');
}
$addbp->execute(array($dbbp+1, $userid));
$action = "Failed login";
$loginlogq->execute(array(':ID' => $userid, ':action' => $action));
LoginUser('Username or password is incorrect');
}
} elseif (empty($_SESSION['token'])) { // Loading the page first time (new session)
LoginUser('');
} elseif ($_SESSION['token'] <> $totoken) { // Session timeout
$action = "Logged OUT (expired)";
$loginlogq->execute(array(':ID' => $tokenid, ':action' => $action));
echo 'tokenid: '.$tokenid;
} else ProlongTime(); // While using the app and still within time
$pdo = null;
?>