Seguridad de aplicaciones PHP: top 10 vulnerabilidades para principiantes
\nPHP sigue siendo uno de los lenguajes más populares para el desarrollo web, pero su flexibilidad a menudo se convierte en vulnerabilidades si no se siguen las reglas básicas de seguridad. Según OWASP, la mayoría de los ataques ocurren debido a 10 errores típicos que cometen los desarrolladores principiantes. En este artículo analizaremos cada vulnerabilidad con ejemplos de código reales y mostraremos cómo proteger su aplicación.
\n\n1. Inyección SQL (SQL Injection)
\nEl ataque más común. El atacante inyecta código SQL malicioso a través de la entrada del usuario.
\nCódigo vulnerable:
\n<?php\n$id = $_GET['id'];\n$query = "SELECT * FROM users WHERE id = $id";\n$result = mysqli_query($conn, $query);\n?>\nProtección: Utilice consultas preparadas (prepared statements):
\n<?php\n$stmt = $conn->prepare("SELECT * FROM users WHERE id = ?");\n$stmt->bind_param("i", $_GET['id']);\n$stmt->execute();\n$result = $stmt->get_result();\n?>\n\n2. XSS (Cross-Site Scripting)
\nInserción de código JavaScript en la página a través de datos no validados.
\nCódigo vulnerable:
\n<?php\necho "Hola, " . $_GET['name'];\n?>\nProtección: Escape la salida con htmlspecialchars():
<?php\necho "Hola, " . htmlspecialchars($_GET['name'], ENT_QUOTES, 'UTF-8');\n?>\n\n3. CSRF (Cross-Site Request Forgery)
\nAtaque en el que el usuario realiza acciones no deseadas en su propio nombre.
\nCódigo vulnerable:
\n<form action="/delete.php" method="POST">\n <input type="submit" value="Eliminar cuenta">\n</form>\nProtección: Agregue un token CSRF:
\n<?php\nsession_start();\n$_SESSION['csrf_token'] = bin2hex(random_bytes(32));\n?>\n<form action="/delete.php" method="POST">\n <input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>">\n <input type="submit" value="Eliminar cuenta">\n</form>\n\n4. Almacenamiento inseguro de contraseñas
\nAlmacenamiento de contraseñas en texto plano o con hashes obsoletos (MD5, SHA1).
\nCódigo vulnerable:
\n<?php\n$password = md5($_POST['password']);\n// o\n$password = sha1($_POST['password']);\n?>\nProtección: Utilice password_hash() y password_verify():
<?php\n$hash = password_hash($_POST['password'], PASSWORD_BCRYPT);\n// Verificación:\nif (password_verify($input_password, $hash)) {\n echo "Contraseña correcta";\n}\n?>\n\n5. Trabajo inseguro con archivos (Inclusión de archivos local/remota)
\nInclusión de archivos a través de la entrada del usuario sin verificación.
\nCódigo vulnerable:
\n<?php\ninclude($_GET['page'] . '.php');\n?>\nProtección: Utilice una lista blanca de archivos permitidos:
\n<?php\n$allowed_pages = ['home', 'about', 'contact'];\n$page = $_GET['page'] ?? 'home';\nif (in_array($page, $allowed_pages)) {\n include($page . '.php');\n} else {\n include('404.php');\n}\n?>\n\n6. Configuración incorrecta de sesiones
\nUso de identificadores de sesión predecibles o falta de regeneración.
\nCódigo vulnerable:
\n<?php\nsession_start();\n$_SESSION['user_id'] = $user_id;\n// La sesión no se regenera después del inicio de sesión\n?>\nProtección:
\n<?php\nsession_start();\nsession_regenerate_id(true); // Regenerar ID después del inicio de sesión\n$_SESSION['user_id'] = $user_id;\n?>\n\n7. Validación de entrada insuficiente
\nConfiar en cualquier dato del usuario.
\nCó