PHP会话重新生成ID会破坏某些用户

时间:2016-07-19 20:06:34

标签: php session login session-variables

我的平台上有一个有效的会话管理,我用PHP编程。

出于安全原因,我想至少在用户成功登录时重新生成会话ID,如果可能的话,我希望重新生成会话ID,以防止会话固定。

如果登录凭据正确,则登录部分如下所示。如果它们不正确或者用户还没有输入任何内容,我就不会开始会话,据我所知,会话ID的一个旧值被使用

session_set_cookie_params(1800, "/", $domain, true, true);
session_start();
session_regenerate_id(true);

每次我向服务器发出另一个请求,并检查我的会话是否有效,我打电话

session_regenerate_id(true);

我使用以下代码检查有效会话:

$domain = $_SERVER["HTTP_HOST"];

if(session_status() != PHP_SESSION_ACTIVE)
{   
    session_set_cookie_params(0, "/", $domain, true, true);
    session_start();
}

//Check if session has expired
$now = time();
if(isset($_SESSION["discard_after"]) && $now > $_SESSION["discard_after"])
{
    session_unset();
    session_destroy();
    header("Location: https://".$domain."/login.php");
    die();
}

session_regenerate_id(true);

$_SESSION["discard_after"] = $now + 120;

if ((!isset($_SESSION["loggedin"]) || !$_SESSION["loggedin"]) &&
    basename($_SERVER["PHP_SELF"]) != "login.php")
{
    header("Location: https://".$domain."/login.php");
    die();
}

我用Burp对此进行了监控并确认,当我成功登录时,会话ID会发生变化。当我浏览网站时没有任何问题和我想要的方式,会话ID也会发生变化。

然而,这种行为并不合适。我有一些用户输入正确的凭据(我知道这是因为日志),但没有有效的会话,也无法通过登录页面到主页。

我也有一个奇怪的例子,即必须登录两次(两次正确的凭证)才能设置有效的会话。这种情况对我来说不可预测以及对其他用户来说都是如此。

时,我还没有看到发生这种情况的时间,以及何时发生的情况

有关设置的一些信息。我有一个带Apache2和PHP 5.X的Ubuntu 14.04 vServer。在客户端,我在Windows 7 64x上使用最新版本的Firefox和Chrome。即使凭据正确且上面的代码确定无法执行也无法登录的用户也在Windows 7 64x上使用Chrome(我没有关于此的更多信息)。

我确定问题是session_regenerate_id(true);函数,因为如果我评论这一行,一切正常,但这个解决方案对我来说并不令人满意。我也试过一台PC,我当然从未进入过该网站,所有内容也都有效。

我无法看到导致这种情况的原因,PHP手册页并没有真正帮助我。特别是不确定的行为使我感到困惑。

直到明天我才回答,但我会重视所有有用的答案和评论。

修改

这是整个登录序列,没有不必要的东西,在我的场景中没有执行或绝对不重要。我从不输出任何东西。

if($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST["inputEmail"],
    $_POST["inputPassword"]) && $_POST["inputEmail"] !== "" &&
    $_POST["inputPassword"] !== "")
{
    $domain = $_SERVER["HTTP_HOST"];

    $passwordHash = hash("sha256", $_POST["inputPassword"]."somesecretsalt");

    //Own function which definitly works
    $connection = connectToDB("standard");

    //Get usernames and passwordhashes for checking
    $query_getUser = "SELECT id, firstname, lastname, email,
    passwordhash FROM user WHERE email = ?;";
    if($stmt = mysqli_prepare($connection, $query_getUser))
    {
        mysqli_stmt_bind_param($stmt, "s", $_POST["inputEmail"]);
        mysqli_stmt_execute($stmt);
        $userRAW = mysqli_stmt_get_result($stmt);
        mysqli_stmt_close($stmt);
    }

    if(mysqli_num_rows($userRAW) == 1)
    {
        //State: User exists
        $dataset = mysqli_fetch_array($userRAW, MYSQLI_ASSOC);
        $now = time();

        //This is the crucial part which is definitly executed because the
        // log entry in the following if clause is executed
        session_set_cookie_params(1800, "/", $domain, true, true);
        session_start();
        session_regenerate_id(true);

        if($dataset["passwordhash"] === $passwordHash)
        {
            //State: User exists, correct password

            $_SESSION["loggedin"] = true;
            $_SESSION["id"] = $dataset["id"];
            $_SESSION["email"] = $dataset["email"];
            $_SESSION["name"] = $dataset["firstname"]." ".$dataset["lastname"];

            $comment = $_SESSION["name"]." (ID:".$dataset["id"].") has logged in";
            writeToLog("Login success   ", $comment, __LINE__);

            if ($_SERVER["SERVER_PROTOCOL"] == "HTTP/1.1")
            {
                if(php_sapi_name() == "cgi")
                {
                    header("Status: 303 See Other");
                }
                else
                {
                    header("HTTP/1.1 303 See Other");
                }
            }

            header("Location: https://".$domain."/index.php");
            mysqli_close($connection);
            die();
        }
    }

    mysqli_close($connection);
}

0 个答案:

没有答案