Guía completa de seguridad en PHP para desarrolladores

php Guía completa de seguridad en PHP para desarrolladores

Guía completa de seguridad en PHP para desarrolladores

PHP sigue siendo el motor de millones de aplicaciones web. Esta guía concentra las prácticas esenciales y ejemplos prácticos para minimizar vulnerabilidades comunes: inyección SQL, XSS, CSRF, sesiones inseguras, y malas configuraciones. Aquí verás qué hacer y el por qué, con snippets listos para usar.

A quién va dirigida

Desarrolladores PHP con conocimientos básicos-intermedios que quieren endurecer aplicaciones propias o de clientes, y equipos que preparan apps para producción.

Modelo de amenazas (rápido)

  • Atacantes remotos que explotan entradas sin validar (SQLi, XSS).
  • Usuarios autenticados que intentan escalar privilegios o forzar CSRF.
  • Exposición de secretos por mala configuración (.env en repo, errores visibles).

1) Validación y saneamiento de entrada

Siempre trata datos externos como maliciosos. Valida por tipo y rango; sanea al salida según el contexto.

  • Validación en servidor: filter_var, ctype_* o librerías de validación.
  • Sanea para HTML con htmlspecialchars; para atributos JS/URL usa funciones específicas.
// Validar email
$email = $_POST['email'] ?? '';
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
    throw new RuntimeException('Email inválido');
}

// Evitar XSS al mostrar
echo htmlspecialchars($username, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');

2) Acceso a la base de datos: PDO y consultas preparadas

Nunca concatenes valores en SQL. Usa consultas preparadas y tipos cuando sea posible.

$pdo = new PDO($dsn, $user, $pass, [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);

$stmt = $pdo->prepare('SELECT id, name FROM users WHERE email = :email');
$stmt->execute([':email' => $email]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);

Si necesitas consultas dinámicas (columnas, ORDER BY), valida y whitelist los valores antes de interpolarlos.

3) Autenticación y hashing de contraseñas

Usa password_hash/password_verify. No inventes tu propio algoritmo.

// Registrar
$hash = password_hash($plainPassword, PASSWORD_DEFAULT);
// Verificar
if (password_verify($inputPassword, $hash)) {
    // OK
}

Re-hash automático si cambian costos:

if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
    $newHash = password_hash($plainPassword, PASSWORD_DEFAULT);
    // Guardar nuevo hash
}

4) Gestión segura de sesiones

Configura cookies de sesión y regenera ID al autenticar.

// Antes de session_start()
ini_set('session.use_strict_mode', 1);
session_set_cookie_params([
    'lifetime' => 0,
    'path' => '/',
    'domain' => 'tu-dominio.com',
    'secure' => true,
    'httponly' => true,
    'samesite' => 'Lax',
]);
session_start();

// Al iniciar sesión correctamente
session_regenerate_id(true);
$_SESSION['user_id'] = $userId;

Evita almacenar datos sensibles sin cifrado en la sesión y limita su contenido.

5) CSRF: tokens y cabeceras

Protege formularios y endpoints mutables. Para APIs con tokens (Bearer) CSRF no aplica igual; para cookies sí.

// Generar token
if (empty($_SESSION['csrf_token'])) {
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}

// En formulario
echo '';

// Verificar
if (!hash_equals($_SESSION['csrf_token'] ?? '', $_POST['csrf_token'] ?? '')) {
    http_response_code(403);
    exit('CSRF token inválido');
}

6) XSS: escapar según contexto

Escapa para HTML (htmlspecialchars), para atributos, CSS y JS usa estrategias específicas. Nunca uses addslashes para esto.

  • Para valores en HTML: htmlspecialchars(..., ENT_QUOTES, 'UTF-8')
  • Para JSON en
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