Seguridad de aplicaciones PHP: top 10 vulnerabilidades y métodos de protección
PHP sigue siendo uno de los lenguajes más populares para el desarrollo web, sin embargo, su flexibilidad a menudo se convierte en vulnerabilidades. Según informes de seguridad, más del 70% de las aplicaciones web tienen al menos una vulnerabilidad crítica. En este artículo analizaremos las 10 vulnerabilidades más peligrosas de PHP, proporcionaremos ejemplos reales de código y mostraremos cómo proteger eficazmente su aplicación.
1. Inyección SQL (SQL Injection)
La vulnerabilidad más común y peligrosa. Un atacante puede inyectar código SQL arbitrario a través de la entrada del usuario.
Código vulnerable:
<?php$id = $_GET['id'];$query = "SELECT * FROM users WHERE id = $id";$result = mysqli_query($conn, $query);?>Protección: uso de declaraciones preparadas (Prepared Statements):
<?php$stmt = $conn->prepare("SELECT * FROM users WHERE id = ?");$stmt->bind_param("i", $_GET['id']);$stmt->execute();$result = $stmt->get_result();?>2. XSS (Cross-Site Scripting)
Inyección de scripts maliciosos en páginas web. Existen tres tipos: reflejado, almacenado y basado en DOM.
Código vulnerable:
<?phpecho "Hola, " . $_GET['name'];?>Protección: escape de salida:
<?phpecho "Hola, " . htmlspecialchars($_GET['name'], ENT_QUOTES, 'UTF-8');?>3. CSRF (Cross-Site Request Forgery)
Ataque en el que un atacante obliga al usuario a realizar acciones no deseadas en un sitio donde está autenticado.
Protección: uso de tokens CSRF:
<?phpsession_start();if (empty($_SESSION['csrf_token'])) { $_SESSION['csrf_token'] = bin2hex(random_bytes(32));}
// Verificación al enviar el formularioif ($_POST['csrf_token'] !== $_SESSION['csrf_token']) { die('¡Ataque CSRF detectado!');}?>
<form method="POST"> <input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>"> <button type="submit">Enviar</button></form>4. Path Traversal (Recorrido de rutas)
Vulnerabilidad que permite leer archivos arbitrarios en el servidor.
Código vulnerable:
<?php$file = $_GET['file'];include("pages/" . $file);?>Protección: validación y restricción de rutas:
<?php$allowed_files = ['about.php', 'contact.php', 'home.php'];$file = basename($_GET['file']);
if (in_array($file, $allowed_files)) { include("pages/" . $file);} else { die('Acceso denegado');}?>5. Subida de archivos (File Upload)
La subida insegura de archivos puede provocar la ejecución de código arbitrario en el servidor.
Protección: verificación del tipo MIME y la extensión:
<?php$allowed_types = ['image/jpeg', 'image/png', 'image/gif'];$max_size = 5 * 1024 * 1024; // 5 MB
if ($_FILES['file']['size'] > $max_size) { die('El archivo es demasiado grande');}
$finfo = finfo_open(FILEINFO_MIME_TYPE);$mime_type = finfo_file($finfo, $_FILES['file']['tmp_name']);
if (!in_array($mime_type, $allowed_types)) { die('Tipo de archivo no permitido');}
// Renombramos el archivo por seguridad$extension = pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION);$new_name = md5(uniqid()) . '.' . $extension;move_uploaded_file($_FILES['file']['tmp_name'], 'uploads/' . $new_name);?>6. Fijación de sesión (Session Fixation)
Ataque en el que un atacante impone al usuario un identificador de sesión conocido.
Protección: regeneración del ID de sesión:
<?phpsession_start();
// Después de una autenticación exitosasession_regenerate_id(true);?>