Sistema de Login Seguro

Iniciado por GameAndWatch, 22 Junio 2012, 21:52 PM

0 Miembros y 1 Visitante están viendo este tema.

GameAndWatch

¡Hola! :D
Estoy creando un sistema de login en PHP, pero me ha surgido este problema.
Antes guardaba el login en cookies, pero me acabo de dar cuenta de lo peligroso que puede ser  >:D :¬¬...así que mi pregunta es:
:huh:¿que sistema es más seguro a la hora de realizar un login? :huh:
Gracias de antemano por la respuesta  :D

it3r

mira no tengo mucha experiencia en logins, pero se que se hace con sesiones, es decir utilizas la variable $_SESSION[] y en ella vas guardando datos por ejemplo, cuando el usuario introduce el user y pass estos se deben comparar con una base de datos, si estan correctos se escribe en la sesion algun valor como

$_SESSION['logeado']=TRUE;

con eso despues verificas si ya esta logeado con un

if(!empty($_SESSION['logeado']))

El usuario no podra modificar este dato porque?,, porque el servidor le pasa una cookie al cliente con el nombre de phpsessionid y este solo contiene un id,, cuando el usuario se mete a la página este le manda la cookie phpsessionid al servidor y el servidor busca en sus sessiones activas la que tenga el id que le paso el cliente.Por ende es mas seguro chequear por session que por cookie. (Si me equivoco corrijanme porfa xD).

Saludos

marko1985

Hola te dejo un código de mi propia cosecha que me da buenos resultados, está adaptado para un proyecto propio que estoy haciendo, pero vamos que lo puedes modificar a tus necesidades. En mi caso hay varios supuestos para hacer redirecciones, pero puedes simplificarlo en dos partes. Una si existe cookie y otra si no existe, dentro de la que no existe, si el usuario ha verificado la casilla de guardar la sesión creo la cookie, ya que si quieres conservar el estado de la sesión al cerrar el navegador es la única forma. Yo lo que hago es genear un identificador lo guardo en la base de datos, y cuándo se vuelve a meter verifico si ese id está en la BBDD. Si te roban la cookie es un problema de todas formas, pero para conservar el estado es la única forma, al menos desde lo que yo conozco. Puedes crear en el registro un sistema de preguntas y respuestas para que en cada login el salga una de las preguntas aleatoriamente y verificar si es ese usuario. Pero cómo todo login puedes poner todas las trabas que quieras. También podrías generar un certificado único para ese usuario, pero estamos en las mismas si te roban el certificado, ¿no?

Código (php) [Seleccionar]

<?php
session_start();
require_once "./includes/classes/class.DB_Handler.php";
require_once "./includes/classes/class.User.php";
require_once "./includes/classes/class.Profiles.php";

if(isset($_COOKIE['SocialCores'])){
$key $_COOKIE['SocialCores'];
try{
if($user User::check_user_cookie($key)){
$_SESSION['user'] = $user;
switch($_SESSION['user']['profiles']){
case 0:
header("Location:./home.php");
break;

case 1:
try{
$profiles_data Profiles::search_user_profiles($_SESSION['user']['id_user']);
while($data mysql_fetch_array($profiles_dataMYSQL_ASSOC)){
$_SESSION['user']['profiles_data'][] = array(
'id_profile'  => $data['id_profile'],
'type' => $data['type'],
'original_id' => $data['original_id'],
'blocked' => $data['blocked']
); 
}

$_SESSION['user']['profiles_data']['current_profile'] = $_SESSION['user']['profiles_data'][0];
$profile_data Profiles::get_profile_data($_SESSION['user']['current_profile']['type'], $_SESSION['user']['current_profile']['id_profile']);
$profile mysql_fetch_array($profile_dataMYSQL_ASSOC);
$_SESSION['user']['profiles_data']['current_profile']['data'] = $profile;
header("Location:./profile.php");
}
catch(ProfilesException $e){
$_SESSION['authError'] = $e->getMessage();
header("Location:./index.php");
}
break;

case 2:
case 3:
case 4:
case 5:
try{
$profiles_data Profiles::search_user_profiles($_SESSION['user']['id_user']);
while($data mysql_fetch_array($profiles_dataMYSQL_ASSOC)){
$_SESSION['user']['profiles_data'][] = array(
'id_profile'  => $data['id_profile'],
'type' => $data['type'],
'original_id' => $data['original_id'],
'blocked' => $data['blocked']
); 
}
header("Location:./switcher.profile.php");
}
catch(ProfilesException $e){
$_SESSION['authError'] = $e->getMessage();
header("Location:./index.php");
}
break;
}
}
else{
setcookie("SocialCores"$sessionIdtime() - 10"/");
$_SESSION['authError'] = "Sesión expirada, introduzca sus datos";
header("Location:./index.php");
}
}
catch(UserException $e){
$_SESSION['authError'] = $e->getMessage();
header("Location:./index.php");
}
}

else if(isset($_POST['email']) && isset($_POST['password'])){
$email=$_POST['email'];
$pass=$_POST['password'];

try{
if($user User::authUser($email$pass)){

$_SESSION['user'] = $user;

if(isset($_POST['rec']) && $_POST['rec']="on"){
$sessionId session_id();
setcookie("SocialCores"$sessionIdtime() + (60 60 24 365), "/");
$id_user $user['id_user'];
User::update_last_access_id($id_user$sessionId);
switch($_SESSION['user']['profiles']){
case 0:
header("Location:./home.php");
break;

case 1:
try{
$profiles_data Profiles::search_user_profiles($_SESSION['user']['id_user']);
while($data mysql_fetch_array($profiles_dataMYSQL_ASSOC)){
$_SESSION['user']['profiles_data'][] = array(
'id_profile'  => $data['id_profile'],
'type' => $data['type'],
'original_id' => $data['original_id'],
'blocked' => $data['blocked']
); 
}
$_SESSION['user']['profiles_data']['current_profile'] = $_SESSION['user']['profiles_data'][0];
$profile_data Profiles::get_profile_data($_SESSION['user']['current_profile']['type'], $_SESSION['user']['current_profile']['id_profile']);
$profile mysql_fetch_array($profile_dataMYSQL_ASSOC);
$_SESSION['user']['profiles_data']['current_profile']['data'] = $profile;
header("Location:./profile.php");
}
catch(ProfilesException $e){
$_SESSION['authError'] = $e->getMessage();
header("Location:./index.php");
}
break;

case 2:
case 3:
case 4:
case 5:
try{
$profiles_data Profiles::search_user_profiles($_SESSION['user']['id_user']);
while($data mysql_fetch_array($profiles_dataMYSQL_ASSOC)){
$_SESSION['user']['profiles_data'][] = array(
'id_profile'  => $data['id_profile'],
'type' => $data['type'],
'original_id' => $data['original_id'],
'blocked' => $data['blocked']
); 
}
header("Location:./switcher.profile.php");
}
catch(ProfilesException $e){
$_SESSION['authError'] = $e->getMessage();
header("Location:./index.php");
}
break;
}
}
else{
switch($_SESSION['user']['profiles']){
case 0:
header("Location:./home.php");
break;

case 1:
try{
$profiles_data Profiles::search_user_profiles($_SESSION['user']['id_user']);
while($data mysql_fetch_array($profiles_dataMYSQL_ASSOC)){
$_SESSION['user']['profiles_data'][] = array(
'id_profile'  => $data['id_profile'],
'type' => $data['type'],
'original_id' => $data['original_id'],
'blocked' => $data['blocked']
); 
}
$_SESSION['user']['profiles_data']['current_profile'] = $_SESSION['user']['profiles_data'][0];
$profile_data Profiles::get_profile_data($_SESSION['user']['profiles_data']['current_profile']['type'], $_SESSION['user']['profiles_data']['current_profile']['id_profile']);
$profile mysql_fetch_array($profile_dataMYSQL_ASSOC);
$_SESSION['user']['profiles_data']['current_profile']['data'] = $profile;
header("Location:./profile.php");
}
catch(ProfilesException $e){
$_SESSION['autherror'] = $e->getMessage();
header("Location:./index.php");
}
break;

case 2:
case 3:
case 4:
case 5:
try{
$profiles_data Profiles::search_user_profiles($_SESSION['user']['id_user']);
while($data mysql_fetch_array($profiles_dataMYSQL_ASSOC)){
$_SESSION['user']['profiles_data'][] = array(
'id_profile'  => $data['id_profile'],
'type' => $data['type'],
'original_id' => $data['original_id'],
'blocked' => $data['blocked']
); 
}
header("Location:./switcher.profile.php");
}
catch(ProfilesException $e){
$_SESSION['authError'] = $e->getMessage();
header("Location:./index.php");
}
break;
}
}
}
else{
$_SESSION['authError'] = "Email o contraseña incorrectos";
header("Location:./index.php");
}
}
catch(UserException $e){
$_SESSION['authError'] = $e->getMessage();
header("Location:./index.php");
}
catch(Exception $e){
$_SESSION['authError'] = $e->getMessage();
header("Location:./index.php");
}
}

else{
$_SESSION['authError'] = "Debe acceder al sistema através de esta página";
header("Location:./index.php");
}



GameAndWatch

Lo primero:
¡Gracias a los dos por responder! :D :D
Pero tengo una duda con el código. Veo que guardas el id en la BBDD, pero...¿Cuando borras ese id? Lo digo porque si no, se te puede crear una tabla enorme... :-\

marko1985

Hola,

Quizás te he dejado a medias con ese código y falta complementarlo. Cómo puedes ver en el script de arriba hago unos includes con una clases que he diseñado para este proposito y que despues también utilizo a lo largo de la aplicacion

En la clase class.User.php existen unos métodos estáticos, uno de estos métodos es check_user_cookie('$key")

Te pongo aquí el código

Código (php) [Seleccionar]

public static function check_user_cookie($key){
$db = new DB_Handler('localhost', 'MI BASE DE DATOS');
$key = md5($key);
$sql = "SELECT * FROM users WHERE last_valid_sessid = '$key'";
if($query =  mysql_query($sql, $db->link)){
$user = mysql_fetch_array($query);
return $user;
}
else{
return false;
}
}


Cómo puedes ver busco en la tabla usuarios un campo que he llamado last_valid_sessid con el valor $key, cuándo se crea la cookie por primera vez este valor se guarda en un campo llamado last_valid_sessid, cuándo vuelva ha acceder se sobreescribe con un nuevo valor. no guardar los ID de las sesiones en ningún sitio diferente sino que va asociado a un campo de la tabla usuarios, que puedes establecer desde un inicio como valor Null te pongo un pantallazo de la tabla.



No sé si me he explicado bien,

El flujo sería:

LEO COOKIE -> BUSCO VALOR EN BBDD -> SI EXISTE VALIDO LA SESIÓN -> SOBREESCRIBIMOS COOKIE Y BBDD CON UN NUEVO ID.

Yo lo tengo muy liado con mis clases y mis historias pero más o menos sería así.

Un saludo.

GameAndWatch

Ahora sí que lo entiendo :D

;-) ;-)¡¡Muchas gracias!! ;-) ;-)

Con PHP había mis cosas internas, pero nunca había hecho nada de login (bueno, he hecho 2 pero con cookies) ;)



marko1985

De nada.

De todas formas yo quería algo muy específico, y es probable que tenga fallos, he intentado hacerlo seguro, pero aquí hay verdaderos expertos en seguridad que estrujarían mi código rápidamente. Aún así te recomiendo encarecidamente que cuándo tengas más por la mano PHP uses algún Framework ya que facilitan mucho el trabajo para estas tareas comunes.

Te pongo algunos de los más comunes

Zend Framework (de los creadores de PHP)
Symphony
Cake
CodeIgniter 2 (Yo estoy empezando con este ahora)

Saludos, cualquier cosa en la que se pueda ayudar ya sabes...