Seguridad operativa en plugins: sanitización, nonces y capacidades
Blindas las acciones críticas del plugin para evitar CSRF, XSS y escalado de privilegios con un flujo defensivo claro y repetible.
Un plugin puede tener una interfaz bonita y aun así ser inseguro si no valida entradas, permisos y origen de peticiones.
En esta lección aplicarás el triángulo de seguridad mínimo en WordPress: sanitizar, verificar nonce y comprobar capacidad.
Este patrón debe ejecutarse en cada acción sensible de admin, AJAX o REST: primero permisos, luego nonce, después sanitización.
Cuando interiorizas esta secuencia, reduces de forma drástica vulnerabilidades comunes en plugins personalizados.
- No es opcional ni intercambiable: permiso -> nonce -> dato limpio.
- Primero comprueba capacidad (`current_user_can`) para asegurarte de que el usuario tiene permiso funcional para esa acción.
- Después valida nonce (`check_admin_referer` o `wp_verify_nonce`) para evitar CSRF.
- Finalmente sanitiza y valida estructura del payload antes de guardar o ejecutar lógica.
- Permiso: quién puede hacerlo.
Secuencia defensiva obligatoria en acciones sensibles
No es opcional ni intercambiable: permiso -> nonce -> dato limpio.
Primero comprueba capacidad (`current_user_can`) para asegurarte de que el usuario tiene permiso funcional para esa acción.
Después valida nonce (`check_admin_referer` o `wp_verify_nonce`) para evitar CSRF.
Finalmente sanitiza y valida estructura del payload antes de guardar o ejecutar lógica.
- Permiso: quién puede hacerlo.
- Nonce: desde dónde viene la petición.
- Sanitización: qué datos son válidos.
Capacidades: evita confiar en 'ser admin' sin matices
Las capacidades son más precisas que el rol bruto.
En vez de comprobar rol textual, usa capacidades específicas como `manage_options` o capacidades personalizadas de tu plugin.
Caso real: una acción crítica quedó abierta a editores por una comprobación ambigua del rol; el resultado fue modificación no autorizada de configuración global.
Define capacidades pensadas por operación y centralízalas en constantes o métodos para no duplicar strings por el código.
Sanitizar entrada no sustituye escapar salida
Son capas distintas: una protege almacenamiento, otra protege render.
Sanitiza al guardar (`sanitize_text_field`, `sanitize_key`, `absint`, etc.) para evitar persistir datos peligrosos o inválidos.
Escapa al mostrar (`esc_html`, `esc_attr`, `esc_url`) porque el contexto de salida define el riesgo real.
Nunca asumas que 'ya estaba limpio' en otro punto del flujo.
Caso real: CSRF en formulario de ajustes
Sin nonce, un usuario logueado puede ejecutar acciones sin querer desde otra web.
Un formulario de plugin guardaba opciones sin `check_admin_referer`. Bastaba visitar una URL maliciosa para disparar cambios en segundo plano.
Con nonce y verificación de capacidad, la acción queda acotada al contexto correcto y al usuario autorizado.
Además, registrar auditoría básica de cambios ayuda a detectar actividad sospechosa.