rchivo con clase para la gestión de las sesiones */ /** * Clase para la gestión de la sesión del usuario * @category core * @package base * @subpackage seguridad * @version 5.2.1 */ class sxSession{ /** * @var int Tiempo en minutos que dura activa una session */ var $gc_maxlifetime=50; /** * constructor para inicializar la configuración del sistema para la administración de sesiones */ function __construct(){ static $controlSession=false; if(!$controlSession){ $controlSession=true; // No permite adicionar el SID a las URLs del sitio ini_set('session.use_trans_sid', 0); // Define que se va a gestionar de otra forma la informacion de la session ini_set('session.save_handler', 'files'); // Define el formato para almacenar los datos ini_set('session.serialize_handler', 'php'); // Establece que se utilizara una cookie para almacenar el id de session ini_set('session.use_cookies', 1); // Nombre de la cookie para el id de session ini_set('session.name', 'nexuraSID'); ini_set('url_rewriter.tags',''); ini_set('session.use_trans_sid', false); // Asegura que la session dura mientras este activo el navegador ini_set('session.cookie_lifetime', 0); // Ruta de la cookie, se debe colocar el / al final para evitar problemas de sesion en ie $path=getBaseUri(); // Dominio de la cookie $domain=false; if(strpos($_SERVER['SERVER_NAME'],'.')===false ){ //$domain=getBaseUri();// Megatron } elseif(strpos($_SERVER['SERVER_NAME'],'www.')===false){ $domain='.'.$_SERVER['SERVER_NAME'];// Subdominios sin www } else{ $domain=str_replace("www.","",'.'.$_SERVER['SERVER_NAME']);// Dominio www y subdominios } //if($domain) ini_set('session.cookie_domain', $domain); ini_set('session.use_only_cookies',1); ini_set('session.cookie_httponly',1); /* * Se verifica si el sitio es seguro y se coloca atributo SameSite en None, * de igual forma se habilita atributo Secure * Si el sitio no es seguro se coloca atributo SameSite en Lax y no se habilita * el atributo Secure * Se realiza este validación dado que en Google Chrome no permite crear la cookie * nexuraSID con el atributo SameSite en None si el sitio no es seguro */ if(isset($_SERVER['HTTPS']) && $_SERVER['HTTPS']=='on') { // Se verifica versión de php para agregar atributo samesite a cookie if (PHP_VERSION_ID < 70300) { ini_set('session.cookie_path', (empty($path)?'/; SameSite=None':"$path/; SameSite=None")); } else { ini_set('session.cookie_path', (empty($path)?'/':"$path/")); ini_set('session.cookie_samesite', 'None'); } ini_set('session.cookie_secure', 1); } else { // Se verifica versión de php para agregar atributo samesite a cookie if (PHP_VERSION_ID < 70300) { ini_set('session.cookie_path', (empty($path)?'/; SameSite=Lax':"$path/; SameSite=Lax")); } else { ini_set('session.cookie_path', (empty($path)?'/':"$path/")); ini_set('session.cookie_samesite', 'Lax'); } } // Porcentaje de probabilidad que se ejecute el gc ini_set('session.gc_probability', 1); // Porcentaje de probabilidad que se ejecute el gc ini_set('session.gc_maxlifetime', $this->gc_maxlifetime*60); // Inicio de session automatico ini_set('session.auto_start', 1); }// if } // sxSession /** * Permite iniciar la sesión, y controlas la inactividad del usuario en el sistema * @return boolean */ function init(){ // Redefine las funciones para el manejo de session por la DB /*if(!session_set_save_handler( array(&$this, 'open'), array(&$this, 'close'), array(&$this, 'read'), array(&$this, 'write'), array(&$this, 'destroy'), array(&$this, 'gc') )) return false;*/ // Inicia la session session_start(); // configuracion para cerrar sesion en caso de inactividad del usuario 20140219 if($_SESSION['uid']) { $datosCliente=configGeneral::getComunidadActual(); $tiempoSesion=$datosCliente->tiempoSesion; if($tiempoSesion){ $tiempo = $tiempoSesion; if(isset($_SESSION['tiempo']) ) { $vida_session = time() - $_SESSION['tiempo']; if($vida_session > ($tiempo*60)) { unset($_SESSION['tiempo']); unset($_SESSION['uid']); $_SESSION['over']=$tiempo; header("Location: user.php"); } // if }// if $_SESSION['tiempo'] = time(); } // if // Almacena la sesión en la base de datos if (!self::write(session_id())) { error_log('No fue posible almacenar la información de la sesión en la base de datos'); return false; } } // if return true; } // init /** * Define en true el inicio de sesión * @param string $path Ruta de almacenamiento de la sesión * @param string $name Nombre de la sesión * @return boolean */ function open($path, $name){ return true; } // open /** * Realiza le cierre de la sessión * @return boolean */ function close(){ return true; } // close /** * Extrae las de la sesión cuando se administra por la DB * @param string $id Identificador de la sesión * @return array */ public static function read($id){ $cx=&bd::getCx(); $tablas=&bd::getTablas(); $tabla=&$tablas['sx_session']; $columnas=&$tablas['sx_session_column']; $query=" SELECT $columnas[id], $columnas[end], $columnas[uid], $columnas[vars], $columnas[log] FROM $tabla WHERE $columnas[id]='$id' "; $resultSet=$cx->execute($query); $data = []; if (!$resultSet->EOF) { list($id, $end, $uid, $vars, $log) = $resultSet->fields; $data['id'] = $id; $data['end'] = (int)$end; $data['uid'] = (int)$uid; $data['vars'] = $vars; $data['log'] = $log; } // if return $data; } // read /** * Permite realizar la escritura de la sesión cuando se administra por la DB * @param string $id Identificador de la sesión * @param string $vars Valor serializado de las variables a almacenar * @return boolean */ public static function write($id, $vars, $log = ''){ $cx=&bd::getCx(); $tablas=&bd::getTablas(); $tabla=&$tablas['sx_session']; $columnas=&$tablas['sx_session_column']; // Session activa y variables if(self::count(session_id()) && $vars){ $query=" UPDATE $tabla SET $columnas[end]=".time().", $columnas[vars]='".($vars)."', $columnas[uid] = " . ($_SESSION['uid'] ?: 0) . " WHERE $columnas[id]='$id' "; } // if // Session activa y sin variables else if(self::count(session_id()) && !$vars){ $query=" UPDATE $tabla SET $columnas[end]=".time().", $columnas[vars]=NULL, $columnas[uid] = " . ($_SESSION['uid'] ?: 0) . " WHERE $columnas[id]='$id' "; } // if // Sin session activa y variables, tiene en cuenta si ha iniciado session el usuario else if($vars){ $query=" INSERT INTO $tabla ( $columnas[id], $columnas[end], $columnas[uid], $columnas[vars], $columnas[log] ) VALUES ( '$id', ".time().", ".($_SESSION['uid'] ?: 0).", '".($vars)."', '$log' ) "; } // else if // Sin session activa y sin variables else{ $query=" INSERT INTO $tabla ( $columnas[id], $columnas[end], $columnas[uid], $columnas[log] ) VALUES ( '$id', ".time().", 0, '$log' ) "; } // else // Ejecuta la consulta y devuelve el resultado if ($cx->Execute($query)) { return true; } return false; } // write /** * Elimina la sesión cuando se administra por la DB * @param string $id Identificador de la sesión * @return boolean */ public static function destroy($id){ $cx=&bd::getCx(); $tablas=&bd::getTablas(); $tabla=&$tablas['sx_session']; $columnas=&$tablas['sx_session_column']; $query=" DELETE FROM $tabla WHERE $columnas[id]='$id' "; if(getClienteId()!=1){ if($cx->Execute($query)) return true; else return false; } else return false; } // destroy /** * Elimina las sesiones que han estado inactivas por más de $maxlifetime * @param int $maxlifetime * @return boolean */ function gc($maxlifetime){ // Primero intenta eliminar los intentos fallidos de inicio de session sxGstUsuarios::delSessionCheck(); $cx=&bd::getCx(); $tablas=&bd::getTablas(); $tabla=&$tablas['sx_session']; $columnas=&$tablas['sx_session_column']; $query=" DELETE FROM $tabla WHERE $columnas[end]<".(time()-$maxlifetime)." "; if(getClienteId()!=1){ if($cx->Execute($query)) return true; else return false; } else return false; } // gc /** * Extrae el número de sesiones que están registradas para un usuario * @param int $id Identificador del usuario * @return int */ public static function count($id){ $cx=&bd::getCx(); $tablas=&bd::getTablas(); $tabla=&$tablas['sx_session']; $columnas=&$tablas['sx_session_column']; $query=" SELECT COUNT($columnas[id]) FROM $tabla WHERE $columnas[id]='$id' "; $resultSet=$cx->execute($query); if(!$resultSet->EOF){ list( $count )=$resultSet->fields; return $count; } // if else return 0; } // count /** * generación de token de validación de peticiones * @param String $modulo * @param String $funcion * @param String $tipo * @param Boolean $unique formulario unico * @param String $type (post, get, string) * @return String */ public static function generateToken($modulo, $tipo='user', $funcion='main', $unique=true, $type='post') { $token = md5(uniqid(mt_rand(), true)); $return = ''; if(strtolower($type) == 'string'){ $return = $token; } if(strtolower($type) == 'get'){ $return = '&sxToken='.hash('adler32',$token); $token = hash('adler32',$token); } if(strtolower($type) == 'post'){ $return = ""; } if($unique){ $_SESSION['token'][$token]=array('servicio'=> $modulo,'tipo'=>$tipo, 'funcion' => $funcion, 'multiple'=> FALSE); }else{ $_SESSION['token'][$token]=array('servicio'=> $modulo,'tipo'=>$tipo, 'funcion' => $funcion, 'multiple'=>true,'hash' =>NULL); } return $return; }//generateToken public static function validateToken($campo = 'sxToken') { if (!isset($_REQUEST[$campo])) { // error_log("Token no encontrado en la solicitud: " . $campo); return false; // El token no está presente en la solicitud } $token = $_REQUEST[$campo]; if (!isset($_SESSION['token'][$token])) { // error_log("Token '$token' no existe en la sesión o ha expirado."); return false; } $sessionTokenData = $_SESSION['token'][$token]; $funcion = (!isset($_REQUEST['lFuncion']) || $_REQUEST['lFuncion'] == '') ? 'main' : $_REQUEST['lFuncion']; $tipo = (!isset($_REQUEST['lTipo']) || $_REQUEST['lTipo'] == '') ? 'user' : $_REQUEST['lTipo']; if (($sessionTokenData['servicio'] != $_REQUEST['lServicio']) || ($sessionTokenData['funcion'] != $funcion) || ($sessionTokenData['tipo'] != $tipo)) { // error_log("Fallo de validación de servicio/función/tipo para el token '$token'."); // Opcionalmente, puedes destruir el token aquí si hay una inconsistencia por seguridad unset($_SESSION['token'][$token]); return false; } if ($sessionTokenData['multiple'] === true) { // Previene ataques de repetición (replay attacks) o dobles envíos. $incoming_request_hash = hash('adler32', json_encode($_REQUEST)); if (isset($_SESSION['infoUsuario']['id'], $_SESSION['infoUsuario']['tipo']) && (int)$_SESSION['infoUsuario']['tipo'] !== 12) { if (isset($sessionTokenData['hash']) && $sessionTokenData['hash'] === $incoming_request_hash) { error_log("Intento de reenvío detectado para el token múltiple '$token'."); return false; // El mismo request exacto ya fue procesado. } } // Es una nueva petición válida para este token. Se actualiza el hash y se permite. $_SESSION['token'][$token]['hash'] = $incoming_request_hash; return true; } else { unset($_SESSION['token'][$token]); return true; } }//validateToken } // class ?>