Seguridad Web
SQL Injection, XSS, validación de datos, contraseñas seguras y password_hash(): la base de una web responsable.
0 / 5 lecciones completadas (0%)
SQL Injection
Lección 02XSS
Lección 03Validación
Lección 04Contraseñas seguras
Lección 05password_hash()
SQL Injection
Ya se vio en el Módulo 2: la inyección SQL ocurre cuando datos escritos por el usuario se mezclan sin protección dentro de una consulta SQL, permitiendo que alguien manipule esa consulta. La defensa siempre son las consultas preparadas.
// Vulnerable:
$sql = "SELECT * FROM usuarios WHERE usuario = '$usuario' AND clave = '$clave'";
// Un atacante podria escribir: ' OR '1'='1 y saltarse el login
// Protegido:
$stmt = $pdo->prepare("SELECT * FROM usuarios WHERE usuario = ? AND clave = ?");
$stmt->execute([$usuario, $clave]);
¿Qué intenta conseguir un atacante con una inyección SQL en un formulario de login?
XSS
XSS (Cross-Site Scripting) ocurre cuando una web muestra sin filtrar texto escrito por un usuario, y ese texto contiene código JavaScript. Ese código se ejecuta en el navegador de otras personas que visiten la página, pudiendo robar información o suplantar sesiones.
// Vulnerable: se muestra el comentario tal cual
echo "<p>" . $_POST["comentario"] . "</p>";
// Un atacante podria escribir: <script>alert('hackeado')</script>
// Protegido: se escapan los caracteres especiales antes de mostrarlos
echo "<p>" . htmlspecialchars($_POST["comentario"], ENT_QUOTES) . "</p>";
¿Qué hace htmlspecialchars() para prevenir XSS?
Validación
Validar significa comprobar que un dato cumple lo esperado antes de usarlo: que un email tenga formato de email, que una edad sea un número positivo, que un campo obligatorio no esté vacío. Es la primera línea de defensa contra datos incorrectos o maliciosos.
function validarEdad($edad) {
if (!is_numeric($edad)) return "La edad debe ser un numero.";
if ($edad < 0 || $edad > 120) return "La edad no parece valida.";
return true;
}
$resultado = validarEdad($_POST["edad"] ?? "");
if ($resultado !== true) {
echo $resultado;
}
¿Cuál de estas es una buena práctica de validación de datos?
Contraseñas seguras
Una contraseña segura es larga, no se reutiliza en varios sitios y combina letras, números y símbolos. Como desarrolladores, además, nunca se debe guardar la contraseña de un usuario tal cual (en texto plano) en la base de datos.
Contrasena debil: 123456, nombre1234, qwerty
Contrasena fuerte: frase-larga-Y-dificil-de-adivinar-2026!
Regla de oro para desarrolladores:
NUNCA guardar la contrasena real en la base de datos.
Se guarda un "hash": una huella irreversible de la contrasena.
¿Por qué no se debe guardar la contraseña de un usuario tal cual en la base de datos?
password_hash()
PHP incluye la función password_hash() para convertir una contraseña en un hash seguro de forma automática, y password_verify() para comprobar si una contraseña introducida coincide con ese hash, sin necesidad de «deshacer» el hash nunca.
// Al registrar un usuario:
$hash = password_hash($_POST["clave"], PASSWORD_DEFAULT);
// Se guarda $hash en la base de datos, nunca la contrasena original
// Al iniciar sesion:
$hashGuardado = "..."; // obtenido de la base de datos
if (password_verify($_POST["clave"], $hashGuardado)) {
echo "Contrasena correcta, acceso permitido.";
} else {
echo "Contrasena incorrecta.";
}
¿Qué hace password_verify() en el ejemplo anterior?