Sistema de login ¿es seguro esto?

B

Bueno soy bastante principiante en esto de php y acabo de hacer mi primer sistema de login, en mysqli y me preguntaba si es "seguro" y que le puedo cambiar para que sea mas seguro (sin tener que hacerlo de 0)

Gracias de ante mano!

<?php

if(!empty($_POST)) {
	if(isset($_POST['username']) && isset($_POST['password'])) {

	if(strlen($_POST['username']) > 0 && strlen($_POST['username']) < 25 && strlen($_POST['password']) > 0 && strlen($_POST['password']) < 30) {

		# Nombre de usuario
		$Username =	trim($_POST['username']);
		$Username = stripslashes($Username);
		$Username = strip_tags($Username);

		# Contraseña
		$Password = trim($_POST['password']);
		$Password = stripslashes($Password);
		$Password = strip_tags($Password);

		$Username = mysqli_real_escape_string($db, $Username);
		$Password = mysqli_real_escape_string($db, $Password);

		# Lo que sigue va adentro de la verificación de recaptcha pero lo quite para que no se haga lío
		include 'conexion.php';

		$Logueo = $db->query("SELECT * FROM usuarios WHERE (username = "."'$Username' or email = "."'$Username') and password = "."'$Password'");
		if($Logueo) {

			$user_id   = null;
			$user_name = null;

			while($row = $Logueo->fetch_array()) {
				$user_id   = $row['id'];
				$user_name = $row['username'];
				$user_adm = $row['user_adm'];
				break;
			} 

			if($user_name != null) {

				session_start();
				$_SESSION["user_id"] = $user_id;
				$_SESSION["user_name"] = $user_name;
				$_SESSION["user_adm"] = $user_adm;
				echo "Iniciaste session de forma correcta!";
			}
			else { echo "Error datos incorrectos."; }
		}
		else { echo "error #4"; }
	}
	else { echo "error #3"; }
}
else { echo "error #2";}
}
else { echo "error #1";}
?>
B

Hice un tema similar el año pasado, siempre se puede mejorar la seguridad, échale un ojo a este hilo, hay un usuario que también colgó un sistema de login.

1 respuesta
pantocreitor

Mírate de preparar las consultas para evitar inyección.
Si recibes los datos de una web a través de una web mírate de cifrar y descifrar los datos.
Viendo que estás practicando y tal no te va a venir mal trastear con esas cosillas y ya si metes JWT/S pues mas cosas que vas aprendiendo.

1 respuesta
vincen

Aparte de todo lo que te han dicho, evita seleccionar todo en la consulta si solo vas a necesitar X datos, en tu caso id,username,user_adm

1 respuesta
bLaKnI

Muy resumidamente y dejando a un lado todo lo demás, basicamente con todo esto:

# Nombre de usuario
		$Username =	trim($_POST['username']);
		$Username = stripslashes($Username);
		$Username = strip_tags($Username);

	# Contraseña
	$Password = trim($_POST['password']);
	$Password = stripslashes($Password);
	$Password = strip_tags($Password);

	$Username = mysqli_real_escape_string($db, $Username);
	$Password = mysqli_real_escape_string($db, $Password);

Tienes "suficiente", sí.

1 respuesta
AikonCWD

#5 Está un poco "outdated" el mysqli_real_escape_string. Es seguro, pero debería verificar el charset en la banda del servidor, no sea que se encuentre con alguna sorpresa desagradable.

Lo mejor a día de hoy es utilizar PDO y preparar las queries: https://www.php.net/manual/en/book.pdo.php
Ejemplo:

$stmt = $pdo->prepare('SELECT * FROM empleados WHERE name = :name');

$stmt->execute([ 'name' => $name ]);

foreach ($stmt as $row) {
    // Do something with $row
}
2 1 respuesta
B

#2 Gracias, lo miraré

#3 #6 Tendré que ponerme a buscar cositas sobre las consultas preparadas, no las entiendo muy bien, gracias!

#4 Sí, me confundí ahí.. muchas gracias!

Wasd

Llevo sin tocar PHP eones pero estás metiendo la password tal cual en la BD no? Si la guardas tu, utiliza un sistema de cifrado y salt que no te permita descifrarla ni a ti mismo, únicamente cifrarla para comprobar que el usuario es quien dice ser.

La otra opción es usar algun servicio de terceros como Firebase, que ya te provee de un sistema de token, refresh token y API, y así ni siquiera guardas tú las passwords.

Si vas a seguir haciendolo por tu cuenta, no compruebes la validación de la password con un if en mitad de la lógica. Preparate un servicio que unifique la forma de validar que un user y password cumple los requisitos que necesitas, e invoca siempre ese servicio. De lo contrario tendrás ese if repetido en mil sitios y es propenso a errores y despistes humanos (cambiarlo en X sitios pero no en todos, por lo tanto lo que hoy funciona, mañana ya no).

Tema aparte, para aprender está genial que hagas las queries tu mismo. Sin embargo ese sistema es poco mantenible y escalable. Para queries sencillas utiliza algún tipo de ORM en el que reflejes tus tablas en forma de entidades y las gestiones via repositorios. Normalmente estos ya te proveen de un query builder o la posibilidad de mandar las queries a pelo si necesitas hacerlas mas complejas, o para sacar estadísticas, etc...

Lo suyo sería separar la lógica de recibir los params del request body (controller), comprobarlos (servicios o alguna librería de validación) y hacer acciones sobre la BD (repositorios via entidades ORM).

Espero que sea de ayuda.

Usuarios habituales