Saneamiento de entradas de usuario en el desarrollo de plugins a medida

Desarrollar plugins a medida para WordPress requiere no solo funcionalidad, sino también una disciplina estricta en el saneamiento y validación de las entradas de usuario. Un input mal tratado puede derivar en XSS, SQL injection, pérdida de datos o problemas de rendimiento. En este artículo repasaremos principios, funciones nativas, patrones recomendados y ejemplos prácticos para que tu plugin sea seguro, consistente y fácil de auditar.

Por qué el saneamiento es imprescindible

La entrada de usuario es una superficie de ataque. Validar y sanitizar reduce riesgo, mejora la estabilidad y facilita el cumplimiento de políticas de privacidad y normas de seguridad. Dos conceptos importantes:

  • Validación: comprobar que los datos cumplen las reglas (tipo, rango, formato).
  • Sanitización: limpiar y normalizar los datos para evitar código malicioso o datos no deseados.

Además, hay que diferenciar entre sanitizar en entrada y escapar en salida. Sanitiza cuando guardas o procesas; escapa siempre al mostrar datos en HTML, atributos, JS o consultas SQL.

Principios prácticos para plugins a medida

  • Principio de menor privilegio: limita quién puede enviar datos sensibles (capabilities).
  • Valida primero, sanitiza después y escapa al final (output-escaping).
  • Usa APIs nativas de WordPress cuando existan.
  • Evita concatenar consultas SQL: usa consultas preparadas.
  • Registra y documenta qué campo acepta qué formato para facilitar auditoría.

Funciones y técnicas nativas recomendadas

WordPress y PHP ofrecen funciones específicas. A continuación se listan las más útiles con ejemplos prácticos.

Sanitización básica y más comunes

  • sanitize_text_field(): ideal para campos de texto simples.
  • sanitize_email(): valida y limpia correos.
  • esc_url_raw(): sanitiza URLs antes de guardarlas. Para salida, usar esc_url().
  • intval()/floatval(): convertir a números garantizando tipo.
  • wp_kses_post() o wp_kses(): permiten HTML seguro según reglas.

Escapado en la salida

Siempre escapa justo antes de imprimir datos en la vista:

  • esc_html() para contenido HTML.
  • esc_attr() para atributos HTML.
  • esc_url() para enlaces y recursos.

Protección en formularios: nonces y capacidades

Usa wp_nonce_field() y valida con wp_verify_nonce(). Además, comprueba capacidades con current_user_can() para evitar que usuarios sin permisos ejecuten acciones sensibles.

Consultas seguras con $wpdb

Nunca concatenes variables en SQL. Usa $wpdb->prepare() o las funciones de abstracción. Ejemplo:

$sql = $wpdb->prepare("SELECT * FROM {$wpdb->prefix}mi_tabla WHERE id = %d", intval( $id ));
$rows = $wpdb->get_results( $sql );

Ejemplos prácticos: formularios, settings y REST API

1) Guardar un campo de opción desde settings

Al registrar opciones, puedes definir una función de sanitización:

register_setting('mi_plugin_group', 'mi_plugin_opcion', array(
  'type' => 'string',
  'sanitize_callback' => 'mi_plugin_sanitize_opcion',
));

function mi_plugin_sanitize_opcion($input) {
  // Validación básica y sanitizado
  $output = array();
  $output['titulo'] = sanitize_text_field( $input['titulo'] );
  $output['url']    = esc_url_raw( $input['url'] );
  $output['activo'] = isset($input['activo']) ? 1 : 0;
  return $output;
}

Esta función mantiene el contrato de datos y evita almacenar HTML o scripts no deseados.

2) Procesar un formulario con nonce

if ( isset($_POST['mi_form']) ) {
  if ( ! isset($_POST['mi_nonce']) || ! wp_verify_nonce($_POST['mi_nonce'], 'accion_mi_form') ) {
    wp_die('Nonce inválido');
  }
  if ( ! current_user_can('manage_options') ) {
    wp_die('Sin permisos');
  }
  $nombre = sanitize_text_field( $_POST['nombre'] );
  $email  = sanitize_email( $_POST['email'] );
  // Guardar o procesar
}

3) Endpoints REST seguros

Al registrar rutas, define esquemas de validación y sanitización en args:

register_rest_route('mi-plugin/v1', '/item', array(
  'methods' => 'POST',
  'callback' => 'mi_plugin_crear_item',
  'permission_callback' => function() {
    return current_user_can('edit_posts');
  },
  'args' => array(
    'title' => array(
      'required' => true,
      'sanitize_callback' => 'sanitize_text_field',
      'validate_callback' => function($param, $request, $key) {
        return is_string($param) && strlen($param) > 3;
      }
    ),
    'url' => array(
      'sanitize_callback' => 'esc_url_raw'
    )
  )
));

Patrones avanzados y errores comunes a evitar

  • No confundir validación con escapado: validar formato, escapar para presentación.
  • No confiar en el cliente: cualquier validación JS debe replicarse en servidor.
  • No usar wp_kses sin reglas explícitas: define exactamente qué etiquetas y atributos permites.
  • No eliminar la auditable trazabilidad: guarda logs de acciones críticas con usuario y timestamp.

Uso de whitelists y blacklists

Prefiere listas blancas (whitelist) sobre listas negras. Por ejemplo, en selects o parámetros esperados, compara el input con valores permitidos antes de aceptar.

Pruebas y revisión

Incluye pruebas unitarias y pruebas de fuzzing para entradas inusuales. Revisa los puntos de entrada populares: settings, AJAX, REST API, upload handlers y shortcodes.

Recursos y referencias técnicas

Para profundizar en buenas prácticas y funciones estándar revisa la guía de seguridad de OWASP, la documentación de PHP sobre funciones de filtrado y MDN Web Docs para el manejo seguro de HTML y URL en el navegador. Estas fuentes ayudan a entender vectores de ataque y contramedidas en un contexto más amplio.

Checklist rápida antes de publicar un plugin

  • ¿Todos los formularios usan nonces y comprueban capacidades?
  • ¿Se sanitizan todos los inputs antes de almacenamiento?
  • ¿Se escapa la salida en plantillas y atributos?
  • ¿Se usan consultas preparadas para SQL?
  • ¿Hay pruebas automatizadas para inputs extremos?

Conclusión

El saneamiento de entradas en plugins a medida es una disciplina técnica que combina validación, sanitización y escapado. Aplicar funciones nativas de WordPress y PHP, proteger endpoints con nonces y capacidades, y usar consultas preparadas reduce significativamente los riesgos. Además, documentar el formato esperado de cada campo y construir pruebas automatizadas facilita mantenimiento y auditoría. Implementa estas prácticas desde el diseño del plugin: seguridad y calidad comienzan en la definición de datos, no como un parche posterior.

Tags: