Seguridad mínima para un CRUD en PHP (sin complicarte la vida) 🔐
Cuando creas un CRUD público —como el caso de estudio que estamos desarrollando— hay algo que no puedes ignorar:
Si está en internet, alguien va a intentar romperlo.
No necesitas convertir tu proyecto en una fortaleza militar, pero sí aplicar una seguridad mínima inteligente que evite:
- Inyección de código.
- Eliminaciones maliciosas.
- Spam masivo.
- Datos basura.
- Ataques automatizados simples.
En este post veremos cómo proteger tu CRUD sin añadir complejidad innecesaria.
1) XSS: proteger la salida con htmlspecialchars()
Uno de los ataques más comunes en aplicaciones web es el XSS (Cross-Site Scripting).
¿Qué es XSS?
Imagina que alguien escribe en el campo “nombres”:
<script>alert('hack')</script>
Si tú muestras eso sin protección:
echo $emp['nombres'];
El navegador ejecutará el script.
Resultado:
- Ventanas emergentes.
- Redirecciones.
- Robo de sesiones.
- Inyección de contenido malicioso.
Solución simple y efectiva
Siempre escapar la salida con:
htmlspecialchars()
En tu CRUD ya lo haces correctamente:
function e($str) {
return htmlspecialchars((string)$str, ENT_QUOTES, 'UTF-8');
}
Y luego:
<?= e($emp['nombres']) ?>
¿Qué hace esto?
Convierte:
<script>
En:
<script>
Así el navegador lo muestra como texto, no lo ejecuta.
2) CSRF: proteger formularios y acciones destructivas
Ya lo implementaste correctamente, pero aquí explicamos por qué.
¿Qué es CSRF?
CSRF (Cross-Site Request Forgery) es un ataque donde otro sitio intenta ejecutar acciones en tu aplicación sin que el usuario lo note.
Ejemplo:
Un atacante envía un enlace oculto como:
https://tusitio.com/crud.php?delete=EMP001
Si el usuario hace clic estando autenticado, se elimina el registro.
Protección con token CSRF
Tu implementación es correcta:
Generación del token:
if (empty($_SESSION['csrf'])) {
$_SESSION['csrf'] = bin2hex(random_bytes(16));
}
Envío en formulario:
<input type="hidden" name="csrf" value="<?= e($csrf) ?>">
Validación:
if (!hash_equals($_SESSION['csrf'], $token)) {
exit;
}
Esto garantiza que:
- Solo el formulario generado por tu servidor puede ejecutar acciones.
- Los enlaces externos no funcionarán.
3) Validación de inputs: no confíes en el usuario
Aunque uses PDO, debes validar los datos.
En tu CRUD ya aplicas validaciones como:
if ($codigo === '' || strlen($codigo) > 10)
Esto protege contra:
- Desbordes de columnas.
- Datos inválidos.
- Intentos de romper estructura.
Reglas mínimas recomendadas
Para demos públicas:
- Limitar longitud (como ya haces).
- No permitir HTML.
- No permitir textos excesivamente largos.
- Convertir números a
(int)cuando corresponda. - Validar que
estadosolo sea 0 o 1.
4) Limitar resultados (protección de rendimiento)
Tu uso de:
LIMIT 200
Es una forma sencilla de evitar que:
- El sistema cargue miles de registros.
- Se consuma memoria excesiva.
- Se degrade el rendimiento.
En demos públicas, esto es fundamental.
5) Tips anti-trolls para demos públicas (sin login)
Como tu CRUD no tiene autenticación, es importante poner límites inteligentes.
Aquí van consejos prácticos que no complican el proyecto:
1️⃣ Limitar cantidad de acciones por IP (opcional simple)
Puedes:
- Guardar acciones en sesión.
- Limitar a X inserciones por minuto.
Ejemplo simple conceptual:
$_SESSION['count']++;
if ($_SESSION['count'] > 20) {
die("Demasiadas acciones.");
}
No es perfecto, pero reduce abuso básico.
2️⃣ Limitar longitud del buscador
Ejemplo:
if (strlen($q) > 50) {
$q = substr($q, 0, 50);
}
Evita cargas innecesarias.
3️⃣ No permitir uploads
En demos públicas:
- Evita subida de archivos.
- Evita ejecución dinámica.
- Evita eval() (nunca usarlo).
4️⃣ Cron de limpieza automática (tu idea es excelente)
Tu estrategia de:
- Reset semanal de la tabla.
- Reinsertar datos de ejemplo.
Es una solución elegante para:
- Evitar acumulación de basura.
- Mantener la demo limpia.
- Prevenir abuso masivo.
Eso convierte tu demo en algo sostenible.
6) Hard delete vs Soft delete
Actualmente usas:
DELETE FROM empleados WHERE codigo = ?
En producción real, muchas veces se usa:
UPDATE empleados SET estado = 0
Eso evita pérdida definitiva.
Para un caso de estudio, el DELETE directo está bien.
7) Seguridad mínima aplicada en tu CRUD (resumen real)
Tu proyecto ya implementa correctamente:
✅ PDO con consultas preparadas
✅ htmlspecialchars() para salida
✅ Token CSRF en POST
✅ Token CSRF en DELETE
✅ Validación por longitud
✅ LIMIT en consultas
✅ Confirmación antes de eliminar
Conclusión:
No necesitas un firewall empresarial para proteger un CRUD educativo.
Pero sí necesitas:
- Escapar la salida (XSS)
- Proteger acciones con CSRF
- Validar inputs
- Limitar resultados
- Tener limpieza periódica
Con estas medidas, tu CRUD público es:
- Seguro para ser demo.
- Suficientemente robusto.
- Educativo y profesional.
Y además sirve como ejemplo real de buenas prácticas.