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 🙂 |
