7 errores críticos que todos cometen con PHP (y cómo resolverlos)

php 7 errores críticos que todos cometen con PHP (y cómo resolverlos)

7 errores críticos que todos cometen con PHP (y cómo resolverlos)

Este post va directo al grano: errores reales que veo en código PHP de producción y cómo corregirlos de forma práctica. Por cada error tienes el por qué, un ejemplo vulnerable y la corrección recomendada.

Error 1 — No usar consultas preparadas (riesgo de SQL Injection)

Por qué duele: concatenar entrada del usuario en SQL permite inyección y compromete la base de datos.

<?php
// vulnerable
$id = $_GET['id'];
$result = $pdo->query("SELECT * FROM users WHERE id = $id");
?>

Solución: siempre usar consultas preparadas (PDO/parameter binding) y validar el tipo si corresponde.

<?php
// seguro
$stmt = $pdo->prepare('SELECT * FROM users WHERE id = :id');
$stmt->execute(['id' => (int)$_GET['id']]);
$user = $stmt->fetch();
?>

Error 2 — Usar funciones obsoletas o APIs inseguras (mysql_*)

Por qué duele: las funciones mysql_* fueron eliminadas y fomentan malas prácticas. Usa PDO o mysqli con prepared statements.

// Evita: mysql_query(), mysql_connect()
// Usa:
<?php
$pdo = new PDO('mysql:host=localhost;dbname=app', 'user', 'pass', [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);
?>

Error 3 — Validación/filtrado insuficiente (confianza en el cliente)

Por qué duele: todo input del cliente es potencialmente malicioso. Validar y sanear en servidor es mandatorio.

// Vulnerable: confiar en datos del formulario
$email = $_POST['email'];
// Mejora: validar
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
    throw new InvalidArgumentException('Email inválido');
}

Error 4 — Manejo inseguro de uploads (sin validación, risk de RCE/path traversal)

Por qué duele: permiten subir scripts, sobrescribir archivos o almacenar fuera de control.

<?php
// Vulnerable: guardando el nombre original sin comprobaciones
move_uploaded_file($_FILES['file']['tmp_name'], __DIR__ . '/uploads/' . $_FILES['file']['name']);
?>

Solución: validar tamaño, tipo (whitelist), generar nombre aleatorio, almacenar fuera del webroot y evitar extensiones peligrosas.

<?php
$allowed = ['png','jpg','jpeg','pdf'];
$ext = strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION));
if (!in_array($ext, $allowed)) {
    throw new RuntimeException('Tipo de archivo no permitido');
}
if ($_FILES['file']['size'] > 2_000_000) {
    throw new RuntimeException('Archivo demasiado grande');
}
$targetDir = __DIR__ . '/private_uploads/';
$filename = bin2hex(random_bytes(16)) . '.' . $ext; // nombre seguro
move_uploaded_file($_FILES['file']['tmp_name'], $targetDir . $filename);
?>

Error 5 — Mostrar errores en producción (display_errors = On)

Por qué duele: la salida de errores puede filtrar rutas, consultas, credenciales y stack traces.

// No hagas esto en producción
ini_set('display_errors', '1');
// Haz esto en producción
ini_set('display_errors', '0');
ini_set('log_errors', '1');
error_log('Mensaje de error');

En producción, registra errores en ficheros y usa un sistema de monitoreo (Sentry, Bugsnag, etc.).

Error 6 — Manejo incorrecto de contraseñas (md5/sha1 sin sal)

Por qué duele: algoritmos obsoletos son triviales de romper. Usa APIs modernas y resistentes.

// Vulnerable
$hash = md5($password);
// Seguro
$hash = password_hash($password, PASSWORD_DEFAULT);
// Verificación
if (password_verify($password, $hash)) {
    // OK
}

Error 7 — Sesiones inseguras (no regenerar ID, cookies mal configuradas)

Por qué duele: session fixation, robo de sesión y exposición en conexiones no seguras.

<?php
// Configuración recomendada al iniciar la app
session_set_cookie_params([
    'lifetime' => 0,
    'path' => '/',
    'domain' => 'tu-dominio.com',
    'secure' => true,   // solo HTTPS
    'httponly' => true, // imposible acceder via JS
    'samesite' => 'Lax',
]);
session_start();
// Al autenticar:
session_regenerate_id(true);
?>

Buenas prácticas extra (rápidas y accionables)

  • Usa declare(strict_types=1) y tipado donde puedas para detectar errores temprano.
  • Integra PHPStan/Psalm en tu CI para análisis estático.
  • Gestiona dependencias y revisa vulnerabilidades: composer audit / GitHub Dependabot.
  • Aplica Content Security Policy y headers: X-Frame-Options, X-Content-Type-Options, Referrer-Policy.
  • Evita reinventar la rueda: usa librerías probadas para autenticación (OAuth libraries, JWT libs bien mantenidas).

Este conjunto de correcciones evita la mayoría de incidentes comunes en aplicaciones PHP. Siguiente paso: añade pruebas automatizadas que verifiquen tus controles (fuzzing de endpoints, tests de integración que comprueben validación y seguridad) y ejecuta análisis estático en cada PR. Un consejo avanzado: aplica mínimo privilegio para la cuenta DB y separa servicios para limitar blast radius.

Comentarios
¿Quieres comentar?

Inicia sesión con Telegram para participar en la conversación


Comentarios (0)

Aún no hay comentarios. ¡Sé el primero en comentar!

Iniciar Sesión