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.

WordPress Plugin
07

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.

Código del tema: check_admin_referer

📘 Teoría

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.

1

En vez de comprobar rol textual, usa capacidades específicas como `manage_options` o capacidades personalizadas de tu plugin.

2

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.

3

Define capacidades pensadas por operación y centralízalas en constantes o métodos para no duplicar strings por el código.

Guard clause de permisos
if (!current_user_can('manage_options')) {
    wp_die('No tienes permisos para realizar esta acción.');
}

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.

1

Entrada

Se limpia antes de guardar o procesar.

  • sanitize_text_field
  • sanitize_email
  • absint
2

Salida

Se escapa según el contexto de render.

  • esc_html
  • esc_attr
  • esc_url

Caso real: CSRF en formulario de ajustes

Sin nonce, un usuario logueado puede ejecutar acciones sin querer desde otra web.

1

Un formulario de plugin guardaba opciones sin `check_admin_referer`. Bastaba visitar una URL maliciosa para disparar cambios en segundo plano.

2

Con nonce y verificación de capacidad, la acción queda acotada al contexto correcto y al usuario autorizado.

3

Además, registrar auditoría básica de cambios ayuda a detectar actividad sospechosa.

🧪 Aprende probando

Ejemplo Ejemplo guiado: guardar ajustes de forma segura Aplicamos guardas de capacidad, nonce y sanitización antes de persistir configuración.

🏁 Retos

Reto Reto real: endurece endpoint de borrado de caché Añade protección completa a una acción de mantenimiento en admin.

¿Qué es esto?

Soy Cristian Eslava y a veces hago webs para procrastinar yo y vosotros 😉.

Esta la hice en febrero de 2026 para facilitar el aprendizaje de mis alumnxs. Aprender desarrollo web practicando. La idea es que crezca semanalmente con nuevos temas, tests y retos.

Inspirado en MDN, en W3Schools, en Codepen, en el crack de Manz y en mil sitios de documentación sobre desarrollo web. Quería aportar además de bloques teóricos con ejemplos, la gamificación de los retos y el sistema de test que ya tenía en culTest .

Si te gustó, si no te gustó, si quieres saludarme, o invitarme a 🍻 no dudes en escribirme en cristianeslava@gmail.com .