1

PHP の知識を深めるために簡単な cms を作成していますが、残念ながら Cookie が機能していないようです。問題の核心であると思われるファイルを以下に示します。

<?php 

    // First we execute our common code to connection to the database and start the session 
    require("common.php");     

    // Detect if the user has a cookie available. If a cookie is availbale, and a valid
    // session is found then redirect the user to the appropriate QUEST landing page
    if(isset($_COOKIE["qcore"]))
    {
        $query = " 
                SELECT  TOP 1
                        u.*
                FROM    dbo.[User] AS u
                        INNER JOIN dbo.UserSession AS us
                            ON us.UserId = u.UserId
                WHERE   us.SessionId = :sessiontoken";

            // The parameter values 
            $query_params = array( 
                ':sessiontoken' => $_COOKIE["qcore"] 
            ); 

        try 
        { 
            // Execute the query against the database 
            $stmt = $db->prepare($query); 
            $result = $stmt->execute($query_params);            
        } 
        catch(PDOException $ex) 
        { 
            // Note: On a production website, you should not output $ex->getMessage(). 
            // It may provide an attacker with helpful information about your code.  
            die("Failed to run query: " . $ex->getMessage()); 
        }

        // Retrieve the user data from the database.  If $row is false, then the session has 
        // likely expired and the user will be presented with the login form again.
        $row = $stmt->fetch(); 

        // This statement checks if data was available when retreiving user information
        // using our session token.
        if($row)
        {
            // Here I am preparing to store the $row array into the $_SESSION by 
            // removing the salt and password values from it.  Although $_SESSION is 
            // stored on the server-side, there is no reason to store sensitive values 
            // in it unless you have to.  Thus, it is best practice to remove these 
            // sensitive values first. 
            unset($row['Salt']); 
            unset($row['Password']); 

            // This stores the user's data into the session at the index 'user'. 
            // We will check this index on the private members-only page to determine whether 
            // or not the user is logged in.  We can also use it to retrieve 
            // the user's details. 
            $_SESSION['user'] = $row; 

            // Redirect the user to the private members-only page. 
            // This will need to be changed once we have the QUEST logic flow sorted out
            // to be the landing quest page.
            header("Location: private.php"); 
            die("Redirecting to: private.php"); 
        }
        else
        {
            // If no data is found then the session has expired, or been terminated
            // and we need to remove the cookie to present the login form to the user
            // To do this we set the cookie expiration date to one hour ago
            setcookie("qcore", "", time()-3600);
        }
    }

    // This variable will be used to re-display the user's username to them in the 
    // login form if they fail to enter the correct password.  It is initialized here 
    // to an empty value, which will be shown if the user has not submitted the form. 
    $submitted_username = ''; 

    // This if statement checks to determine whether the login form has been submitted 
    // If it has, then the login code is run, otherwise the form is displayed
    if(!empty($_POST))
    {
        // This query retreives the user's information from the database using 
        // their username. SELECT TOP 1 prevents people from being able to edit
        // their HTTP POST to fetch the entire table.
        $query = " 
            SELECT TOP 1
                *
            FROM dbo.[User]  
            WHERE 
                Username = :username 
        "; 

        $query_params = array( 
            ':username' => $_POST['username'] 
        ); 

        try 
        { 
            // Execute the query against the database 
            $stmt = $db->prepare($query); 
            $result = $stmt->execute($query_params);            
        } 
        catch(PDOException $ex) 
        { 
            // Note: On a production website, you should not output $ex->getMessage(). 
            // It may provide an attacker with helpful information about your code.  
            die("Failed to run query: " . $ex->getMessage()); 
        } 

        // This variable tells us whether the user has successfully logged in or not. 
        // We initialize it to false, assuming they have not. 
        // If we determine that they have entered the right details, then we switch it to true. 
        $login_ok = false; 

        // Retrieve the user data from the database.  If $row is false, then the username 
        // they entered is not registered.
        $row = $stmt->fetch();

        if($row) 
        { 
            // Using the password submitted by the user and the salt stored in the database, 
            // we now check to see whether the passwords match by hashing the submitted password 
            // and comparing it to the hashed version already stored in the database. 
            $check_password = hash('sha256', $_POST['password'] . $row['Salt']); 
            for($round = 0; $round < 65536; $round++) 
            { 
                $check_password = hash('sha256', $check_password . $row['Salt']); 
            } 

            if($check_password === $row['Password']) 
            { 
                // If they do, then we flip this to true 
                $login_ok = true; 
            } 
        } 

        // If the user logged in successfully, then we send them to the private members-only page 
        // Otherwise, we display a login failed message and show the login form again 
        if($login_ok) 
        { 
            // Here I am preparing to store the $row array into the $_SESSION by 
            // removing the salt and password values from it.  Although $_SESSION is 
            // stored on the server-side, there is no reason to store sensitive values 
            // in it unless you have to.  Thus, it is best practice to remove these 
            // sensitive values first. 
            if(!empty($_POST))
            {
                unset($row['Salt']); 
                unset($row['Password']); 
            }
            // This stores the user's data into the session at the index 'user'. 
            // We will check this index on the private members-only page to determine whether 
            // or not the user is logged in.  We can also use it to retrieve 
            // the user's details. 
            $_SESSION['user'] = $row; 

            // Generate a session token which is used locally as a key between the users cookie
            // and their UserID, this prevents  the user from being able to edit their cookie
            // to login as another user.
            $sessiontoken = dechex(mt_rand(0, 2147483647)) . dechex(mt_rand(0, 2147483647));

            // Save our cookie 'qcore' with the users session id
            setcookie("qcore", $sessiontoken);

            // Insert a new session ID record, or update if one already exists. One should never
            // exist but this is added as a precaution in case a session has expired whilst the login
            // form was being filled out (EXTREMELY unlikely), but hey, why not.
            $query = "
                DECLARE @userid AS INTEGER = :userid
                DECLARE @sessionid AS varchar(500) = :sessionid

                IF EXISTS ( SELECT  TOP 1 * 
                            FROM    dbo.UserSession 
                            WHERE   UserId = @userid    )
                                UPDATE  dbo.UserSession 
                                SET     SessionId = @sessionid
                                WHERE   UserId = @userid
                ELSE
                            INSERT INTO dbo.UserSession ( 
                                    UserId ,
                                    SessionId
                            ) VALUES  (
                                    @userid ,
                                    @sessionid)";

            $query_params = array( 
                ':userid' => $row['UserId'], 
                ':sessionid' => $sessiontoken 
            );    

            try 
            { 
                // Execute the query to insert a new user session or update
                // an existing one
                $stmt = $db->prepare($query); 
                $result = $stmt->execute($query_params); 
            } 
            catch(PDOException $ex) 
            { 
                // Note: On a production website, you should not output $ex->getMessage(). 
                // It may provide an attacker with helpful information about your code.  
                // die("Failed to run query: " . $ex->getMessage()); 
                die("Failed to run query: " . $ex->getMessage()); 
            } 

            // Redirect the user to the private members-only page. 
            // This will need to be changed once we have the QUEST logic flow sorted out
            // to be the landing quest page.
            header("Location: private.php"); 
            die("Redirecting to: private.php"); 
        } 
        else 
        { 
            // Tell the user they failed 
            print("Login Failed."); 

            // Show them their username again so all they have to do is enter a new 
            // password.  The use of htmlentities prevents XSS attacks.  You should 
            // always use htmlentities on user submitted values before displaying them 
            // to any users (including the user that submitted them).  For more information: 
            // http://en.wikipedia.org/wiki/XSS_attack 
            $submitted_username = htmlentities($_POST['username'], ENT_QUOTES, 'UTF-8'); 
        } 
    }

?> 
<h1>Login</h1> 
<form action="login.php" method="post"> 
    Username:<br /> 
    <input type="text" name="username" value="<?php echo $submitted_username; ?>" /> 
    <br /><br /> 
    Password:<br /> 
    <input type="password" name="password" value="" /> 
    <br /><br /> 
    <input type="submit" value="Login" /> 
</form> 
<a href="register.php">Register</a>

そして、セッションを取得した後、この領域で何か単純な問題が発生していると思われますが、何が原因なのかわかりません:

// This statement checks if data was available when retreiving user information
// using our session token.
if($row)
{
4

1 に答える 1

1

これは IIS の既知の問題です (Azure は IIS を実行していると思いますか?)

参照: http://support.microsoft.com/kb/q176113

CGI アプリケーションが "302 Object Moved" 応答と Location ヘッダーを含む Set-Cookie ヘッダーを送信すると、Internet Information Server (IIS) は Cookie ヘッダーを無視します。

この動作は、「サーバー ディレクティブではないヘッダーはクライアントに直接送信されます。現在、この仕様では 3 つのサーバー ディレクティブが定義されています...」と述べている CGI 仕様に違反しています。

リンクされたページに回避策があり、このプロジェクトに少し関係しているようです。ごめん。私はマイクロソフト製品を実際に使用した経験がないため、別のスタックを試すことをお勧めします。

于 2013-09-25T23:24:59.313 に答える