Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/289.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 登录系统-首次未设置会话cookie_Php_Mysql - Fatal编程技术网

Php 登录系统-首次未设置会话cookie

Php 登录系统-首次未设置会话cookie,php,mysql,Php,Mysql,通过遵循各种教程和在线阅读文章,我从头创建了一个登录/注册系统。系统工作正常,但有一个我不理解的错误。当用户第一次尝试登录时,会返回一个错误,即找不到帐户,但如果用户再次尝试登录,则会继续登录。我测试了它是否存储了会话cookie,结果发现它没有(至少第一次没有)。下次用户尝试登录时,它会正确存储cookie 这是我登录脚本的第一部分,它检查输入的验证码是否正确,然后设置会话cookies并将用户重定向到登录页面脚本,该脚本检查用户是否存在 <?php session_start();

通过遵循各种教程和在线阅读文章,我从头创建了一个登录/注册系统。系统工作正常,但有一个我不理解的错误。当用户第一次尝试登录时,会返回一个错误,即找不到帐户,但如果用户再次尝试登录,则会继续登录。我测试了它是否存储了会话cookie,结果发现它没有(至少第一次没有)。下次用户尝试登录时,它会正确存储cookie

这是我登录脚本的第一部分,它检查输入的验证码是否正确,然后设置会话cookies并将用户重定向到登录页面脚本,该脚本检查用户是否存在

<?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");