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:

&lt;script&gt;

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 estado solo 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.




Post relacionados: