Contents
Introducción
Crear shortcodes en WordPress es una forma potente de añadir contenido dinámico y reutilizable. Sin embargo, si no se programan correctamente, los shortcodes pueden introducir vulnerabilidades, sobre todo XSS (cross-site scripting) o permitir ejecución involuntaria de datos no confiables. Este artículo muestra, con todo lujo de detalles, cómo diseñar e implementar un shortcode seguro con atributos en PHP: validación de atributos, saneamiento de contenido, escape de salida y buenas prácticas.
Conceptos clave para la seguridad
- Validar: comprobar que los atributos recibidos estén dentro de los valores esperados (listas blancas, tipos numéricos, booleanos).
- Saneamiento: aplicar funciones de saneamiento a los datos entrantes (sanitize_text_field, esc_url_raw, absint, sanitize_html_class, etc.).
- Escapado: cuando generes HTML de salida, escapar con las funciones apropiadas (esc_html, esc_attr, esc_url, wp_kses_post) para evitar inyección XSS.
- Contenido: permitir solo HTML seguro para el contenido interno del shortcode mediante wp_kses_post o una lista blanca personalizada.
- Evitar ejecución: nunca evalúes código PHP desde atributos ni incluyas archivos arbitrarios basados en valores recibidos.
- Privilegios: si el shortcode realiza acciones sensibles (modificar base de datos, mostrar datos privados), comprueba capacidades de usuario y usa nonces si se genera un formulario.
Diseño del shortcode
Antes de programar, define claramente los atributos permitidos y su tipo. Ejemplo: un shortcode tipo card que admita atributos:
- title: texto (string)
- url: URL válida
- image: URL válida
- size: valor predefinido (smallmediumlarge)
- align: valor predefinido (leftcenterright)
- show_image: boolean (truefalse)
- class: clase CSS permitida (sanitize_html_class)
- content: contenido interno con HTML permitido (wp_kses_post)
Implementación paso a paso
-
Registrar y establecer valores por defecto:
Usa shortcode_atts para mezclar atributos recibidos con valores por defecto.
-
Saneamiento inicial de atributos:
Usa funciones como sanitize_text_field, esc_url_raw, absint, sanitize_html_class y listas blancas con in_array para valores enumerados.
-
Saneamiento del contenido:
Permite solo HTML seguro con wp_kses_post o wp_kses con una lista blanca personalizada. Si aceptas shortcodes anidados, ejecuta do_shortcode sobre el contenido antes de sanearlo.
-
Escapar la salida:
Al imprimir atributos en HTML, utiliza esc_attr, esc_html o esc_url según corresponda.
-
Revisar privilegios y acciones sensibles:
Si el shortcode genera formularios o acciones que cambian datos, añade nonces y comprobaciones de capacidades.
Ejemplo completo y seguro
Ejemplo práctico de un shortcode secure_card siguiendo las buenas prácticas descritas. El ejemplo registra el shortcode y muestra cómo validar, sanear y escapar correctamente.
, url => , image => , size => medium, // allowed: smallmediumlarge align => left, // allowed: leftcenterright show_image => false, // string boolean class => , ) // Mezclar atributos con valores por defecto atts = shortcode_atts( defaults, atts, secure_card ) // SANITIZACIÓN DE ATRIBUTOS title = sanitize_text_field( atts[title] ) url = esc_url_raw( atts[url] ) image = esc_url_raw( atts[image] ) // Validar enumerados con lista blanca size_allowed = array( small, medium, large ) align_allowed = array( left, center, right ) size = in_array( atts[size], size_allowed, true ) ? atts[size] : medium align = in_array( atts[align], align_allowed, true ) ? atts[align] : left // Booleano: convertir a boolean real show_image = filter_var( atts[show_image], FILTER_VALIDATE_BOOLEAN ) // Clase CSS: usar sanitize_html_class para evitar clases inseguras custom_class = sanitize_html_class( atts[class] ) // CONTENIDO: permitir shortcodes anidados, luego sanear HTML permitido content = do_shortcode( content ) content = wp_kses_post( content ) // permite etiquetas seguras por WP para posts // CONSTRUCCIÓN DE SALIDA: escapar siempre al imprimir classes = array( secure-card, secure-card-- . esc_attr( size ), secure-card--align- . esc_attr( align ), ) if ( custom_class ) { classes[] = esc_attr( custom_class ) } class_attr = implode( , classes ) // Título y enlace: escapar apropiadamente title_html = title ? . esc_html( title ) . : if ( url ) { // esc_url para salida (permite más escape para HTML) linked_title = . title_html . } else { linked_title = title_html } // Imagen (si se permite) image_html = if ( image show_image ) { image_html =} // Montar HTML de salida html =
if ( image_html ) { html .= image_html } if ( linked_title ) { html .= linked_title } if ( content ) { html .= . content . } html .=
return html } add_shortcode( secure_card, secure_card_shortcode ) ?>
Uso de ejemplo
Ejemplo de invocación del shortcode en el editor o en un post:
// En el contenido del post: [secure_card title=Mi tarjeta url=https://example.org image=https://example.org/imagen.jpg show_image=true size=large align=center class=destacado]Texto permitido y safe[/secure_card]
Notas sobre el ejemplo
- Se usa esc_url_raw para sanitizar las URLs recibidas y esc_url al imprimirlas.
- Se usa sanitize_text_field para texto plano (título) y sanitize_html_class para clases CSS.
- Se valida size y align con listas blancas (in_array).
- El contenido admite shortcodes anidados (do_shortcode) y luego se filtra con wp_kses_post para permitir solo HTML seguro.
- La salida se construye escapando cada parte con esc_attr, esc_html o esc_url según corresponda.
Buenas prácticas adicionales
- Evita ejecutar PHP o incluir archivos basados en atributos del shortcode.
- Si el shortcode muestra datos sensibles, comprueba current_user_can antes de mostrarlos.
- Si el shortcode genera formularios que realizan acciones, incluye wp_nonce_field y verifica el nonce en la acción.
- Considera internacionalizar textos con __() o esc_html__() si hay textos estáticos dentro del shortcode.
- Documenta los atributos esperados para que los usuarios no pasen valores inesperados.
- Realiza pruebas con datos maliciosos (scripts, protocolos javascript:) para verificar que el saneamiento funciona.
Comprobaciones y pruebas recomendadas
- Prueba con atributos malformados: urls con javascript:, atributos con HTML o scripts, valores fuera de la lista blanca.
- Inserta HTML malicioso en el contenido para asegurarte de que wp_kses_post lo limpia según lo esperado.
- Prueba shortcodes anidados para confirmar que do_shortcode wp_kses_post no deja vectores de XSS.
- Revisa la salida en el inspector del navegador para verificar que los atributos están correctamente escapados.
Resumen
Un shortcode seguro se diseña definiendo claramente los atributos, validando y saneando cada valor, permitiendo solo HTML seguro en el contenido y escapando siempre la salida. Nunca confíes en los datos de entrada: valida, sanea y escapa. Siguiendo las funciones nativas de WordPress (shortcode_atts, sanitize_text_field, esc_url_raw, wp_kses_post, esc_attr, esc_html, etc.) construirás shortcodes que ofrecen funcionalidad sin introducir riesgos de seguridad.
Para ampliar, revisa la documentación oficial de WordPress sobre shortcodes y funciones de saneamiento en developer.wordpress.org.
|
Acepto donaciones de BAT's mediante el navegador Brave 🙂 |