Php 登录系统-首次未设置会话cookie
通过遵循各种教程和在线阅读文章,我从头创建了一个登录/注册系统。系统工作正常,但有一个我不理解的错误。当用户第一次尝试登录时,会返回一个错误,即找不到帐户,但如果用户再次尝试登录,则会继续登录。我测试了它是否存储了会话cookie,结果发现它没有(至少第一次没有)。下次用户尝试登录时,它会正确存储cookie 这是我登录脚本的第一部分,它检查输入的验证码是否正确,然后设置会话cookies并将用户重定向到登录页面脚本,该脚本检查用户是否存在Php 登录系统-首次未设置会话cookie,php,mysql,Php,Mysql,通过遵循各种教程和在线阅读文章,我从头创建了一个登录/注册系统。系统工作正常,但有一个我不理解的错误。当用户第一次尝试登录时,会返回一个错误,即找不到帐户,但如果用户再次尝试登录,则会继续登录。我测试了它是否存储了会话cookie,结果发现它没有(至少第一次没有)。下次用户尝试登录时,它会正确存储cookie 这是我登录脚本的第一部分,它检查输入的验证码是否正确,然后设置会话cookies并将用户重定向到登录页面脚本,该脚本检查用户是否存在 <?php session_start();
<?php
session_start();
$mode = $_GET['mode'];
if($mode == 'login')
{
require_once('recaptchalib.php');
$privatekey = "---";
$resp = recaptcha_check_answer ($privatekey,
$_SERVER["REMOTE_ADDR"],
$_POST["recaptcha_challenge_field"],
$_POST["recaptcha_response_field"]);
if (!$resp->is_valid) {
// What happens when the CAPTCHA was entered incorrectly
header('Location: http://cpalander.net/login.php?option=captcha');
} else {
$user = $_POST['username2'];
$pass = $_POST['password3'];
$_SESSION['pass3'] = $pass;
$_SESSION['user3'] = $user;
header('Location: http://cpalander.net/login.php?option=checkuser');
}
die();
}
else if($mode == 'sendticket')
{
require_once('recaptchalib.php');
$privatekey = "---";
$resp = recaptcha_check_answer ($privatekey,
$_SERVER["REMOTE_ADDR"],
$_POST["recaptcha_challenge_field"],
$_POST["recaptcha_response_field"]);
if (!$resp->is_valid) {
// What happens when the CAPTCHA was entered incorrectly
header('Location: http://cpalander.net/dashboard.php?option=sendticket&error=captcha');
} else {
$subject = $_POST['subject'];
$message = $_POST['message'];
header('Location: http://cpalander.net/dashboard.php?option=sendticket&subject=' . urlencode($subject) . '&message=' . urlencode($message));
}
die();
}
else
{
require_once('recaptchalib.php');
$privatekey = "---";
$resp = recaptcha_check_answer ($privatekey,
$_SERVER["REMOTE_ADDR"],
$_POST["recaptcha_challenge_field"],
$_POST["recaptcha_response_field"]);
if (!$resp->is_valid) {
// What happens when the CAPTCHA was entered incorrectly
header('Location: http://cpalander.net/register.php?option=captcha');
} else {
$_SESSION['user2'] = $_POST['username'];
$_SESSION['pass2'] = $_POST['password'];
$_SESSION['mail2'] = $_POST['email'];
header('Location: http://cpalander.net/makeacc.php');
}
die();
}
?>
这是检查用户是否存在并在出现错误时重定向用户的代码部分:
<?php session_start();
$data = $_GET["option"];
$user = $_SESSION['user3'];
$pass = $_SESSION['pass3'];
function generateRandomString($length = 10)
{
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[rand(0, strlen($characters) - 1)];
}
return $randomString;
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>....</head>...
<body>...
...<?php
if ($data == 'checkuser')
{
$user = $_SESSION['user3'];
$link = new mysqli('127.0.0.1', '*******', '*******', '*******');
if ($link->connect_errno) {
die('Failed to connect to MySQL: (' . $mysqli->connect_errno . ') ' . $mysqli->connect_error);
}
$result = $link->query("SELECT * FROM users WHERE username='$user' AND active=1 AND banned=0");
$numrows = $result->num_rows;
if($numrows == 0)
{
$link->close();
session_destroy();
echo '<META HTTP-EQUIV="Refresh" Content="0; URL=login.php?option=notfound&user=' . $user . '">'; // This is the part that I used to check if the $user variable is set
exit;
}
$row = $result->fetch_assoc();
$sid = $row['salt'];
$pass_h = hash('sha256', $sid . $pass);
$result = $link->query("SELECT * FROM users WHERE username='$user' AND password='$pass_h' AND active=1 AND banned=0");
$numrows = $result->num_rows;
if($numrows == 0)
{
$link->close();
session_destroy();
echo '<META HTTP-EQUIV="Refresh" Content="0; URL=login.php?option=notfound">';
exit;
}
else
{
$link->close();
$_SESSION['user'] = $user;
echo '<META HTTP-EQUIV="Refresh" Content="0; URL=dashboard.php?option=home&user=' . $user . '">';
exit;
}
$link->close();
}...</body>
.......
...
…需要访问$会话
变量的所有文件中都应包含会话
启动
。这意味着,如果要访问不相关的文件,则需要添加session_id()或session_start()代码>发送给他们(会话id()或会话开始()
部分是为了确保如果在同一请求中对同一文件进行了请求/包含,则不会显示对已启动会话的恐惧警告)
session\u destroy()
销毁会话,您可能只想session\u unset()
,因为session\u destroy()
将在再次调用session\u start()
时重新创建会话。但是,如果您真的想销毁会话并重新启动,跨浏览器的方法是调用session\u unset()
和session\u destroy()
(cough IE cough)
另外,您应该注意,除了问题本身之外,您还允许在代码上存在XSS漏洞,方法是将原始
$\u POST
数据传递到URL,而不进行检查 代码看起来好像应该工作。在找不到用户时销毁会话,
所以没有理由让它第二次工作,而不是第一次。。。除非有
之前发生的事情,依赖于一些会话数据,而您没有发布这些数据
唯一不确定的是两个登录字段分别命名为username2和username2
password3,但我想如果这是一个问题,您应该每次都会出错-除非
您生成“username2”或“username3”以响应不同的条件
除此之外,我还有一些建议:
1)
可以放在开头,因为您似乎无论如何都在使用它
而不是
$user = $_POST['username2'];
$pass = $_POST['password3'];
$_SESSION['pass3'] = $pass;
$_SESSION['user3'] = $user;
你可以把它放进去(但以后会有更多的内容)
你不需要三个独立的模具,事实上我认为你不需要它们
在这一点上:
if ($data == 'checkuser')
{
$user = $_SESSION['user3'];
您没有检查$\u会话['user3']是否已实际设置。你可能会出错
正因为如此。事实上,您之前已经分配了$user(同样没有检查)
它已经被设定了)
这里的争吵真的很危险
$result = $link->query("SELECT * FROM users WHERE username='$user' AND active=1 AND banned=0");
因为如果我向您发送一个值为“bobby”或“=”的“username2”,您的查询将变成:
$link->query("SELECT * FROM users WHERE username='bobby' OR ''='' AND active=1 AND banned=0");
由于“=”总是正确的,所以小Bobby Tables可能已经登录,即使处于非活动状态且被禁止
然后将密码存储在会话中的clear中,我承认这没有什么危险,但这仍然比没有危险更糟糕。为什么不存储一个散列呢
$_SESSION['pass'] = hash('sha256', $_POST['password3']); // unsalted password
$_SESSION['user'] = hash('sha256', $_POST['username2']); // unsalted username
...
$link->query("SELECT * FROM users WHERE SHA2(username,256)='$user'
AND SHA2(CONCAT(salt,'$pass'),256)=password AND active=1 AND banned=0");
现在,不管你把什么放入$_POST,它都会被碾碎并消化成两个安全的散列。这个
会话不再包含用户名或密码。密码仍然是咸的。如果有的话
用户不存在、被禁止、不活动或密码错误,查询将不产生结果,
而且它的成本永远是一样的,可以击败大多数定时攻击
如果你保持用户名/密码的透明,那么你需要
mysqli_escape()
它来避免SQL注入攻击(或与绑定参数一起使用)。查看这篇文章上的日期,我发现我参加聚会迟到了,但我发现这是因为我遇到了一个非常类似的问题。见我的帖子
下面是一个可能缩小问题范围的实验:从您的页面浏览,转到浏览器的cookie并删除该域的cookie,浏览回登录页面,然后检查是否存在PHPSESSID cookie。我猜不会有了。然后尝试登录(您说登录失败)。然后再次检查cookies-PHPSESSID将在那里。然后,下一次登录尝试开始工作
现在,请尝试以下操作:再次清除该域的cookies,然后浏览到该登录页面,并在URL末尾显示?nocache=1
。这一次可能会有一个PHPSESSID cookie,而这一次登录将在第一次尝试时起作用
在我的例子中,?nocache=1
可以工作,但当我在本地主机上本地运行相同的代码时,甚至不需要它
它看起来绝对像是服务器上的会话处理设置。您应该隐藏私钥,并更改:)如果第二部分的开头是另一个文件+1,那么您也必须在第二部分的开头有session_start()mysql@Jan卡尼-是的,我正要这么做,但pocesar打败了我xD Sebas-是的,我在文件的开头,在任何HTML输出或任何pocesar之前就有了它-我做了一些研究,从一开始就使用它来添加我的2美分作为评论似乎是最好的选择,因为不是100%确定-但是你可能想在这里研究跨浏览器问题,我曾经遇到过这样一个问题,cookies和会话没有正确设置,因为我必须提示用户输入-现在网站在设置cookie之前必须请求交互似乎已经成为一个常见的地方-值得研究吗?我的会话从代码的顶部开始,我不想发布完整的代码,因为它包含
$link->query("SELECT * FROM users WHERE username='bobby' OR ''='' AND active=1 AND banned=0");
$_SESSION['pass'] = hash('sha256', $_POST['password3']); // unsalted password
$_SESSION['user'] = hash('sha256', $_POST['username2']); // unsalted username
...
$link->query("SELECT * FROM users WHERE SHA2(username,256)='$user'
AND SHA2(CONCAT(salt,'$pass'),256)=password AND active=1 AND banned=0");