1

重要

以下の回答のアドバイスに従った後、クライアントは問題なくログインできましたが、保護されたページを実際にナビゲートしようとはしませんでした。後でログインしようとすると、「ログインしてください」というエラーが表示され、以前のようにログインに戻りました。多くの頭を悩ませた後、信じられないほど単純なことが頭に浮かびました。クライアントはhttp://www.example.com/adminでサイトにアクセスしており、ログインスクリプトのすべてがhttp://example.comにリダイレクトされていたため、セッションは探していた Cookie が別のドメインに設定されていました。これは、彼が最初にログインする際に問題が発生し、その後は問題が発生しなかった理由も説明しています。スクリプトにより、www.

簡単な修正は、.htaccess ファイルを作成して www を削除することでした。問題は解決しました。もちろん、これはログイン スクリプト内で処理することもできます。これは、将来の使用のために改善する予定です。

元の投稿

自作の CMS とログイン システムを使用して、PHP と MySQL ベースのサイトを開発しています。私の CMS はすべてのクライアントに固有のものであり、多くの人を喜ばせてきました。残念ながら、私のログイン システムには同じことが当てはまりません。以下は長い投稿ですが、解決策を見つけるために詳細をカバーする必要があります. 我慢して..

システムは、少し重くはないにしても、かなり簡単です。各ユーザーは、SALT と一緒に MySQL テーブルに格納されたソルト ハッシュを持っています。ユーザーがログインすると、SALT が取得され、送信されたパスワードがソルト付きハッシュになります。

送信されたソルト付きハッシュがテーブルに格納されているものと一致する場合、ユーザーは認証されます。名前、最後の IP アドレス、アカウント レベル (ほとんどのサイトで 3 レベル) などの詳細は、セッション変数に割り当てられた配列に格納されます。次に、ログインした制限付きサイト (メンバーのみまたは管理者/CMS) のランディング ページにリダイレクトされます。

セキュリティで保護されたページには、詳細を含むセッション変数が存在するかどうかを確認する小さな auth.php ファイルが含まれています。そうでない場合は、そのサイトのログイン フォームにリダイレクトされ、「ログインしてください」というエラー メッセージが表示されます。存在する場合は続行が許可され、配列に格納されている詳細が変数に割り当てられます。

多くのユーザーから報告されている問題は、「ログインしてください」というエラー メッセージが表示されてログイン フォームに戻されないようにするために、何度もログインする必要があることです。サイトにアクセスして、同じエラーでランダムにログインに戻されます。したがって、セッション変数は、サイトの通常の使用中に何らかの理由で設定されていないか、クリアされているようです。

最初の問題は、多数のデバイスとネットワークで発生したことがなく、クライアントのオフィスでラップトップを使用して目撃したことがあります。モバイルホットスポットに接続してもらいましたが、変化はありませんでした。しかし、彼らは私のラップトップとホットスポット接続を使用して問題なくログインできました. 残念ながら、ラップトップを使用してネットワークに接続できなかったため、その変数を除外できませんでした.

*注意 - *問題のあるクライアントが正しい認証情報で 2 ~ 3 回ログインすると、システムは正常に動作するということを最初に言い忘れました。ブラウザを開いたままログインしようとすると、その後は問題なく実行される傾向があります。また、ログイン ページはセッションを破棄します。

ログイン スクリプトから始まる各ステージのコードを次に示します。

login.php

<?php
putenv("TZ=US/Eastern");

if (array_key_exists('site', $_POST)) {
    $authenticate = new loginUser($_POST['username'], $_POST['password'], $_POST['site'], $_SERVER['REMOTE_ADDR']);
}
//Authenticate and log-in
class loginUser {
    private $memDB, $username, $password, $site, $ip_address;

     //Clean input variables
    private function clean($str) {
        $str = @trim($str);
        if(get_magic_quotes_gpc()) {
            $str = stripslashes($str);
        }
        return $str;
    }
    //Construct variables
    function __construct($username, $password, $site, $ip_address) {
    session_start();
        $this->memDB = new PDO('mysql:host=localhost;dbname=exampleDB', 'exampleUser', 'examplePassword');
        $this->username = $this->clean($username);
        $this->password = $this->clean($password);
        $this->site = $site;
        $this->ip_address = $ip_address;
    $this->authUser();
    }
    //Validate username
    private function validateUsername($username) {

        $checkUsername = $this->memDB->prepare("SELECT COUNT(*) FROM accounts WHERE username = ?");
        $checkUsername->execute(array($username));
        return $checkUsername->fetchColumn();
    }
    //Obtain and set account details
    private function accountDetails() {

        $fetchAccountDetails = $this->memDB->prepare("SELECT id, name_f, name_l, ipAddr, lastLogin, accountLevel, isActive 
        FROM accounts WHERE username = ?");
        $fetchAccountDetails->execute(array($this->username));
        $accountDetails = $fetchAccountDetails->fetch();
        $this->updateLogin();
        return $accountDetails;
    }
    //Update last login details
    private function updateLogin() {

        $updateLogin = $this->memDB->prepare("UPDATE accounts SET ipAddr = ?, lastLogin = DATE_ADD(NOW(), INTERVAL 1 HOUR) WHERE username = ?");
        $updateLogin->execute(array($this->ip_address, $this->username));
    }
    public function authUser() {

        $loginErr = array(); //Array for holding login error message
        $loginErrFlag = false; //Boolean for error
        //Validate submitted $_POST elements
        if (!$this->username) {
            $loginErr[] = "Username missing";
            $loginErrFlag = true;
        }
        if (!$this->password) {
            $loginErr[] = "Password missing";
            $loginErrFlag = true;
        }
        if ($this->username && $this->validateUsername($this->username) == 0) {
            $loginErr[] = "Username invalid";
            $loginErrFlag = true;
        }
        if (!$loginErrFlag) {
            //Fetch the password and SALT to compare to entered password
            $validatePW = $this->memDB->prepare("SELECT password, salt FROM accounts WHERE username = ? LIMIT 1");
            $validatePW->execute(array($this->username));
            $passwordResult = $validatePW->fetch();
            $dbPW = $passwordResult['password'];
            $dbSalt = $passwordResult['salt'];
            //Compare entered password to SALT + hash
            $hashPW = hash('sha512', $dbSalt . $this->password);
            if ($hashPW === $dbPW) {
                //Logged in
                $_SESSION['CVFD-USER-DETAILS'] = $this->accountDetails();
                //Redirect to secure landing page for log-in origin (Members or Admin)
                //Adding SID is a recent attempt to handle log-in problems
                header("Location: http://example.com/$this->site/$this->site-main.php?" . SID);
                //session_write_close() was here but was removed
                exit();
            } else {
                //Password invalid
                $loginErr[] = "Please check your password and try again";
                $_SESSION['CVFD_LOGIN_ERR'] = $loginErr;
                //Redirect to the log-in for the origin
                header("Location: http://example.com/$this->site");
        session_write_close();
                exit();
            }
        } else {
            $_SESSION['CVFD_LOGIN_ERR'] = $loginErr;
            header("Location: http://example.com/$this->site");
            session_write_close();
            exit();
        }

    }
}
?>

auth.php

<?php
session_start();
if (!isset($_SESSION['CVFD-USER-DETAILS']) || $_SESSION['CVFD-USER-DETAILS'] == '') {
    //Not logged in
    $_SESSION['CVFD_LOGIN_ERR'] = array('Please login');
    header('Location: http://example.com/members');
    session_write_close();
    exit();
} else {
    $userDetails = $_SESSION['CVFD-USER-DETAILS']; //Assign user details array to variable
    //Check to see if account is active
    $accountStatus = $userDetails['isActive'];
    $accountLevel = $userDetails['accountLevel'];
    if ($accountStatus == 0) {
        //Account is not yet active (pending Admin activation)
        $_SESSION['CVFD_LOGIN_ERR'] = array('Your account is suspended or pending activation');
        header('Location: http://example.com/members');
        session_write_close();
        exit();
    } else {
        $CVFDFirstName = $userDetails['name_f'];
        $CVFDLastName = $userDetails['name_l'];
        $CVFDLastLogin = date("m/d/Y H:i:s", strtotime($userDetails['lastLogin']));
        $CVFDAccountLevel = $userDetails['accountLevel'];
        $CVFDIPAddr = $userDetails['ipAddr'];
    }
}
?>

安全なファイルに auth.php を含める方法は次のとおりです。

<?php
if (substr_count($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip')) ob_start("ob_gzhandler"); else ob_start();
require($_SERVER['DOCUMENT_ROOT'] . '/members/includes/handlers/handler.auth.php');

どんな助けでも大歓迎です。なかなかの謎..

ありがとう!

4

3 に答える 3

1

私がログインシステムを行う方法は、セッション自体に何かを保存するのではなく、セッションIDを使用することです。ユーザーがハッシュされたユーザーエージェントデータ、セッションID、ユーザーID(usersテーブルに対応)にログインし、有効期限が「active_users」と呼ばれるテーブルに入れられると、ログインしたヘッドファイルが含まれます。セッションを開始し、ユーザーセッションIDを取得し、そのセッションIDがアクティブユーザーテーブルにあるかどうか、およびチェック対象のユーザーが同じユーザーエージェントデータを持っているかどうかを確認するすべての管理者制限ページで、有効期限を超えません。そのクエリから何も返されない場合、それらはログインせず、バウンスされます。

それが私が作るほとんどのログインシステムのやり方であり、私は何の問題もありませんでした。

于 2012-10-05T16:00:46.613 に答える
0

成功!どの変更が問題の解消につながったのかを正確に絞り込む必要がありますが、クライアントはログインの問題がなくなったと報告しています。

すぐに頭に浮かぶ最大の変更は、session_write_close()ほぼすべての場所を削除することでした。コードの一部でヘッダーリダイレクトの後に配置されているか、単に存在していることが原因である可能性があります。リダイレクトの前に配置してみます。

ご提案いただきありがとうございます

于 2012-10-05T17:44:17.660 に答える
0

私に飛び出す1つのことは次のとおりです。

header('Location: http://example.com/members');
session_write_close();
exit();

私はそのsession_write_close()前に電話をかけますheader('location ...')

ログに「headers already sent」エラーが表示されていますか?

他に思いつくのは、AJAX 競合状態です。ログインページで非同期呼び出しが行われていますか?

于 2012-10-05T15:53:16.513 に答える