entre Desarrolladores

Recibe ayuda de expertos

Registrate y pregunta

Es gratis y fácil

Recibe respuestas

Respuestas, votos y comentarios

Vota y selecciona respuestas

Recibe puntos, vota y da la solución

Pregunta

3votos

Nivel de acceso usuario - PHP

Hola , bueno nuevamente me veo en la necesidad de solicitar ayuda no logro ubicar mi error, podrian ser solo comas, corchetes o punto y coma pero no logro verlo.

lo que necesito es darle el nivel de acceso para los cuales en la columna de la DB tengo la seccion "niveles" la cual 0 es para usuario normal y 1 es para usuario administrador.

debo indicar que los administradores ingresan perfectamente a su seccion, pero los usuarios normales al ingresar los datos no ingresan simplemente se borran los datos de el login sin indicar nada . dejo mi codigo de mi validador de usuarios.

//Valido si el nombre del administrador existe en la base de datos o es correcto
if($row = mysql_fetch_array($result))
{     
//Si el usuario es correcto ahora valido su contraseña
 if($row["password"] == $password)
 {
// aca valido que si es nivel 1 es administrador lo envie a su zona
 if($row["nivel"] == 1)
  //Creo la sesión
  session_start();  
  //Almaceno el nombre de usuario en una variable de sesión usuario
  $_SESSION['usuario'] = $usuario;  
  //y Redirecciono a la pagina del admin , hasta aca todo bien
  header("Location: admin.php");  
 }
// aca le indico que si es nivel 0 lo mande a su zona , pero no me responde
 else { 
if($row["nivel"] == 0)
 session_start();
 $_SESSION['usuario'] = $usuario;
header("location:index.php"); 

2 Respuestas

5votos

Leonardo-Tadei Puntos227320

Hola @indiglosv,

me alegra que lo hayas resuelto! Te escribo para sugerirte que te pases lo antes posible a PDO o al menos a mysqli* para acceder a la DB, ya que las mysql* están por desaparecer.

Por otra parte, tu validación de usuario solo está redirigiendo según el nivel a admin.php o a index.php, pero si en ambos archivos no estás validando el nivel de acceso no tenés ninguna seguridad, ya que si accedo con nivel 0 y luego cambio el URL del navegador a admin.php podría seguir logeado.

Tené siempre en cuenta estas cosas cuando getiones usuarios.

PD: y chequeá que luego del logout, apretar "atrás" en el navegador no te deje nuevamente dentro del sistema... es un fallo de seguridad típico.

2votos

indiglosv comentado

Hola @Leonardo-Tadei

Gracias por tu recomendación y en efecto sucede lo que me indicas si ingreso como usuario y luego cambio el URL a admin.php sigue logado en la sección de administrador, eso quiere decir que como tu dices debo también protegerlo en todas las páginas, por lo cual en la sección de administrador lo tengo de la siguiente manera:

 if($row["nivel"] == 1)
session_start();
if(!isset($_SESSION['usuario'])) 
{
  header('Location: login.php'); 
  exit();
}

Luego de esto tengo toda la información de la web que quiero proteger, el problema es que ahora los administradores no logran ingresar únicamente los usuarios.

2votos

Leonardo-Tadei comentado

Que bueno que no funciona, porque no es esa la forma correcta de validar que un usuario esté logueado.

Estás confundiendo los datos en la sesión (que dependen de una cookie y por tanto son falseables) con los datos de un usuario válido.

Lo correcto es guardar en la sesión el nombre de usuario y la contraseña, y en cada script, verificar contra la DB si ese usuario y contraseña es válido y si el nivel es el que corresponde al script que estás entrando.

De esta forma incluso si deshabilitás un usuario logueado, al próximo click quedará fuera del sitio, ya que las cosas no dependen de la sesión.

Por último, en caso de detectar que el usuario es inválido o que la sección no es la debida, además de redirigir al usuario tenés que blanquear los datos en la sesión.

Te pongo un ejemplo de código que no maneja diferentes niveles, pero que es simple de adaptar:

login.php

<?php
/*
* @Prometeus Technology, a subsidiary of Pegasus Tech Supply
* @copyright Copyright (C) 2006-2015 Leonardo Tadei. All rights reserved.
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL, see gpl-3.0.txt
* CRUD is free software. This version may have been modified pursuant
* to the GNU General Public License, and as distributed it includes or
* is derivative of works licensed under the GNU General Public License or
* other free or open source software licenses.
*
* Login y manejo de sesiones
*/
include_once('Config.php');
// Inicializa la sesión
session_start();

// Si hay datos para un login, lo hace
if( isset($_POST['Blogin']) ) {
    $sql = "SELECT * FROM Usuarios
                WHERE usr='{$_POST['usr']}'
                AND pas='{$_POST['pas']}'";
    $qry = $dbh->prepare($sql);
    $qry->execute();

    $total = $qry->rowCount();

    if($total === 1) {
        $_SESSION['usr'] = $_POST['usr'];
        $_SESSION['pas'] = $_POST['pas'];
        header('Location: index.php');
    } else {
        $_SESSION['usr'] = '';
        $_SESSION['pas'] = '';  
        header('Location: index.html');     
    }
}

function checkLogin($dbh) {
    // chequea que el usuario esté logeado
    $sql = "SELECT * FROM Usuarios
                WHERE usr='{$_SESSION['usr']}'
                AND pas='{$_SESSION['pas']}'";
    $qry = $dbh->prepare($sql);
    $qry->execute();

    $total = $qry->rowCount();

    if($total === 1) {
        return true;
    } else {
        header('Location: index.html');     
        return false;
    }
}
?>

Hay un HTML llamado index.html que tiene campos usr, pas y un botón Blogin y luego dentro de cada script, se llama a la función:

<?php
include_once('login.php');
checkLogin($dbh);

include('top.php');
?>

Bienvenido ;-)

<?php
include('bottom.php');
?>

es decir, toda llamada empieza verificando el login contra la DB.

El archivo config.php tiene los datos de acceso a la DB y hace la conexión:

<?php
define('SERVER',    'localhost');
define('DB',        'la_deb');
define('USR',       'el_usr');
define('PAS',       'la_clave');

function Conectar() {
    try {
        $dbh = new PDO('mysql:host='.SERVER.';dbname='.DB, USR, PAS);
        return $dbh;
    } catch (PDOException $e) {
        die("Error!: " . $e->getMessage());
    }   
}

// Llama a la función, ergo, siempre está conectado
$dbh = Conectar();
?>

Con esta estrategia basta con hacer el include del login en cada archivo, y luego escribir el código sin pensar mucho más en ello. Si tenés que mostrar más datos del usaurio en la pantalla, los cargás a las variables de sesión al loguearte y luego los usás de ahí.

Saludos cordiales!

1voto

indiglosv comentado

Gracias por la respuesta, por el trabajo no habia podido seguir la practica de php y viendo tu respuesta he entendido la parte sobre hacer un archivo y llamarlo en otro, para evitar estar escribiendo el código en todas las paginas en donde deba validar y verificar la sesión del usuario, pero no logro hacerlo de la manera que tu me lo indicas, termino con mas dudas :p

Este es mi validador de usuario:

<?php
mysql_connect('mysql.xxxxx.com','uxxxxxxxx_user','xxxxxxxx')or die ('Ha fallado la conexión: '.mysql_error());

mysql_select_db('u363250006_name')or die ('Error al seleccionar la Base de Datos: '.mysql_error());

$usuario = $_POST["admin"];   
$password = $_POST["password_usuario"];

$result = mysql_query("SELECT * FROM administradores WHERE nombre_administrador = '$usuario'");

if($row = mysql_fetch_array($result))
{     
 if($row["password"] == $password)
 {
 if($row["nivel"] == 1)
  session_start();  
  $_SESSION['usuario'] = $usuario;  
  header("Location: admin.php");  

 }
 elseif ($row["nivel"] == 0)
  { 
 session_start();
 $_SESSION['usuario'] = $usuario;
header("Location: index.php"); 

  ?>
   <script languaje="javascript">
    alert("Contraseña Incorrecta");
    location.href = "login.php";
   </script>
  <?php

 }
}
else
{
?>
 <script languaje="javascript">
  alert("El nombre de usuario es incorrecto!");
  location.href = "login.php";
 </script>
<?php  

}

mysql_free_result($result);

mysql_close();
?>

Este código es con lo único que validó la sesión del usuario en cada página

<?php
session_start();
if(!isset($_SESSION['usuario'])) 
{
  header('Location: login.php'); 
  exit();
}

 ?>

a el código anterior quiero agregarle las funciones para que valide si es nivel 0 lo envie para la sección de usuarios básicos, entonces si entiendo bien este archivo tendria que agregarlo con un include_once('validar_usuario.php'); para que me valide en la página que únicamente utilizó el código anterior, quedando así:

<?php
include_once('validar_usuario.php'); 
session_start();
if(!isset($_SESSION['usuario'])) 
{
  header('Location: login.php'); 
  exit();
}

 ?>

Y excelente, el usuario normal es dirigido a su página correcta, si modifico el URL y trato de ingresar a la sección de admin me salta el mensaje "Usuario incorrecto" me muestra por unos segundos la página de admin luego lo regresa al login de usuarios básicos, pero ahora el problema es a la hora que el admin ingresa a su área, salta el mismo mensaje "Usuario incorrecto" y no le permite ingresar lo envía nuevamente a su página de login.

1voto

Leonardo-Tadei comentado

Hola!

tal y como decís, la idea es tener un solo include al principio de cada script que se encargue de la validación.

Sin embargo, para hacer esto e hace falta ver un caso particular que es el momento del login. Si te fijás en el código que te pongo de ejemplo, el código discrimina el caso en que se estén ingresando los datos del formulario, con el caso general que es el usuario ya logueado y lo tenés que validar contra los datos de la sesión.

En tu caso, como los datos de usuario y contraseña siempre se cargan desde el fomulario:

$usuario = $_POST["admin"];   
$password = $_POST["password_usuario"];

nunca funcionará cuando el usuario logueado navegue por el sitio, porque nunca más esas variables $_POST tendrán valores.

Fijate en el código de ejemplo, que se entra a un IF si los datos vienen del formulario de login, pero para todo otro caso se llama a la función checkLogin($dbh) que busca los datos de la sesión.

Además la redirección con headr() debería ser solo en caso en que no sea un usuario válido, y en caso de ser válido debería seguir en contenido de la página a la que se está visitando.

Saludos!

1voto

indiglosv comentado

Hola ..

Bueno el caso está solventado, con tu ayuda pude eliminar los problemas de seguridad, pero no se que sucedio y ahora me genera el problema siguiente, no se si estara en la parte de código o será en la base de datos.

Resulta que el usuario admin con nivel 1 puede ingresar perfectamente a su cuenta con su usuario y contraseña, pero los usuarios con nivel 0 ingresan a su cuenta con su usuario y únicamente con la contraseña de otro usuario, con su propia contraseña no es posible entrar, elimine las tablas y las hice nuevamente y me salta el mismo error, solo tengo 2 usuarios el admin y un usuario nivel 0 que ingresan con sus datos sin problema, los demás pueden ingresar con la contraseña de cualquier otro usuario pero menos con la contraseña propia guardada.

estoy que me lleva la que no me trajo, creo que voy a empezar todo el código y aprovechare a cambiarme a mysqli* nuevamente porque ni yo lo entiendo ya jejejejejej

1voto

Leonardo-Tadei comentado

Esto te pasa porque tenés un problema en la lógica de los IF en la que usás los header() como saltos condicionales, pero además, partís de una query incorrecta para este uso.

Deberías ejecuentando algo como:

$result = mysql_query("SELECT * FROM administradores WHERE nombre_administrador = '$usuario' AND password = '$password' ");

entonces si la query devuelve un solo registro, el usuario es válido y según el nivel decidís que hacer, pero si devuelve una cantidad de registros distinta de 1, el usuario o contraseña son inválidos.

Esto simplificaría mucho el código... pero igual aprovechá a pasarlo a mysqli_* o a PDO.

Saludos!

1voto

doblea_pg comentado

Hola, Buenas tardes se que ya esto tiene mas de un año de antigüedad pero me encuentro con este inconveniente y no logro como adaptar tu código, ¿Sería una molestia si me ayudaras?, trato de gestionar 3 tipos de usuarios en mis sistema.

3votos

Leonardo-Tadei comentado

Hola @doblea_pg,

y cuál es tu duda? Qué es lo que no te funciona?

Lo mejor para que consigas una respuesta rápida es crear una nueva pregunta, indicando tu problema, el código que no te funciona y lo que quieres conseguir.

Saludos cordiales!

1voto

doblea_pg comentado

Gracias por tu pronta respuesta, creo que lo solucione de otra forma, Mi problema era que estaba trabajando con 3 tipos de usuarios y sesiones pero con un simple cambio de URL el usuario podia cambiar de modulo sin ser ese el que le correspondía. Ahora surgió otro y hare lo que me aconsejas y creare un hilo :) muchas gracias

2votos

indiglosv Puntos1150

Problema resuelto ..

estaba usando mal la instrucción else, al darle una repasada al manual de PHP me di cuenta de mi error, dandome resultado de esta manera.

elseif ($row["nivel"] == 0)
  { 
 session_start();
 $_SESSION['usuario'] = $usuario;
header("Location: index.php"); 

Por favor, accede o regístrate para responder a esta pregunta.

Otras Preguntas y Respuestas


...

Bienvenido a entre Desarrolladores, donde puedes realizar preguntas y recibir respuestas de otros miembros de la comunidad.

Conecta