#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. Это не гарантирует безопасность, но усложняет процесс олицетворения. Некоторые системы также предложат пользователю «обновить» свою безопасность, если они предварительно аутентифицированы, если запрос более (потенциально) опасный и / или чувствительный.