Seguridad Web: XSS y Validación
La seguridad en aplicaciones PHP web no es opcional: es parte fundamental del trabajo. Los dos ataques más comunes son SQL Injection (insertar SQL malicioso en campos del formulario para manipular la base de datos) y XSS o Cross-Site Scripting (insertar JavaScript malicioso que se ejecuta en el navegador de otros usuarios). Ambos explotan el mismo error: confiar en datos del usuario sin validarlos ni escaparlos.
La regla de oro de seguridad PHP: nunca confíes en datos del usuario. Para prevenir SQL Injection: siempre usa prepared statements con PDO, nunca construyas consultas SQL concatenando strings del usuario. Para prevenir XSS: siempre escapa con htmlspecialchars() cuando muestres datos del usuario en HTML.
Para contraseñas: usa password_hash() para guardar y password_verify() para verificar, nunca guardes contraseñas en texto plano. Filtros como filter_var() validan emails, URLs y otros formatos comunes.
<?php
// XSS Prevention - SIEMPRE escapar datos del usuario
$nombre_usuario = "<script>alert('XSS')</script>";
echo htmlspecialchars($nombre_usuario, ENT_QUOTES, "UTF-8");
// Muestra el texto, no ejecuta el script
// Función helper corta
function e(string $str): string {
return htmlspecialchars($str, ENT_QUOTES, "UTF-8");
}
echo e($_GET["nombre"] ?? "");
// Validación con filter_input
$email = filter_input(INPUT_POST, "email", FILTER_VALIDATE_EMAIL);
if ($email === false || $email === null) {
echo "Email inválido";
}
$edad = filter_input(INPUT_POST, "edad", FILTER_VALIDATE_INT, [
"options" => ["min_range" => 18, "max_range" => 120]
]);
$url = filter_var($_POST["url"] ?? "", FILTER_SANITIZE_URL);
// Hash de contraseñas - NUNCA uses MD5 o SHA1
$password = "mi_contraseña_123";
$hash = password_hash($password, PASSWORD_BCRYPT);
// Verificar contraseña
if (password_verify($password, $hash)) {
echo "Contraseña correcta";
}
// CSRF Token
session_start();
// Generar token
if (empty($_SESSION["csrf_token"])) {
$_SESSION["csrf_token"] = bin2hex(random_bytes(32));
}
// En el formulario HTML
echo '<input type="hidden" name="csrf" value="' . e($_SESSION["csrf_token"]) . '">' ;
// Verificar en el servidor
if (!isset($_POST["csrf"]) || $_POST["csrf"] !== $_SESSION["csrf_token"]) {
http_response_code(403);
die("Token CSRF inválido");
}
// Validación robusta
function validarPassword(string $pass): array {
$errores = [];
if (strlen($pass) < 8) $errores[] = "Mínimo 8 caracteres";
if (!preg_match("/[A-Z]/", $pass)) $errores[] = "Requiere mayúscula";
if (!preg_match("/[0-9]/", $pass)) $errores[] = "Requiere número";
return $errores;
}
Practica esta lección
Resuelve los ejercicios del curso de PHP en la app, gratis y con corrección automática.
Empezar a practicar