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
¿Quieres comentar?
Inicia sesión con Telegram para participar en la conversación