Предотвращение кражи файлов cookie при входе в систему на панели разработчика браузера

#php #authentication #cookies #session-cookies

#php #аутентификация #файлы cookie #сессия-файлы cookie

Вопрос:

Я внедряю систему входа на свой веб-сайт и обнаружил, что если я изменю идентификатор сеанса на панели разработчика в своем браузере (нажмите F12> Приложение> Файлы cookie> Мой сайт), я могу фактически войти в другую учетную запись, это возможно только в том случае, если я знаю идентификатор сеанса изкто-то другой, но есть ли какой-либо способ избежать этого или это нормально, и безопасность идентификатора сеанса должна быть сосредоточена в базе данных и на компьютере пользователя?

Извините, если это что-то базовое, я все еще учусь использовать сеансы и файлы cookie.

это мой сценарий сеанса:

 <?php

class _account {

    private $id;
    private $username;
    private $authenticated;
    private $updateTime;

    public function __construct(){
        $this->id = NULL;
        $this->username = NULL;
        $this->authenticated = FALSE;
        $this->updateTime = NULL;
    }
    
    public function __destruct(){
        
    }

    public function login(string $username, string $password): bool {
        global $conn;
        $conn->link = $conn->connect();

        if(!empty($username) amp;amp; !empty($password)){
            if($stmt = $conn->link->prepare("SELECT id, password FROM users WHERE username = ?")){
                $stmt->bind_param('s', $username);
                try{
                    $stmt->execute();
                    $stmt->store_result();
                }
                catch(Exception $e){
                    throw new Exception('Erro ao conectar com a base de dados: '. $e);
                }
                if($stmt->num_rows > 0){
                    $stmt->bind_result($db_account_id, $db_account_password);
                    $stmt->fetch();

                    if(password_verify($password, $db_account_password)){
                        session_regenerate_id();

                        $_SESSION['loggedin'] = TRUE;
                        $_SESSION['id'] = $db_account_id;
                        $_SESSION['username'] = $username;
                        if(!isset($_SESSION['updateTime'])) $_SESSION['updateTime'] = strtotime('NOW');

                        $this->id = $db_account_id;
                        $this->username = $username;
                        $this->authenticated = TRUE;
                        $this->updateTime = $_SESSION['updateTime'];

                        if(!$this->isActive()){
                            $_SESSION['exceptional_error'] = ERROR_LOGIN_DENIED;
                            $this->logout();
                        }

                        //Verify if the current password's hash needs to be updated to newest algorithm
                        if(password_needs_rehash($db_account_password, $password)){
                            if($stmt = $conn->link->prepare("UPDATE users SET password = ? WHERE id = ?")){
                                $stmt->bind_param('si', $new_hash, $refer_id);

                                $new_hash = password_hash($password, PASSWORD_DEFAULT);
                                $refer_id = $db_account_id;
                                $stmt->execute();
                                echo '<div class="box-msg sucess" style="top:100%;">Hash updated to a newly version!</div>';
                            }
                        }

                        /* Register the current Sessions on the database */
                        $this->registerLoginSession();

                        return TRUE;
                    } else{
                        $stmt->close();
                        $conn->disconnect($conn->link);
                        throw new Exception(ERROR_LOGIN_PASSWORD);
                    }
                } else{
                    $stmt->close();
                    $conn->disconnect($conn->link);
                    throw new Exception(ERROR_LOGIN_USERNAME);
                }
            }
        } else {
            $stmt->close();
            $conn->disconnect($conn->link);
            throw new Exception(ERROR_LOGIN_BLANK);
        }
    }

    private function registerLoginSession(){
        global $conn;
        global $browser;
        $conn->link = $conn->connect();

        if(session_status() == PHP_SESSION_ACTIVE){
            if($stmt = $conn->link->prepare("REPLACE INTO users_sessions (session_id, user_id, login_time, user_agent, user_OS) VALUES (?, ?, NOW(), ?, ?)")){
                $stmt->bind_param('siss', $session, $userid, $user_agent, $user_OS);
                $session = session_id();
                $userid = $this->id;
                $user_agent = $_SERVER['HTTP_USER_AGENT'];
                $user_OS = $browser->getPlatform() .' '. $browser->getPlatformVersion(true);

                /*
                $browser->setUserAgent($user_agent);

                echo $browser->getName();
                echo $browser->getVersion();
                echo $browser->getPlatform();
                echo $browser->getPlatformVersion(true);
                */

                try{
                    $stmt->execute();
                }
                catch(Exception $e){
                    throw new Exception('Erro ao conectar com a base de dados: '. $e);
                }
                $stmt->close();
                $conn->disconnect($conn->link);
                return TRUE;
            }
        }
    }

    public function regenerateSession($userid): bool{
        global $conn;
        $conn->link = $conn->connect();

        if($stmt = $conn->link->prepare("UPDATE users_sessions SET users_sessions.session_id = ? WHERE users_sessions.session_id = ? AND users_sessions.user_id = ?")){
            $stmt->bind_param('ssi', $newSession, $actualSession, $userid);
            $actualSession = session_id();
            session_regenerate_id();
            $newSession = session_id();

            try{
                $stmt->execute();
            }
            catch(Exception $e){
                throw new Exception('Erro ao conectar com a base de dados: '. $e);
            }
            $stmt->close();
            $conn->disconnect($conn->link);
            return TRUE;
        }
        $stmt->close();
        $conn->disconnect($conn->link);
        return FALSE;
    }

    public function sessionLogin(): bool{
        global $conn;
        $conn->link = $conn->connect();

        if(session_status() == PHP_SESSION_ACTIVE){
            if($stmt = $conn->link->prepare("SELECT * FROM users_sessions, users WHERE (users_sessions.session_id = ?) AND (users_sessions.login_time >= (NOW() - INTERVAL 7 DAY)) AND (users_sessions.user_id = users.id) AND (users.active = 1)")){
                $stmt->bind_param('s', $session);
                $session = session_id();

                try{
                    $stmt->execute();
                    //$result = $stmt->get_result();
                    $result = $this->get_result($stmt);
                    //$data = $result->fetch_all(MYSQLI_ASSOC);
                    $row = array_shift($result);
                }
                catch(Exception $e){
                    throw new Exception('Erro ao conectar com a base de dados: '. $e);
                }
                if($stmt->num_rows > 0){

                    $this->id = $row['id'];
                    $this->username = $row['username'];
                    $this->authenticated = TRUE;
                    $this->updateTime = $_SESSION['updateTime'];

                    $differenceBetweenTimes = (strtotime('NOW') - $this->updateTime);
                    $minutesToUpdate = $differenceBetweenTimes / 60;

                    if($minutesToUpdate > 30){
                        //Atualiza o id da sessão a cada X minutos
                        if(!$this->regenerateSession($this->id)){
                            $this->logout();
                        }
                        $_SESSION['updateTime'] = strtotime('NOW');
                    }                   
                    return TRUE;
                } else if($this->getFileName() == 'cpainel.php'){
                    //Não redireciona, o usuário já está na página inicial
                } else{
                    $this->logout();
                }
            }
            $this->logout();
        }
        $stmt->close();
        $conn->disconnect($conn->link);
        return FALSE;
    }

    public function isAuthenticated(): bool {
        return $this->authenticated;
    }
}

?>
 

Комментарии:

1. Если вы знаете чей-то идентификатор сеанса, вы можете выдавать себя за него, это просто факт. Вот почему идентификаторы сеанса представляют собой длинные случайные строки, в идеале передаваемые по протоколу SSL.

2. Некоторые места также привязывают сеанс пользователя к дополнительной информации, такой как агент пользователя и / или IP. Это не гарантирует безопасность, но усложняет процесс олицетворения. Некоторые системы также предложат пользователю «обновить» свою безопасность, если они предварительно аутентифицированы, если запрос более (потенциально) опасный и / или чувствительный.